From db7ae82fa98ec49d912b4e2175fd0be9d8339600 Mon Sep 17 00:00:00 2001 From: lfkdsk Date: Sun, 1 Jan 2017 22:00:02 +0800 Subject: [PATCH] fix bug in folder names --- .../lfk/justweengine/anim/AliveAnimation.java | 29 + .../lfk/justweengine/anim/AlphaAnimation.java | 41 + .../com/lfk/justweengine/anim/AnimType.java | 36 + .../com/lfk/justweengine/anim/BaseAnim.java | 55 ++ .../anim/CircleMoveAnimation.java | 33 + .../justweengine/anim/DoAfterAnimation.java | 8 + .../lfk/justweengine/anim/FenceAnimation.java | 33 + .../lfk/justweengine/anim/FrameAnimation.java | 52 ++ .../lfk/justweengine/anim/MoveAnimation.java | 45 + .../lfk/justweengine/anim/ShootAnimation.java | 34 + .../lfk/justweengine/anim/SpinAnimation.java | 28 + .../lfk/justweengine/anim/ThrobAnimation.java | 40 + .../justweengine/anim/VelocityAnimation.java | 50 ++ .../justweengine/anim/WrapMoveAnimation.java | 40 + .../lfk/justweengine/anim/ZoomAnimation.java | 71 ++ .../drawable/Bone/BoneGroupSprite.java | 121 +++ .../drawable/Bone/BoneSprite.java | 40 + .../drawable/Button/BaseButton.java | 102 +++ .../drawable/Button/BaseButtonAnimation.java | 36 + .../drawable/Button/ColorAnimation.java | 26 + .../drawable/Button/OnClickListener.java | 8 + .../drawable/Button/TextButton.java | 151 ++++ .../drawable/Button/TextureButton.java | 127 +++ .../drawable/Button/ZoomCenterButtonAnim.java | 56 ++ .../drawable/Sprite/BaseSprite.java | 725 ++++++++++++++++ .../justweengine/drawable/Sprite/BaseSub.java | 47 + .../drawable/Sprite/FrameType.java | 13 + .../drawable/Sprite/StateFinder.java | 8 + .../drawable/Sprite/StateSprite.java | 53 ++ .../com/lfk/justweengine/engine/Engine.java | 28 + .../justweengine/engine/GameTextPrinter.java | 79 ++ .../lfk/justweengine/engine/GameTexture.java | 111 +++ .../lfk/justweengine/engine/GameTimer.java | 57 ++ .../engine/Layer/ButtonLayer.java | 99 +++ .../engine/Layer/DefaultLayer.java | 215 +++++ .../lfk/justweengine/engine/Layer/Layer.java | 95 +++ .../engine/Layer/LayerEngine.java | 174 ++++ .../lfk/justweengine/engine/Layer/Screen.java | 597 +++++++++++++ .../engine/Layer/SimpleLayerEngine.java | 56 ++ .../lfk/justweengine/engine/ObjectPool.java | 77 ++ .../justweengine/engine/ObjectPoolGroup.java | 118 +++ .../lfk/justweengine/engine/SimpleEngine.java | 806 ++++++++++++++++++ .../lfk/justweengine/engine/TouchMode.java | 25 + .../lfk/justweengine/info/UIdefaultData.java | 41 + .../utils/blueTooth/BlueToothServer.java | 277 ++++++ .../utils/blueTooth/BluetoothChatService.java | 520 +++++++++++ .../utils/blueTooth/OnMessageBack.java | 14 + .../crashHandler/AfterCrashListener.java | 12 + .../utils/crashHandler/CrashHandler.java | 243 ++++++ .../crashHandler/CrashHandlerDefault.java | 20 + .../justweengine/utils/database/DataBase.java | 367 ++++++++ .../utils/database/LabelName.java | 23 + .../lfk/justweengine/utils/database/Node.java | 27 + .../utils/database/TableName.java | 20 + .../lfk/justweengine/utils/database/User.java | 39 + .../com/lfk/justweengine/utils/io/FileIO.java | 20 + .../com/lfk/justweengine/utils/io/GameIO.java | 47 + .../utils/logger/AndroidLogTool.java | 35 + .../lfk/justweengine/utils/logger/LogCat.java | 96 +++ .../justweengine/utils/logger/LogLevel.java | 17 + .../justweengine/utils/logger/LogParser.java | 104 +++ .../justweengine/utils/logger/LogTool.java | 15 + .../lfk/justweengine/utils/logger/Logger.java | 100 +++ .../utils/logger/LoggerPrinter.java | 389 +++++++++ .../justweengine/utils/logger/Options.java | 9 + .../justweengine/utils/logger/Printer.java | 30 + .../justweengine/utils/logger/Settings.java | 89 ++ .../lfk/justweengine/utils/music/Music.java | 28 + .../justweengine/utils/music/MusicPlayer.java | 126 +++ .../utils/music/SoundManager.java | 140 +++ .../justweengine/utils/music/SoundPlayer.java | 150 ++++ .../utils/quad/Collisionable.java | 8 + .../lfk/justweengine/utils/quad/QuadTree.java | 164 ++++ .../lfk/justweengine/utils/script/Exp.java | 286 +++++++ .../justweengine/utils/script/Function.java | 35 + .../justweengine/utils/script/KeyCode.java | 52 ++ .../utils/script/NumberUtils.java | 140 +++ .../utils/script/ScriptManager.java | 412 +++++++++ .../utils/showLogger/LogHandler.java | 155 ++++ .../utils/showLogger/LogPrinter.java | 105 +++ .../utils/tools/DisplayUtils.java | 93 ++ .../justweengine/utils/tools/ImageHelper.java | 136 +++ .../justweengine/utils/tools/NetUtils.java | 90 ++ .../justweengine/utils/tools/PicUtils.java | 554 ++++++++++++ .../utils/tools/ServiceUtils.java | 65 ++ .../lfk/justweengine/utils/tools/SpUtils.java | 282 ++++++ .../utils/tools/ValidatorsUtils.java | 371 ++++++++ .../utils/webServer/ChangeCharset.java | 132 +++ .../webServer/Interface/OnLogResult.java | 23 + .../webServer/Interface/OnPermissionFile.java | 14 + .../utils/webServer/Interface/OnPostData.java | 17 + .../webServer/Interface/OnWebFileResult.java | 18 + .../webServer/Interface/OnWebResult.java | 11 + .../Interface/OnWebStringResult.java | 11 + .../utils/webServer/RequestSolve.java | 183 ++++ .../justweengine/utils/webServer/Servers.java | 73 ++ .../utils/webServer/WebServer.java | 154 ++++ .../utils/webServer/WebServerDefault.java | 59 ++ .../utils/webServer/WebServerService.java | 137 +++ 99 files changed, 11423 insertions(+) create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/AliveAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/AlphaAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/AnimType.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/BaseAnim.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/CircleMoveAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/DoAfterAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/FenceAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/FrameAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/MoveAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/ShootAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/SpinAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/ThrobAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/VelocityAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/WrapMoveAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/anim/ZoomAnimation.java create mode 100755 engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneGroupSprite.java create mode 100755 engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneSprite.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButton.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButtonAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/ColorAnimation.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/OnClickListener.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/TextButton.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/TextureButton.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Button/ZoomCenterButtonAnim.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSprite.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSub.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Sprite/FrameType.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateFinder.java create mode 100644 engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateSprite.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Engine.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/GameTextPrinter.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/GameTexture.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/GameTimer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/ButtonLayer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/DefaultLayer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/Layer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/LayerEngine.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/Screen.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/Layer/SimpleLayerEngine.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/ObjectPool.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/ObjectPoolGroup.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/SimpleEngine.java create mode 100644 engine/src/main/java/com/lfk/justweengine/engine/TouchMode.java create mode 100644 engine/src/main/java/com/lfk/justweengine/info/UIdefaultData.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BlueToothServer.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BluetoothChatService.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/blueTooth/OnMessageBack.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/crashHandler/AfterCrashListener.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandler.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandlerDefault.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/database/DataBase.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/database/LabelName.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/database/Node.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/database/TableName.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/database/User.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/io/FileIO.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/io/GameIO.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/AndroidLogTool.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/logger/LogCat.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/LogLevel.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/logger/LogParser.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/LogTool.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/Logger.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/LoggerPrinter.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/logger/Options.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/Printer.java create mode 100755 engine/src/main/java/com/lfk/justweengine/utils/logger/Settings.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/music/Music.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/music/MusicPlayer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/music/SoundManager.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/music/SoundPlayer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/quad/Collisionable.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/quad/QuadTree.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/script/Exp.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/script/Function.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/script/KeyCode.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/script/NumberUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/script/ScriptManager.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogHandler.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogPrinter.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/DisplayUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/ImageHelper.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/NetUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/PicUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/ServiceUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/SpUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/tools/ValidatorsUtils.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/ChangeCharset.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnLogResult.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPermissionFile.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPostData.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebFileResult.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebResult.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebStringResult.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/RequestSolve.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/Servers.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServer.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerDefault.java create mode 100644 engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerService.java diff --git a/engine/src/main/java/com/lfk/justweengine/anim/AliveAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/AliveAnimation.java new file mode 100644 index 0000000..235b714 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/AliveAnimation.java @@ -0,0 +1,29 @@ +package com.lfk.justweengine.anim; + +import com.lfk.justweengine.engine.GameTimer; + +/** + * 判断生死 + * + * @author liufengkai + * Created by liufengkai on 15/12/5. + */ +public class AliveAnimation extends BaseAnim { + private int liftTime; + private GameTimer timer; + + public AliveAnimation(int liftTime) { + this.liftTime = liftTime; + this.timer = new GameTimer(); + animating = true; + animType = AnimType.ALIVE; + } + + @Override + public boolean adjustAlive(boolean ori) { + if (liftTime > 0 && timer.stopWatch(liftTime)) { + ori = false; + } + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/AlphaAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/AlphaAnimation.java new file mode 100644 index 0000000..badd2b2 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/AlphaAnimation.java @@ -0,0 +1,41 @@ +package com.lfk.justweengine.anim; + +/** + * 透明度动画 + * + * @author liufengkai + * Created by liufengkai on 15/11/28. + */ +public class AlphaAnimation extends BaseAnim { + private int maxAlpha; + private int minAlpha; + private int changeAlpha; + + public AlphaAnimation(int changeAlpha) { + this(255, 0, changeAlpha); + } + + public AlphaAnimation(int maxAlpha, int minAlpha, int changeAlpha) { + super(); + this.maxAlpha = maxAlpha; + this.minAlpha = minAlpha; + this.changeAlpha = changeAlpha; + this.animType = AnimType.ALPHA; + this.animating = true; + } + + @Override + public int adjustAlpha(int ori) { + int modified = ori; + modified += changeAlpha; + if (modified < minAlpha) { + modified = minAlpha; + animating = false; + } + if (modified > maxAlpha) { + modified = maxAlpha; + animating = false; + } + return modified; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/AnimType.java b/engine/src/main/java/com/lfk/justweengine/anim/AnimType.java new file mode 100644 index 0000000..15a5ab1 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/AnimType.java @@ -0,0 +1,36 @@ +package com.lfk.justweengine.anim; + +/** + * 动画类型 + * + * @author liufengkai + * Created by liufengkai on 15/11/28. + */ +public enum AnimType { + // anim with frame change + FRAME, + + ALPHA, + + SCALE, + + ROTATION, + + POSITION, + + WRAPMOVE, + + ALIVE, + + SHOOT, + + ZOOM, + + ZOOM_CENTER, + + MASK, + + COLOR, + + NULL +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/BaseAnim.java b/engine/src/main/java/com/lfk/justweengine/anim/BaseAnim.java new file mode 100644 index 0000000..0a0b9c9 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/BaseAnim.java @@ -0,0 +1,55 @@ +package com.lfk.justweengine.anim; + +import android.graphics.Rect; +import android.renderscript.Float2; + +/** + * 动画基类 + * + * @author liufengkai + * Created by liufengkai on 15/11/28. + */ +public class BaseAnim { + // Is it running ? + public boolean animating; + // anim type + public AnimType animType; + + // init + public BaseAnim() { + animating = false; + animType = AnimType.NULL; + } + + public int adjustAlpha(int ori) { + return ori; + } + + public int adjustFrame(int ori) { + return ori; + } + + public Float2 adjustScale(Float2 ori) { + return ori; + } + + public float adjustRotation(float ori) { + return ori; + } + + public Float2 adjustPosition(Float2 ori) { + return ori; + } + + public boolean adjustAlive(boolean ori) { + return ori; + } + + public Rect adjustScale(Rect ori) { + return ori; + } + + public float adjustTag(float ori) { + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/CircleMoveAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/CircleMoveAnimation.java new file mode 100644 index 0000000..1323736 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/CircleMoveAnimation.java @@ -0,0 +1,33 @@ +package com.lfk.justweengine.anim; + +import android.graphics.Point; +import android.renderscript.Float2; + +/** + * Created by liufengkai on 15/11/29. + */ +public class CircleMoveAnimation extends BaseAnim { + private int radius; + private Point center; + private double angle; + private float velocity; + + public CircleMoveAnimation(int centerX, int centerY, + int radius, double angle, + float velocity) { + animating = true; + animType = AnimType.POSITION; + this.center = new Point(centerX, centerY); + this.radius = radius; + this.angle = angle; + this.velocity = velocity; + } + + @Override + public Float2 adjustPosition(Float2 ori) { + angle += velocity; + ori.x = (int) (center.x + (float) (Math.cos(angle) * radius)); + ori.y = (int) (center.y + (float) (Math.sin(angle) * radius)); + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/DoAfterAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/DoAfterAnimation.java new file mode 100644 index 0000000..f7e8432 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/DoAfterAnimation.java @@ -0,0 +1,8 @@ +package com.lfk.justweengine.anim; + +/** + * Created by liufengkai on 15/12/2. + */ +public interface DoAfterAnimation { + void afterAnimation(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/FenceAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/FenceAnimation.java new file mode 100644 index 0000000..c5c0df0 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/FenceAnimation.java @@ -0,0 +1,33 @@ +package com.lfk.justweengine.anim; + +import android.graphics.Rect; +import android.renderscript.Float2; + +/** + * 围栏使用动画防止出界 + * + * @author liufengkai + * Created by liufengkai on 15/12/4. + */ +public class FenceAnimation extends BaseAnim { + private Rect fence; + + public FenceAnimation(Rect fence) { + this.fence = fence; + animating = true; + animType = AnimType.POSITION; + } + + @Override + public Float2 adjustPosition(Float2 ori) { + if (ori.x < fence.left) + ori.x = fence.left; + else if (ori.x > fence.right) + ori.x = fence.right; + else if (ori.y < fence.top) + ori.y = fence.top; + else if (ori.y > fence.bottom) + ori.y = fence.bottom; + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/FrameAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/FrameAnimation.java new file mode 100644 index 0000000..359f370 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/FrameAnimation.java @@ -0,0 +1,52 @@ +package com.lfk.justweengine.anim; + +import com.lfk.justweengine.engine.GameTimer; + +/** + * 逐帧动画 + * + * @author liufengkai + * Created by liufengkai on 15/11/29. + */ +public class FrameAnimation extends BaseAnim { + private int firstFrame; + private int lastFrame; + private int direction; + private int interval; + // 帧动画切换时间间隔,单位ms + private GameTimer timer; + + public FrameAnimation(int firstFrame, int lastFrame, int direction) { + this.firstFrame = firstFrame; + this.lastFrame = lastFrame; + this.direction = direction; + this.animType = AnimType.FRAME; + this.animating = true; + this.interval = 0; + timer = new GameTimer(); + } + + public FrameAnimation(int firstFrame, int lastFrame, int direction, int interval) { + this.firstFrame = firstFrame; + this.lastFrame = lastFrame; + this.direction = direction; + this.animType = AnimType.FRAME; + this.animating = true; + this.interval = interval; + timer = new GameTimer(); + } + + @Override + public int adjustFrame(int ori) { + int modified = ori; + if (timer.stopWatch(interval)) { + modified += direction; + if (modified < firstFrame) { + modified = lastFrame; + } else if (modified > lastFrame) { + modified = firstFrame; + } + } + return modified; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/MoveAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/MoveAnimation.java new file mode 100644 index 0000000..28161c9 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/MoveAnimation.java @@ -0,0 +1,45 @@ +package com.lfk.justweengine.anim; + +import android.renderscript.Float2; +import android.util.Log; + +/** + * Created by liufengkai on 15/12/3. + */ +public class MoveAnimation extends BaseAnim { + private Float2 velocity; + private float toX; + private float toY; + + public MoveAnimation( + float toX, float toY, + Float2 velocity) { + this.toX = toX; + this.toY = toY; + this.velocity = velocity; + animating = true; + animType = AnimType.POSITION; + } + + @Override + public Float2 adjustPosition(Float2 ori) { + if (ori.x != toX) { + if (ori.x > toX) + ori.x -= velocity.x; + else + ori.x += velocity.x; + } + if (ori.y != toY) { + Log.d("ori.y" + ori.y, "toY" + toY); + if (ori.y > toY) + ori.y -= velocity.y; + else + ori.y += velocity.y; + } + if (Math.abs(ori.x - toX) < velocity.x && + Math.abs(ori.y - toY) < velocity.y) { + animating = false; + } + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/ShootAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/ShootAnimation.java new file mode 100644 index 0000000..cea79f7 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/ShootAnimation.java @@ -0,0 +1,34 @@ +package com.lfk.justweengine.anim; + +import android.renderscript.Float2; + +import com.lfk.justweengine.info.UIdefaultData; + +/** + * Created by liufengkai on 15/12/5. + */ +public class ShootAnimation extends BaseAnim { + private float speed; + private float y; + + public ShootAnimation(float y, float v) { + this.speed = v; + this.y = y; + animating = true; + animType = AnimType.SHOOT; + } + + @Override + public Float2 adjustPosition(Float2 original) { + y = original.y += speed; + return original; + } + + @Override + public boolean adjustAlive(boolean ori) { + if (y < 0 || y > UIdefaultData.screenHeight) { + ori = false; + } + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/SpinAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/SpinAnimation.java new file mode 100644 index 0000000..3bcc7b9 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/SpinAnimation.java @@ -0,0 +1,28 @@ +package com.lfk.justweengine.anim; + +/** + * 旋转动画 + * + * @author liufengkai + * Created by liufengkai on 15/11/29. + */ +public class SpinAnimation extends BaseAnim { + private float angleDist, velocity; + + public SpinAnimation(float velocity) { + animating = true; + angleDist = 0.0f; + this.velocity = velocity; + } + + @Override + public float adjustRotation(float ori) { + float modified = ori; + float fullCircle = (float) (2.0 * Math.PI); + angleDist += velocity; + if (angleDist > fullCircle) + animating = false; + modified += velocity; + return modified; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/ThrobAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/ThrobAnimation.java new file mode 100644 index 0000000..8fd8fbf --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/ThrobAnimation.java @@ -0,0 +1,40 @@ +package com.lfk.justweengine.anim; + +import android.renderscript.Float2; + +/** + * 跳跃动画 + * + * @author liufengkai + * Created by liufengkai on 15/11/29. + */ +public class ThrobAnimation extends BaseAnim { + private float startScale, endScale, speed; + private boolean started; + + public ThrobAnimation(float startScale, float endScale, float speed) { + this.startScale = startScale; + this.endScale = endScale; + this.speed = speed; + animType = AnimType.SCALE; + started = false; + animating = true; + } + + @Override + public Float2 adjustScale(Float2 ori) { + if (!started) { + ori.x = startScale; + ori.y = startScale; + started = true; + } + ori.x += speed; + ori.y += speed; + if (ori.x >= endScale) { + speed *= -1; + } else if (ori.x <= startScale) { + speed *= -1; + } + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/VelocityAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/VelocityAnimation.java new file mode 100644 index 0000000..2a0ef8c --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/VelocityAnimation.java @@ -0,0 +1,50 @@ + + +package com.lfk.justweengine.anim; + +import android.renderscript.Float2; + +import com.lfk.justweengine.engine.GameTimer; + +public class VelocityAnimation extends BaseAnim { + private double p_angle; + private double p_multiplier; + private double p_velX, p_velY; + private int p_lifetime; + private GameTimer p_timer; + + public VelocityAnimation(double angleDegrees, float speedMultiplier, + int lifetime) { + animating = true; + animType = AnimType.SHOOT; + p_lifetime = lifetime; + p_timer = new GameTimer(); + p_angle = angleDegrees; + p_multiplier = speedMultiplier; + double angleRadians = Math.toRadians(p_angle); + //calculate X velocity + p_velX = Math.cos(angleRadians) * p_multiplier; + //calculate Y velocity + p_velY = Math.sin(angleRadians) * p_multiplier; + } + + @Override + public Float2 adjustPosition(Float2 original) { + Float2 modified = new Float2(original.x, original.y); + modified.x += p_velX; + modified.y += p_velY; + return modified; + } + + @Override + public boolean adjustAlive(boolean original) { + boolean modified = original; + if (p_lifetime > 0) { + if (p_timer.stopWatch(p_lifetime)) { + modified = false; + } + } + return modified; + } +} + diff --git a/engine/src/main/java/com/lfk/justweengine/anim/WrapMoveAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/WrapMoveAnimation.java new file mode 100644 index 0000000..29b67cb --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/WrapMoveAnimation.java @@ -0,0 +1,40 @@ +package com.lfk.justweengine.anim; + +import android.graphics.Point; +import android.graphics.Rect; +import android.renderscript.Float2; + +/** + * Created by liufengkai on 15/11/29. + */ +public class WrapMoveAnimation extends BaseAnim { + private Rect bounds; + private Float2 velocity; + private Point size; + + public WrapMoveAnimation(Rect bounds, Point size, Float2 velocity) { + animating = true; + animType = AnimType.WRAPMOVE; + this.bounds = bounds; + this.size = size; + this.velocity = velocity; + } + + @Override + public Float2 adjustPosition(Float2 ori) { + ori.x += velocity.x; + ori.y += velocity.y; + + if (ori.x < bounds.left) { + ori.x = bounds.right - size.x; + } else if (ori.x > bounds.right - size.x) { + ori.x = bounds.left; + } + if (ori.y < bounds.top) { + ori.y = bounds.bottom - size.y; + } else if (ori.y > bounds.bottom - size.y) { + ori.y = bounds.top; + } + return ori; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/anim/ZoomAnimation.java b/engine/src/main/java/com/lfk/justweengine/anim/ZoomAnimation.java new file mode 100644 index 0000000..2d348e6 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/anim/ZoomAnimation.java @@ -0,0 +1,71 @@ +package com.lfk.justweengine.anim; + +import android.renderscript.Float2; + + +/** + * 按钮放大缩小动画 + * + * @author liufengkai + * Created by liufengkai on 15/12/10. + */ +public class ZoomAnimation extends BaseAnim { + private float from; + private float to; + private float speed; + private boolean start; + public int touchType; + private boolean changeType; + + // speed永为正值 + public ZoomAnimation(float from, float to, float speed) { + this.from = from; + this.to = to; + this.speed = speed; + this.start = false; + this.animating = true; + changeType = false; + animType = AnimType.ZOOM; + } + + @Override + public Float2 adjustScale(Float2 ori) { + if (!start) { + start = true; + } + + if (changeType) { + animating = false; + changeType = false; + return ori; + } + + if (from < to) { // 放大 + if (from + speed < to) { + from += speed; + } else { + from = to; + } + } else if (from > to) { // 缩小 + if (from - speed > to) { + from -= speed; + } else { + from = to; + } + } + + if (from == to) { + touchType = -touchType; + changeType = true; + } + + ori.x = from; + ori.y = from; + return ori; + } + + @Override + public float adjustTag(float ori) { + return touchType; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneGroupSprite.java b/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneGroupSprite.java new file mode 100755 index 0000000..ad72164 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneGroupSprite.java @@ -0,0 +1,121 @@ +package com.lfk.justweengine.drawable.Bone; + +import com.lfk.justweengine.engine.Engine; + +import java.util.HashMap; +import java.util.Map; + +/** + * 骨骼精灵组 + * Created by Administrator on 2016/4/30. + */ +public class BoneGroupSprite { + + private Map spriteMap; + + private Map boneAnimGroup; + + private BoneBuilder.BoneBuilderConfig config; + + public Map getSpriteMap() { + return spriteMap; + } + + public BoneSprite getBoneSprite(String name) { + return spriteMap.get(name); + } + + public void runFixedAnimation(String groupName) { + BoneBuilder.BoneAnimGroup group = boneAnimGroup.get(groupName); + for (int i = 0; i < group.group.length; i++) { + BoneBuilder.BoneAnimItem item = group.group[i]; + item.boneSprite.fixedAnimation(item.animName); + } + } + + /** + * 骨骼构建内部类 + */ + public static class BoneBuilder { + public class BoneBuilderConfig { + float positionX, positionY; + + } + + public class BoneAnimGroup { + BoneAnimItem[] group; + String groupName; + + public BoneAnimGroup(String groupName, BoneAnimItem... items) { + this.groupName = groupName; + this.group = new BoneAnimItem[items.length]; + for (int i = 0; i < group.length; i++) { + this.group[i] = items[i]; + } + } + } + + public class BoneAnimItem { + BoneSprite boneSprite; + String animName; + + public BoneAnimItem(BoneSprite boneSprite, String animName) { + this.boneSprite = boneSprite; + this.animName = animName; + } + } + + public final Engine engine; + + private int currentNum; + + private BoneBuilderConfig config; + + private Map boneSprites; + private Map boneAnimGroup; + + public BoneBuilder(Engine engine) { + this.engine = engine; + this.currentNum = 0; + this.boneSprites = new HashMap<>(); + this.boneAnimGroup = new HashMap<>(); + this.config = new BoneBuilderConfig(); + } + + public BoneBuilder setPosition(float x, float y) { + this.config.positionX = x; + this.config.positionY = y; + return this; + } + + public BoneBuilder addBone(String name, BoneSprite sprite) { + sprite.s_position.x += config.positionX; + sprite.s_position.y += config.positionY; + this.boneSprites.put(name, sprite); + this.currentNum++; + return this; + } + + public BoneBuilder deleteBone(String name) { + this.boneSprites.remove(name); + this.currentNum--; + return this; + } + + public BoneBuilder addBoneAnimGroup(String name, BoneAnimGroup group) { + this.boneAnimGroup.put(name, group); + return this; + } + + public BoneGroupSprite create() { + BoneGroupSprite sprite = new BoneGroupSprite(); + for (String name : boneSprites.keySet()) { + boneSprites.get(name).setParentGroup(sprite); + } + sprite.spriteMap = new HashMap<>(boneSprites); + sprite.boneAnimGroup = new HashMap<>(boneAnimGroup); + sprite.config = config; + return sprite; + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneSprite.java b/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneSprite.java new file mode 100755 index 0000000..12378f8 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Bone/BoneSprite.java @@ -0,0 +1,40 @@ +package com.lfk.justweengine.drawable.Bone; + +import com.lfk.justweengine.drawable.Sprite.BaseSprite; +import com.lfk.justweengine.drawable.Sprite.FrameType; +import com.lfk.justweengine.engine.Engine; + +/** + * 骨骼精灵 + * 坐标为相对坐标 + * Created by Administrator on 2016/4/30. + */ +public class BoneSprite extends BaseSprite { + + public BoneGroupSprite parentGroup; + + /** + * @param engine + * @param w + * @param h + * @param columns + */ + public BoneSprite(Engine engine, int w, int h, int columns) { + super(engine, w, h, columns); + + } + + public BoneSprite(Engine engine) { + super(engine); + + } + + public BoneSprite(Engine engine, int w, int h, FrameType type) { + super(engine, w, h, type); + + } + + public void setParentGroup(BoneGroupSprite parentGroup) { + this.parentGroup = parentGroup; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButton.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButton.java new file mode 100644 index 0000000..31f18c5 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButton.java @@ -0,0 +1,102 @@ +package com.lfk.justweengine.drawable.Button; + +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.renderscript.Float2; +import android.util.Log; + +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.engine.GameTextPrinter; +import com.lfk.justweengine.info.UIdefaultData; +import com.lfk.justweengine.utils.tools.DisplayUtils; + +/** + * Button 基类 + * + * @author liufengkai + * Created by liufengkai on 15/12/2. + */ +public abstract class BaseButton extends GameTextPrinter { + protected Engine b_engine; + protected int b_width, b_height; + public Point b_position; + protected Paint paint; + public Rect b_rect; + protected String b_name; + protected Float2 b_scale; + protected OnClickListener onClickListener; + protected BaseButtonAnimation b_baseAnim; + // protected int b_buttonType; + protected boolean b_normal; + + public BaseButton(Engine b_engine, String name) { + this(b_engine, 0, 0, name); + } + + public BaseButton(Engine b_engine, int b_width, int b_height, String name) { + this.b_engine = b_engine; + this.b_width = b_width; + this.b_height = b_height; + this.b_name = name; + init(); + } + + private void init() { + b_normal = false; +// this.b_buttonType = BaseButtonAnimation.NORMAL; + paint = new Paint(); + paint.setColor(UIdefaultData.sprite_default_color_paint); + } + + public abstract void draw(); + + public abstract void animation(); + + public String getName() { + return b_name; + } + + public void setName(String b_name) { + this.b_name = b_name; + } + + public Rect getRect() { + return b_rect; + } + + public void onClick(boolean flag) { + if (flag) { + onClickListener.onClick(); + } + } + + public void setOnClickListener(OnClickListener onClickListener) { + this.onClickListener = onClickListener; + } + + public void setScale(Float2 scale) { + b_scale = scale; + Log.e("scale", b_scale.x + ":" + b_scale.y); + } + + public void setScale(float x, float y) { + this.b_scale.x = x; + this.b_scale.y = y; + } + + public void setDipWidth(int w) { + this.b_scale.x = DisplayUtils.dip2px(w); + } + + public void setDipHeight(int h) { + this.b_scale.y = DisplayUtils.dip2px(h); + } + + public BaseButtonAnimation getAnimation() { + return b_baseAnim; + } + + public void setNormal(boolean b_normal) { + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButtonAnimation.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButtonAnimation.java new file mode 100644 index 0000000..27ddfbb --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/BaseButtonAnimation.java @@ -0,0 +1,36 @@ +package com.lfk.justweengine.drawable.Button; + +import android.graphics.Rect; + +import com.lfk.justweengine.anim.AnimType; +import com.lfk.justweengine.anim.BaseAnim; + +/** + * Created by liufengkai on 15/12/12. + */ +public abstract class BaseButtonAnimation extends BaseAnim { + // Is it running ? + public boolean animating; + // anim type + public AnimType animType; + + public static final int UP = 1; + public static final int DOWN = -1; + public static final int NORMAL = 0; + + // init + public BaseButtonAnimation() { + animating = false; + animType = AnimType.NULL; + } + + // center zoom + public Rect adjustButtonRect(Rect rect, boolean type) { + return rect; + } + + public int adjustButtonBackGround(int ori, boolean type) { + return ori; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/ColorAnimation.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/ColorAnimation.java new file mode 100644 index 0000000..4deead0 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/ColorAnimation.java @@ -0,0 +1,26 @@ +package com.lfk.justweengine.drawable.Button; + +import com.lfk.justweengine.anim.AnimType; + +/** + * Created by liufengkai on 15/12/12. + */ +public class ColorAnimation extends BaseButtonAnimation { + private int pressed_color, unpressed_color; + + public ColorAnimation(int unpressed_color, int pressed_color) { + this.pressed_color = pressed_color; + this.unpressed_color = unpressed_color; + animating = false; + animType = AnimType.COLOR; + } + + @Override + public int adjustButtonBackGround(int ori, boolean type) { + if (type) { + return unpressed_color; + } else { + return pressed_color; + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/OnClickListener.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/OnClickListener.java new file mode 100644 index 0000000..76c0df2 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/OnClickListener.java @@ -0,0 +1,8 @@ +package com.lfk.justweengine.drawable.Button; + +/** + * Created by liufengkai on 15/12/10. + */ +public interface OnClickListener { + void onClick(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextButton.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextButton.java new file mode 100644 index 0000000..80b0d4e --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextButton.java @@ -0,0 +1,151 @@ +package com.lfk.justweengine.drawable.Button; + +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.renderscript.Float2; + +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.utils.tools.DisplayUtils; + +/** + * TextButton + * + * @author liufengkai + * Created by liufengkai on 15/12/12. + */ +public class TextButton extends BaseButton { + // text color / button color + private int b_text_Color, b_button_Color; + // text + private String b_text; + // zoom in center + private boolean b_zoomCenter, b_firstInit; + private Paint b_textPaint; + private float b_textWidth, b_singleWidth; + + /** + * TextButton + * + * @param b_engine engine context + * @param name textButton name + */ + public TextButton(Engine b_engine, String name) { + super(b_engine, name); + init(); + } + + /** + * TextButton + * + * @param b_engine engine context + * @param b_width w + * @param b_height h + * @param name textButton name + */ + public TextButton(Engine b_engine, int b_width, int b_height, String name) { + super(b_engine, b_width, b_height, name); + init(); + } + + private void init() { + b_text = ""; + b_text_Color = Color.WHITE; + b_button_Color = Color.TRANSPARENT; + b_zoomCenter = false; + b_firstInit = false; + b_position = new Point(110, 110); + b_scale = new Float2(1.0f, 1.0f); + + b_textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + b_textPaint.setColor(b_text_Color); + b_textPaint.setTextSize(40); + + paint.setColor(b_button_Color); + paint.setAntiAlias(true); + paint.setStyle(Paint.Style.FILL); + } + + @Override + public void draw() { + e_canvas = b_engine.getCanvas(); + if (b_width == 0 || b_height == 0) { + float[] widths = new float[1]; + // 获取单个汉字的宽度 + b_textPaint.getTextWidths("蛤", widths); + b_text = b_text != null ? b_text : ""; + b_textWidth = widths[0] * b_text.length(); + b_singleWidth = widths[0]; + b_width = (int) (b_text.length() * widths[0] + 2 * DisplayUtils.dip2px(16)); + b_height = (int) (widths[0] + 2 * DisplayUtils.dip2px(8)); + } + int x = b_position.x; + int y = b_position.y; + int w = (int) (b_width * b_scale.x); + int h = (int) (b_height * b_scale.y); + if (!b_firstInit) { + b_rect = new Rect(x, y, x + w, y + h); + b_firstInit = true; + } + + if (!b_zoomCenter) { + b_rect = new Rect(x, y, x + w, y + h); + } + e_canvas.drawRect(b_rect, paint); + e_canvas.drawText(b_text, x + (b_width / 2 - b_textWidth / 2), + y + (b_height / 2 + b_singleWidth / 2), b_textPaint); + } + + @Override + public void animation() { + if (b_baseAnim != null && b_baseAnim.animating) { + doAnimation(); + } + } + + private void doAnimation() { + switch (b_baseAnim.animType) { + case COLOR: + paint.setColor(b_baseAnim.adjustButtonBackGround(b_button_Color, b_normal)); + break; + } + } + + public void setZoomCenter(boolean zoomCenter) { + this.b_zoomCenter = zoomCenter; + } + + public void setTextColor(int text_Color) { + if (b_textPaint != null) b_textPaint.setColor(text_Color); + this.b_text_Color = text_Color; + } + + public void setButtonColor(int button_Color) { + this.b_button_Color = button_Color; + this.paint.setColor(button_Color); + } + + + @Override + public void setNormal(boolean b_normal) { + if (b_baseAnim != null) { + this.b_baseAnim.animating = true; + this.b_normal = b_normal; + } + } + + public void setAnimation(BaseButtonAnimation anim) { + this.b_baseAnim = anim; + } + + @Override + public void setText(String b_text) { + this.b_text = b_text; + } + + public void setPosition(int x, int y) { + this.b_position.x = x; + this.b_position.y = y; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextureButton.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextureButton.java new file mode 100644 index 0000000..31586a5 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/TextureButton.java @@ -0,0 +1,127 @@ +package com.lfk.justweengine.drawable.Button; + +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.renderscript.Float2; + +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.engine.GameTexture; +import com.lfk.justweengine.utils.tools.DisplayUtils; + +/** + * 图片Button + * + * @author liufengkai + * Created by liufengkai on 15/12/2. + */ +public class TextureButton extends BaseButton { + private GameTexture texture; + private int b_alpha; + private boolean zoomCenter; + private boolean firstInit; + + public TextureButton(Engine b_engine, String name) { + super(b_engine, name); + init(); + } + + + public TextureButton(Engine b_engine, String name, int b_width, int b_height) { + super(b_engine, b_width, b_height, name); + init(); + } + + private void init() { + b_alpha = 255; + zoomCenter = false; + firstInit = false; + texture = new GameTexture(b_engine); + b_position = new Point(0, 0); + b_scale = new Float2(1.0f, 1.0f); + } + + @Override + public void draw() { + e_canvas = b_engine.getCanvas(); + if (b_width == 0 || b_height == 0) { + b_width = texture.getBitmap().getWidth(); + b_height = texture.getBitmap().getHeight(); + } + + Rect src = new Rect(0, 0, b_width, b_height); + + int x = b_position.x; + int y = b_position.y; + int w = (int) (b_width * b_scale.x); + int h = (int) (b_height * b_scale.y); + + if (!firstInit) { + b_rect = new Rect(x, y, x + w, y + h); + firstInit = true; + } + + if (!zoomCenter) { + b_rect = new Rect(x, y, x + w, y + h); + } + + paint.setAlpha(b_alpha); + e_canvas.drawBitmap(texture.getBitmap(), src, b_rect, paint); + + paint.setStyle(Paint.Style.STROKE); + } + + @Override + public void animation() { + if (b_baseAnim != null && b_baseAnim.animating) { + doAnimation(); + } + } + + private void doAnimation() { + switch (b_baseAnim.animType) { + case ZOOM_CENTER: + b_rect = b_baseAnim.adjustButtonRect(b_rect, b_normal); + break; + case MASK: + + break; + } + } + + public void setPosition(Point b_position) { + this.b_position = b_position; + } + + public void setPosition(int x, int y) { + this.b_position.x = x; + this.b_position.y = y; + } + + public void setZoomCenter(boolean zoomCenter) { + this.zoomCenter = zoomCenter; + } + + public void setTexture(GameTexture texture) { + this.texture = texture; + } + + public void setAnimation(BaseButtonAnimation anim) { + this.b_baseAnim = anim; + } + + public void setDipScale(int dipW, int dipH) { + if (b_width == 0 || b_height == 0) { + b_width = texture.getBitmap().getWidth(); + b_height = texture.getBitmap().getHeight(); + } + setScale(new Float2(DisplayUtils.dip2px(dipW) * 1.0f / b_width, + DisplayUtils.dip2px(dipH) * 1.0f / b_height)); + } + + @Override + public void setNormal(boolean b_normal) { + this.b_normal = b_normal; + this.b_baseAnim.animating = true; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Button/ZoomCenterButtonAnim.java b/engine/src/main/java/com/lfk/justweengine/drawable/Button/ZoomCenterButtonAnim.java new file mode 100644 index 0000000..8da8963 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Button/ZoomCenterButtonAnim.java @@ -0,0 +1,56 @@ +package com.lfk.justweengine.drawable.Button; + +import android.graphics.Rect; + +import com.lfk.justweengine.anim.AnimType; + +/** + * Created by liufengkai on 15/12/12. + */ +public class ZoomCenterButtonAnim extends BaseButtonAnimation { + private int from; + private int to; + private int frame; + private float speed; + private int currentFrame; + private boolean start; + private Rect rect; + + public ZoomCenterButtonAnim(int from, int to, int frame) { + this.from = from; + this.to = to; + this.frame = frame; + this.currentFrame = 0; + this.speed = (to - from) * 1.0f / frame; + animating = false; + animType = AnimType.ZOOM_CENTER; + start = true; + } + + @Override + public Rect adjustButtonRect(Rect ori, boolean touchType) { + Rect modify = new Rect(ori); + if (start) { + rect = new Rect(modify); + start = false; + } + + if (touchType) { + animating = false; + currentFrame = 0; + return rect; + } + + if (currentFrame <= frame) { + modify.top -= speed; + modify.left -= speed; + modify.right += speed; + modify.bottom += speed; + currentFrame++; + } else { + animating = false; + currentFrame = 0; + } + return modify; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSprite.java b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSprite.java new file mode 100644 index 0000000..d1d1cc4 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSprite.java @@ -0,0 +1,725 @@ +package com.lfk.justweengine.drawable.Sprite; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.renderscript.Float2; + +import com.lfk.justweengine.anim.BaseAnim; +import com.lfk.justweengine.anim.DoAfterAnimation; +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.engine.GameTexture; +import com.lfk.justweengine.info.UIdefaultData; +import com.lfk.justweengine.utils.tools.DisplayUtils; + +import java.util.LinkedList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * 精灵基类 + * 包含基础的加载图片和位置 + * + * @author liufengkai + * Created by liufengkai on 15/11/27. + */ +public class BaseSprite extends BaseSub { + // 死或生 + private boolean s_alive; + // 是否可碰撞 / 是否检测过 + private boolean s_collidable, s_collided; + private BaseSub e_offender; + private int e_identifier; + private FrameType frameType; + private Canvas s_canvas; + // 图片 + private GameTexture s_texture; + // 画笔 + private Paint s_paint; + // 宽度高度 + private int s_width, s_height; + // 帧动画的列 + private int s_columns; + // 透明度 + private int s_alpha; + // 帧数 + private int s_frame; + // 缩放 + private Float2 s_scale; + // 旋转 + private float s_rotation; + // 固定动画 + private ConcurrentHashMap animMap; + // 流式动画 + private CopyOnWriteArrayList animList; + // 动画结束的回调 + private DoAfterAnimation afterAnimation = null; + private LinkedList s_frame_rect; + private Rect s_dst; + private Rect src; + private Matrix s_matrix, s_mat_scale, s_mat_rotate, s_mat_translation; + private Bitmap s_frameBitmap; + private Canvas s_frameCanvas; + + /** + * easy init + * + * @param engine + */ + public BaseSprite(Engine engine) { + this(engine, 0, 0, 1); + this.frameType = FrameType.SIMPLE; + } + + /** + * init with type + * + * @param engine + * @param w + * @param h + * @param type + */ + public BaseSprite(Engine engine, int w, int h, FrameType type) { + switch (type) { + case SIMPLE: + frameType = FrameType.SIMPLE; + break; + case COMMON: + frameType = FrameType.COMMON; + break; + } + this.s_engine = engine; + this.s_width = w; + this.s_height = h; + init(); + } + + /** + * init with long pic + * + * @param engine + * @param w + * @param h + * @param columns + */ + public BaseSprite(Engine engine, int w, int h, int columns) { + this.s_engine = engine; + this.s_width = w; + this.s_height = h; + this.s_columns = columns; + this.frameType = FrameType.FIXED; + init(); + } + + private void init() { + s_alpha = 255; + s_canvas = null; + s_texture = new GameTexture(s_engine); + s_paint = new Paint(); + s_position = new Float2(0, 0); + s_frame = 0; + animMap = new ConcurrentHashMap<>(); + animList = new CopyOnWriteArrayList<>(); + s_scale = new Float2(1.0f, 1.0f); + s_rotation = 0.0f; + s_collidable = true; + s_collided = false; + s_alive = true; + + if (frameType == FrameType.COMMON) { + s_frame_rect = new LinkedList<>(); + } else if (frameType == FrameType.SIMPLE) { + this.s_columns = 1; + } + + s_dst = new Rect(); + src = new Rect(); + + s_mat_translation = new Matrix(); + s_mat_scale = new Matrix(); + s_mat_rotate = new Matrix(); + s_matrix = new Matrix(); + + s_paint.setColor(UIdefaultData.sprite_default_color_paint); + } + + public void setColor(int color) { + s_paint.setColor(color); + } + + /** + * draw + */ + public void drawWithFixedFrame() { + // init width and height + if (s_width == 0 || s_height == 0) { + s_width = s_texture.getBitmap().getWidth(); + s_height = s_texture.getBitmap().getHeight(); + } + // scratch bitmap + if (s_frameBitmap == null) { + s_frameBitmap = Bitmap.createBitmap(s_width, s_height, Bitmap.Config.ARGB_8888); + s_frameCanvas = new Canvas(s_frameBitmap); + } + + // calculate w/h in each frame + int u = (s_frame % s_columns) * s_width; + int v = (s_frame / s_columns) * s_height; + + // set rect + src.set(u, v, u + s_width, v + s_height); + // scale + int w = s_width;//* s_scale.x + int h = s_height; + s_dst.set(0, 0, w, h); + // draw the frame + s_paint.setAlpha(s_alpha); + s_frameBitmap.eraseColor(Color.TRANSPARENT); + s_frameCanvas.drawBitmap(s_texture.getBitmap(), src, s_dst, s_paint); + + s_matrix.reset(); + s_mat_scale.reset(); + s_mat_rotate.reset(); + s_mat_translation.reset(); + + s_mat_scale.setScale((float) Math.sqrt(s_scale.x), (float) Math.sqrt(s_scale.y)); + s_mat_rotate.setRotate((float) Math.toDegrees(s_rotation)); + s_mat_translation.setTranslate(s_position.x, s_position.y); + + s_matrix.postConcat(s_mat_scale); + s_matrix.postConcat(s_mat_rotate); + s_matrix.postConcat(s_mat_translation); + // update transform + s_canvas.drawBitmap(s_frameBitmap, s_matrix, s_paint); + } + + /** + * draw + */ + @Override + public void draw() { + s_canvas = s_engine.getCanvas(); + switch (frameType) { + case FIXED: + case SIMPLE: + drawWithFixedFrame(); + break; + case COMMON: + drawWithFrame(); + break; + } + debugDraw(); + } + + + /** + * 绘制debug模式下的轮廓线 + */ + public void debugDraw() { + s_engine.debugDraw(getBounds()); + } + + + public void drawWithFrame() { + if (s_width == 0 || s_height == 0) { + s_width = s_frame_rect.getFirst().width(); + s_height = s_frame_rect.getFirst().height(); + } + + if (!s_frame_rect.isEmpty()) { + int x = (int) s_position.x; + int y = (int) s_position.y; + int w = (int) (s_width * s_scale.x); + int h = (int) (s_height * s_scale.y); + s_dst.set(x, y, x + w, y + h); + s_paint.setAlpha(s_alpha); + s_canvas.drawBitmap(s_texture.getBitmap(), + s_frame_rect.get(s_frame), + s_dst, s_paint); + } + } + + /** + * set / get alive + */ + @Override + public boolean getAlive() { + return s_alive; + } + + public void setAlive(boolean s_alive) { + this.s_alive = s_alive; + } + + /** + * set paint + * + * @param paint + */ + public void setPaint(Paint paint) { + s_paint = paint; + } + + /** + * set texture + * + * @param s_texture + */ + public void setTexture(GameTexture s_texture) { + this.s_texture = s_texture; + } + + /** + * get texture + * + * @return + */ + public GameTexture getTexture() { + return s_texture; + } + + /** + * set position + * + * @param x + * @param y + */ + public void setPosition(float x, float y) { + s_position.x = x; + s_position.y = y; + } + + /** + * set position with dip + * + * @param x + * @param y + */ + public void setDipPosition(int x, int y) { + s_position.x = DisplayUtils.dip2px(x); + s_position.y = DisplayUtils.dip2px(y); + } + + /** + * get position + * + * @return + */ + public Float2 getPosition() { + return s_position; + } + + /** + * set frame + * + * @param s_frame + */ + public void setFrame(int s_frame) { + this.s_frame = s_frame; + } + + /** + * get frame + * + * @return + */ + public int getFrame() { + return s_frame; + } + + /** + * set alpha + * + * @param s_alpha + */ + public void setAlpha(int s_alpha) { + this.s_alpha = s_alpha; + } + + /** + * get alpha + * + * @return + */ + public int getAlpha() { + return s_alpha; + } + + /** + * get height + * + * @return + */ + public int getHeight() { + return s_height; + } + + /** + * get width + * + * @return + */ + public int getWidth() { + return s_width; + } + + public int getWidthWithScale() { + return (int) (s_width * s_scale.x); + } + + public int getHeightWidthScale() { + return (int) (s_height * s_scale.y); + } + + /** + * set height + * + * @param h + */ + public void setHeight(int h) { + s_height = h; + } + + /** + * set width + * + * @param w + */ + public void setWidth(int w) { + s_width = w; + } + + /** + * get size + * + * @return + */ + public Float2 getSize() { + return new Float2(s_width, s_height); + } + + /** + * get scale + * + * @return + */ + public Float2 getScale() { + return s_scale; + } + + /** + * set scale + * + * @param scale + */ + public void setScale(Float2 scale) { + s_scale = scale; + } + + public void setScale(float scale) { + s_scale = new Float2(scale, scale); + } + + /** + * get / set rotation + * + * @return + */ + public float getRotation() { + return s_rotation; + } + + public void setRotation(float s_rotation) { + this.s_rotation = s_rotation; + } + + /** + * is collidable ? + * + * @return + */ + public boolean isCollidable() { + return s_collidable; + } + + /** + * is collided ? + * + * @return + */ + public boolean isCollided() { + return s_collided; + } + + /** + * set collidable + * + * @param s_collidable + */ + public void setCollidable(boolean s_collidable) { + this.s_collidable = s_collidable; + } + + /** + * set collided + * + * @param s_collided + */ + public void setCollided(boolean s_collided) { + this.s_collided = s_collided; + } + + /** + * get offender + * + * @return + */ + public BaseSub getOffender() { + return e_offender; + } + + /** + * stop / clear / replace Animation + */ + public void clearAllAnimation() { + if (animList != null) + animList.clear(); + } + + public void clearAllFixedAnimation() { + if (animMap != null) + animMap.clear(); + } + + public void clearAnimation(int position) { + if (animList != null) + animList.remove(position); + } + + public void clearFixedAnimation(String name) { + if (animMap != null) + animMap.remove(name); + } + + public void removeAnimFromList(int index) { + if (animList != null && !animList.isEmpty()) + animList.remove(index); + } + + public void removeFixedAnimFromMap(String name) { + if (animMap != null && !animMap.isEmpty()) + animMap.remove(name); + } + + public void replaceFixedAnimFromMap(String name, BaseAnim anim) { + if (animMap != null && !animMap.isEmpty()) + animMap.replace(name, anim); + } + + /** + * set offender + * + * @param e_offender + */ + @Override + public void setOffender(BaseSub e_offender) { + this.e_offender = e_offender; + } + + /** + * get Bounds + * 获取区域大小 + * + * @return + */ + public RectF getBounds() { + // scaled + return new RectF((int) s_position.x, (int) s_position.y, + (int) (s_position.x + s_width * Math.sqrt(s_scale.x)), + (int) (s_position.y + s_height * Math.sqrt(s_scale.y)));//这里取平方根,不然假设scale=2,算出来就变成了放大4倍。 + } + + /** + * get / set Id + * + * @return + */ + @Override + public int getIdentifier() { + return e_identifier; + } + + public void setIdentifier(int e_identifier) { + this.e_identifier = e_identifier; + } + + /** + * get / set Name + * + * @return + */ + public String getName() { + return s_name; + } + + public void setName(String s_name) { + this.s_name = s_name; + } + + /** + * get / set FrameType + * + * @return + */ + public FrameType getFrameType() { + return frameType; + } + + public void setFrameType(FrameType frameType) { + this.frameType = frameType; + } + + /** + * add anim to list + * + * @param anim + */ + public void addAnimation(BaseAnim anim) { + animList.add(anim); + } + + /** + * add fixed to Map + * + * @param name + * @param anim + */ + public void addfixedAnimation(String name, BaseAnim anim) { + animMap.put(name, anim); + } + + /** + * do fixed anim + * + * @param name + */ + public void fixedAnimation(String name) { + if (animMap.isEmpty()) return; + BaseAnim anim = animMap.get(name); +// anim.animating = true; + if (anim.animating) + doAnimation(anim); + } + + /** + * add rect frame for the common type + * + * @param x + * @param y + * @param w + * @param h + */ + public void addRectFrame(int x, int y, int w, int h) { + if (s_frame_rect != null) { + s_frame_rect.add(new Rect(x, y, x + w, y + h)); + } + } + + /** + * do the anim + * + * @param anim + */ + protected void doAnimation(BaseAnim anim) { + switch (anim.animType) { + case FRAME: + s_frame = anim.adjustFrame(s_frame); + break; + case ALPHA: + s_alpha = anim.adjustAlpha(s_alpha); + break; + case SCALE: + s_scale = anim.adjustScale(s_scale); + break; + case ROTATION: + s_rotation = anim.adjustRotation(s_rotation); + break; + case POSITION: + s_position = anim.adjustPosition(s_position); + break; + case ALIVE: + s_alive = anim.adjustAlive(s_alive); + break; + case SHOOT: + s_position = anim.adjustPosition(s_position); + s_alive = anim.adjustAlive(s_alive); + break; + case ZOOM: + s_scale = anim.adjustScale(s_scale); + break; + } + // listener + if (afterAnimation != null) + afterAnimation.afterAnimation(); + } + + /** + * list animation + */ + public void animation() { + if (animList.isEmpty()) return; + for (BaseAnim anim : animList) { + if (anim.animating) { + doAnimation(anim); + } else { + animList.remove(anim); + return; + } + } + } + + /** + * 设定放大值,相当于设置dp宽高 + * + * @param dp + */ + public void setDipWidth(int dp) { + s_scale.x = DisplayUtils.dip2px(dp) / s_width; + } + + public void setDipHeight(int dp) { + s_scale.y = DisplayUtils.dip2px(dp) / s_height; + } + + public void setDipScale(int dipWidth, int dipHeight) { + if (s_width == 0 || s_height == 0) { + s_width = s_texture.getBitmap().getWidth(); + s_height = s_texture.getBitmap().getHeight(); + } + setScale(new Float2(DisplayUtils.dip2px(dipWidth) / s_width, + DisplayUtils.dip2px(dipHeight) / s_height)); + } + + /** + * 动画后的接口回调 + * + * @param afterAnimation + */ + public void setAfterAnimation(DoAfterAnimation afterAnimation) { + this.afterAnimation = afterAnimation; + } + + /** + * 获取固定动画动作 + * + * @param name + * @return + */ + public BaseAnim getFixedAnimation(String name) { + return animMap.get(name); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSub.java b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSub.java new file mode 100644 index 0000000..85f3955 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/BaseSub.java @@ -0,0 +1,47 @@ +package com.lfk.justweengine.drawable.Sprite; + +import android.graphics.RectF; +import android.renderscript.Float2; + +import com.lfk.justweengine.engine.Engine; + +/** + * 游戏中的抽象基类 + * + * @author liufengkai + * Created by liufengkai on 15/12/4. + */ +public abstract class BaseSub { + // 传入的engine + protected Engine s_engine; + + public Float2 s_position; + + public String s_name; + + public abstract boolean getAlive(); + + public abstract void draw(); + + public abstract void animation(); + + public abstract boolean isCollidable(); + + public abstract boolean isCollided(); + + public abstract void setCollidable(boolean s_collidable); + + public abstract void setCollided(boolean s_collided); + + public abstract BaseSub getOffender(); + + public abstract void setOffender(BaseSub e_offender); + + public abstract RectF getBounds(); + + public abstract int getIdentifier(); + + public abstract void setAlive(boolean s_alive); + + public abstract void debugDraw(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/FrameType.java b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/FrameType.java new file mode 100644 index 0000000..38a4c52 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/FrameType.java @@ -0,0 +1,13 @@ +package com.lfk.justweengine.drawable.Sprite; + +/** + * Created by liufengkai on 15/12/4. + */ +public enum FrameType { + // fixed frame + FIXED, + // frame with rect from a bitmap + COMMON, + // only one frame + SIMPLE +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateFinder.java b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateFinder.java new file mode 100644 index 0000000..8bdd953 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateFinder.java @@ -0,0 +1,8 @@ +package com.lfk.justweengine.drawable.Sprite; + +/** + * Created by liufengkai on 16/1/15. + */ +public interface StateFinder { + boolean isContent(BaseSub baseSub); +} diff --git a/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateSprite.java b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateSprite.java new file mode 100644 index 0000000..413b0de --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/drawable/Sprite/StateSprite.java @@ -0,0 +1,53 @@ +package com.lfk.justweengine.drawable.Sprite; + +import com.lfk.justweengine.anim.BaseAnim; +import com.lfk.justweengine.engine.Engine; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by liufengkai on 16/1/15. + */ +public class StateSprite extends BaseSprite { + private ConcurrentHashMap b_state; + + public StateSprite(Engine engine) { + super(engine); + initState(); + } + + public StateSprite(Engine engine, int w, int h, FrameType type) { + super(engine, w, h, type); + initState(); + } + + public StateSprite(Engine engine, int w, int h, int columns) { + super(engine, w, h, columns); + initState(); + } + + + @Override + public void animation() { + for (StateFinder state : b_state.keySet()) { + if (state.isContent(this)) { + BaseAnim anim = b_state.get(state); + if (anim.animating) { + doAnimation(anim); + } + } + } + } + + protected void initState() { + b_state = new ConcurrentHashMap<>(); + } + + public void addState(StateFinder finder, BaseAnim anim) { + b_state.put(finder, anim); + } + + public void removeState(StateFinder finder) { + b_state.remove(finder); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Engine.java b/engine/src/main/java/com/lfk/justweengine/engine/Engine.java new file mode 100644 index 0000000..8016f7f --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Engine.java @@ -0,0 +1,28 @@ +package com.lfk.justweengine.engine; + +import android.app.Activity; +import android.content.pm.ActivityInfo; +import android.graphics.Canvas; +import android.graphics.RectF; + +/** + * Created by liufengkai on 16/5/8. + */ +public abstract class Engine extends Activity { + + public enum ScreenMode { + LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), + PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + public int value; + + ScreenMode(int mode) { + this.value = mode; + } + } + + protected boolean isOpenDebug; + + public abstract Canvas getCanvas(); + + public abstract void debugDraw(RectF bound); +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/GameTextPrinter.java b/engine/src/main/java/com/lfk/justweengine/engine/GameTextPrinter.java new file mode 100644 index 0000000..57b4038 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/GameTextPrinter.java @@ -0,0 +1,79 @@ +package com.lfk.justweengine.engine; + +import android.graphics.Canvas; +import android.graphics.Paint; + +/** + * 文字绘制类 + * + * @author liufengkai + * Created by liufengkai on 15/11/27. + */ +public class GameTextPrinter { + protected Canvas e_canvas; + private Paint e_paint; + protected float e_x, e_y; + private float e_spaceing; + private String text; + + public GameTextPrinter() { + this(null); + } + + public GameTextPrinter(Canvas e_canvas) { + this.e_canvas = e_canvas; + e_paint = new Paint(); + e_paint.setAntiAlias(true); + e_x = e_y = 0; + e_spaceing = 22; + } + + public void setCanvas(Canvas e_canvas) { + this.e_canvas = e_canvas; + } + + public void setLineSpaceing(float e_spaceing) { + this.e_spaceing = e_spaceing; + } + + public void setTextSize(int size) { + e_paint.setTextSize(size); + } + + public void setTextColor(int color) { + e_paint.setColor(color); + } + + public void drawText(String text, float x, float y) { + e_x = x; + e_y = y; + drawText(text); + } + + public void drawText(String text) { + e_canvas.drawText(text, e_x, e_y, e_paint); + e_y += e_spaceing; + } + + public void setText(String text) { + this.text = text; + } + + public void draw() { + if (text != null) + drawText(text); + } + + public void setX(float e_x) { + this.e_x = e_x; + } + + public void setY(float e_y) { + this.e_y = e_y; + } + + public void setTextPosition(float e_x, float e_y) { + this.e_x = e_x; + this.e_y = e_y; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/GameTexture.java b/engine/src/main/java/com/lfk/justweengine/engine/GameTexture.java new file mode 100644 index 0000000..373525d --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/GameTexture.java @@ -0,0 +1,111 @@ +package com.lfk.justweengine.engine; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import com.lfk.justweengine.utils.io.GameIO; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 封装图片的获取 + * Created by liufengkai on 15/11/27. + */ +public class GameTexture { + private Context e_context; + private Bitmap e_bitmap; + private GameIO gameIO; + + public GameTexture(Context e_context) { + this.e_context = e_context; + this.e_bitmap = null; + this.gameIO = new GameIO(e_context); + } + + public Bitmap getBitmap() { + return e_bitmap; + } + + public GameTexture(Bitmap e_bitmap) { + this.e_bitmap = e_bitmap; + } + + /** + * get bitmap form assets + * + * @param filename + * @return + */ + public boolean loadFromAsset(String filename) { + InputStream inputStream; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + try { + inputStream = gameIO.readAsset(filename); + e_bitmap = BitmapFactory.decodeStream(inputStream, null, options); + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * get bitmap from a big bitmap + * + * @param filename + * @param x + * @param y + * @param width + * @param height + * @return + */ + public boolean loadFromAssetStripFrame(String filename, + int x, int y, + int width, int height) { + InputStream inputStream; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + try { + inputStream = gameIO.readAsset(filename); + Bitmap temp = BitmapFactory.decodeStream(inputStream, null, options).copy(Bitmap.Config.ARGB_8888, true); + inputStream.close(); + e_bitmap = Bitmap.createBitmap(temp, x, y, width, height); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + return true; + } + + public static Bitmap loadFromBigBitmap(GameTexture texture, int x, int y + , int w, int h) { + return Bitmap.createBitmap(texture.getBitmap(), x, y, w, h); + } + + public void setBitmap(Bitmap e_bitmap) { + this.e_bitmap = e_bitmap; + } + + /** + * 从大图取出小图 + * + * @param x 横轴 + * @param y 纵轴 + * @param w 宽 + * @param h 高 + * @return + */ + public GameTexture getFrameFromBitmap(int x, int y, + int w, int h) { + if (e_bitmap != null) { + Bitmap bitmap = + Bitmap.createBitmap(e_bitmap, x, y, w, h); + return new GameTexture(bitmap); + } + return null; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/GameTimer.java b/engine/src/main/java/com/lfk/justweengine/engine/GameTimer.java new file mode 100644 index 0000000..7eaa717 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/GameTimer.java @@ -0,0 +1,57 @@ +package com.lfk.justweengine.engine; + +/** + * 计时器 + *

+ * 控制帧数\节律 + * + * @author liufengkai + * Created by liufengkai on 15/11/27. + */ +public class GameTimer { + private long e_start; + private long e_stopWatchStart; + + public GameTimer() { + e_start = System.currentTimeMillis(); + e_stopWatchStart = 0; + } + + /** + * get time from start to now + * + * @return time from start to now + */ + public long getElapsed() { + return System.currentTimeMillis() - e_start; + } + + /** + * rest time + * + * @param ms + */ + public void rest(int ms) { + long start = getElapsed(); + while (start + ms > getElapsed()) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { +// Logger.e("engine gameTimer error:" + e); + } + } + } + + public void resetStop() { + e_stopWatchStart = getElapsed(); + } + + + public boolean stopWatch(long ms) { + if (getElapsed() > e_stopWatchStart + ms) { + resetStop(); + return true; + } else + return false; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/ButtonLayer.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/ButtonLayer.java new file mode 100644 index 0000000..2c574c0 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/ButtonLayer.java @@ -0,0 +1,99 @@ +package com.lfk.justweengine.engine.Layer; + +import android.graphics.Rect; +import android.view.MotionEvent; + +import com.lfk.justweengine.drawable.Button.BaseButton; + +import java.util.HashMap; + +/** + * Created by liufengkai on 16/5/8. + */ +public class ButtonLayer extends Layer { + // 按钮组 + private HashMap e_button_group; + + private boolean e_is_hit_button; + private BaseButton e_hit_button = null; + + public ButtonLayer(Screen layerScreen, Rect layerField) { + super(LayerType.Button, layerScreen, layerField); + init(); + } + + public ButtonLayer(Screen layerScreen, int x, int y, int w, int h) { + super(LayerType.Button, layerScreen, new Rect(x, y, w, h)); + init(); + } + + private void init() { + e_is_hit_button = false; + e_hit_button = null; + e_button_group = new HashMap<>(); + } + + @Override + protected void layerUpdate() { + + } + + @Override + protected void layerDraw() { + for (String o : e_button_group.keySet()) { + BaseButton button = e_button_group.get(o); + button.animation(); + button.draw(); + } + } + + @Override + protected void layerCollision() { + + } + + + @Override + protected void layerClick(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + for (String name : e_button_group.keySet()) { + BaseButton button = e_button_group.get(name); + if (button.getRect().contains((int) event.getX(), + (int) event.getY())) { + button.setNormal(false); + e_is_hit_button = true; + e_hit_button = button; + } + } + break; + case MotionEvent.ACTION_UP: + if (e_hit_button != null && e_is_hit_button && + e_hit_button.getRect().contains((int) event.getX(), + (int) event.getY())) { + e_hit_button.setNormal(true); + e_hit_button.onClick(true); + resetHitButton(); + } else if (e_is_hit_button) { + if (e_hit_button != null) { + e_hit_button.setNormal(true); + resetHitButton(); + } + } + break; + } + } + + public void addToButtonGroup(BaseButton button) { + e_button_group.put(button.getName(), button); + } + + public void removeButtonFromGroup(String name) { + e_button_group.remove(name); + } + + private void resetHitButton() { + e_is_hit_button = false; + e_hit_button = null; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/DefaultLayer.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/DefaultLayer.java new file mode 100644 index 0000000..51e787c --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/DefaultLayer.java @@ -0,0 +1,215 @@ +package com.lfk.justweengine.engine.Layer; + +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.Log; +import android.view.MotionEvent; + +import com.lfk.justweengine.drawable.Bone.BoneGroupSprite; +import com.lfk.justweengine.drawable.Sprite.BaseSub; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * 默认实现的绘制层 + * + * @author liufengkai + * Created by liufengkai on 16/5/8. + */ +public class DefaultLayer extends Layer { + // 对象绘制组 + private CopyOnWriteArrayList l_sprite_group; + // 对象回收组 + private CopyOnWriteArrayList l_sprite_recycle_group; + + public DefaultLayer(Screen screen, Rect layerField) { + super(LayerType.Default, screen, layerField); + init(); + } + + public DefaultLayer(LayerType type, Screen screen, int x, int y, int w, int h) { + super(type, screen, new Rect(x, y, w, h)); + init(); + } + + /** + * 初始化 + */ + private void init() { + l_sprite_group = new CopyOnWriteArrayList<>(); + l_sprite_recycle_group = new CopyOnWriteArrayList<>(); + } + + @Override + protected void layerUpdate() { + for (BaseSub A : l_sprite_group) { + if (!A.getAlive()) continue; + + if (!A.isCollidable()) continue; + + if (A.isCollided()) continue; + + for (BaseSub B : l_sprite_group) { + if (!B.getAlive()) continue; + + if (!B.isCollidable()) continue; + + if (B.isCollided()) continue; + + if (A == B) continue; + + if (A.getIdentifier() == + B.getIdentifier()) + continue; + + if (collisionCheck(A, B)) { + A.setCollided(true); + A.setOffender(B); + B.setCollided(true); + B.setOffender(A); + break; + } + } + } + } + + @Override + protected void layerDraw() { + for (BaseSub baseSub : l_sprite_group) { + if (baseSub.getAlive()) { + baseSub.animation(); + baseSub.draw(); + } + baseSub.debugDraw(); + } + } + + @Override + protected void layerCollision() { + // new collision + for (BaseSub baseSub : l_sprite_group) { + if (!baseSub.getAlive()) { + l_sprite_recycle_group.add(baseSub); + l_sprite_group.remove(baseSub); + continue; + } + + if (baseSub.isCollidable()) { + if (baseSub.isCollided()) { + // Is it a valid object ? + if (baseSub.getOffender() != null) { + // collision + if (layerListener != null) + layerListener.Collision(baseSub); + // reset offender + baseSub.setOffender(null); + } + baseSub.setCollided(false); + } + } + + baseSub.setCollided(false); + } + + } + + @Override + protected void layerClick(MotionEvent event) { + + } + + /** + * 检测碰撞 + * + * @param A a 物体 + * @param B b 物体 + * @return 是否碰撞 + */ + private boolean collisionCheck(BaseSub A, BaseSub B) { + return RectF.intersects(A.getBounds(), B.getBounds()); + } + + /** + * add BaseSub to group + * + * @param sprite + */ + public void addToSpriteGroup(BaseSub sprite) { + l_sprite_group.add(sprite); + } + + /** + * add boneSprite + * + * @param sprite + */ + public void addToSpriteGroup(BoneGroupSprite sprite) { + for (String name : sprite.getSpriteMap().keySet()) { + addToSpriteGroup(sprite.getBoneSprite(name)); + } + } + + /** + * remove from group + * + * @param sprite + */ + public void removeFromSpriteGroup(BaseSub sprite) { + l_sprite_group.remove(sprite); + } + + public void removeFromSpriteGroup(int index) { + l_sprite_group.remove(index); + } + + /** + * get size + * + * @return size + */ + public int getSpriteGroupSize() { + return l_sprite_group.size(); + } + + public int getRecycleGroupSize() { + return l_sprite_recycle_group.size(); + } + + public void addToRecycleGroup(BaseSub baseSub) { + l_sprite_recycle_group.add(baseSub); + } + + public void removeFromRecycleGroup(int index) { + l_sprite_recycle_group.remove(index); + } + + public void removeFromRecycleGroup(BaseSub baseSub) { + l_sprite_recycle_group.remove(baseSub); + } + + public boolean isRecycleGroupEmpty() { + return l_sprite_recycle_group.isEmpty(); + } + + public BaseSub recycleSubFromGroup(int id) { + for (BaseSub baseSub : l_sprite_recycle_group) { + if (baseSub.getIdentifier() == id) { + return baseSub; + } + } + return null; + } + + + public int getTypeSizeFromRecycleGroup(int id) { + int num = 0; + for (BaseSub baseSub : l_sprite_recycle_group) { + if (baseSub.getIdentifier() == id) { + num++; + } + } + Log.e("num" + num, "id" + id); + return num; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/Layer.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/Layer.java new file mode 100644 index 0000000..061d00b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/Layer.java @@ -0,0 +1,95 @@ +package com.lfk.justweengine.engine.Layer; + +import android.graphics.Rect; +import android.view.MotionEvent; + +import com.lfk.justweengine.drawable.Sprite.BaseSub; + +/** + * Layer 绘制分层 + * 负责数据处理 + * Created by liufengkai on 16/5/8. + */ +public abstract class Layer { + public enum LayerType { + Button, + Default + } + + public interface LayerListener { + boolean Touch(MotionEvent event); + + void Collision(BaseSub baseSub); + + void Update(); + + void Draw(); + } + + + protected LayerType layerType; + + protected String layerName; + // Layer的刷新范围也是绘制范围 + protected Rect layerField; + + protected Screen layerScreen; + + protected int layerBackgroundColor; + + protected LayerListener layerListener; + + protected abstract void layerUpdate(); + + protected abstract void layerDraw(); + + protected abstract void layerCollision(); + + protected abstract void layerClick(MotionEvent event); + + public Layer(LayerType layerType, Screen layerScreen, Rect layerField) { + this.setLayerType(layerType); + this.layerField = layerField; + this.layerScreen = layerScreen; + } + + public Rect getLayerField() { + return layerField; + } + + public void setLayerField(Rect layerField) { + this.layerField = layerField; + } + + public LayerType getLayerType() { + return layerType; + } + + public String getLayerName() { + return layerName; + } + + public void setLayerName(String layerName) { + this.layerName = layerName; + } + + public void setLayerType(LayerType layerType) { + this.layerType = layerType; + } + + public int getLayerBackgroundColor() { + return layerBackgroundColor; + } + + public void setLayerBackgroundColor(int layerBackgroundColor) { + this.layerBackgroundColor = layerBackgroundColor; + } + + public LayerListener getLayerListener() { + return layerListener; + } + + public void setLayerListener(LayerListener layerListener) { + this.layerListener = layerListener; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/LayerEngine.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/LayerEngine.java new file mode 100644 index 0000000..899ba4e --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/LayerEngine.java @@ -0,0 +1,174 @@ +package com.lfk.justweengine.engine.Layer; + +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.Window; + +import com.lfk.justweengine.drawable.Sprite.BaseSub; +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.utils.logger.LogLevel; +import com.lfk.justweengine.utils.logger.Logger; + +/** + * 使用了Layer分层的Engine + * + * @author liufengkai + * Created by liufengkai on 16/5/5. + */ +public abstract class LayerEngine extends Engine { + protected Screen layerEngineScreen; + + public abstract void init(); + + public abstract void load(); + + public abstract void update(); + + public abstract void touch(MotionEvent event); + + public abstract void collision(BaseSub baseSub); + + public LayerEngine() { + // init logger + Logger.init().logLevel(LogLevel.NONE); + } + + public LayerEngine(boolean isOpenDebug) { + this.isOpenDebug = isOpenDebug; + if (!isOpenDebug) { + Logger.init().logLevel(LogLevel.NONE); + } else { + Logger.init(); + } + } + + private void Engine() { + this.layerEngineScreen = new Screen(this, new Screen.ScreenListener() { + @Override + public void Init() { + init(); + } + + @Override + public void Load() { + load(); + } + + @Override + public void Update() { + update(); + } + + @Override + public void Touch(MotionEvent event) { + touch(event); + } + }); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Logger.d("engine onCreate start"); + + this.Engine(); + this.requestWindowFeature(Window.FEATURE_NO_TITLE); + this.getWindow().setFormat(PixelFormat.TRANSLUCENT); + setContentView(layerEngineScreen); + layerEngineScreen.createScreen(); + + Logger.d("engine onCreate end"); + + } + + /** + * engine onResume + */ + @Override + protected void onResume() { + super.onResume(); + Logger.d("engine onResume"); + layerEngineScreen.restart(); + // need add... + } + + /** + * engine onPause + */ + @Override + protected void onPause() { + super.onPause(); + Logger.d("engine onPause"); + layerEngineScreen.pause(); + layerEngineScreen.addPauseTime(); + // need add... + } + + /** + * 设定整体背景 + * + * @param color + */ + public void setBackgroundColor(int color) { + this.layerEngineScreen.setBackgroundColor(color); + } + + /** + * set screenOrientation + * + * @param mode + */ + public void setScreenOrientation(ScreenMode mode) { + setRequestedOrientation(mode.value); + } + + + @Override + public Canvas getCanvas() { + return layerEngineScreen.getCanvas(); + } + + public Screen getScreen() { + return layerEngineScreen; + } + + @Override + public void debugDraw(RectF bound) { + layerEngineScreen.debugDraw(bound); + } + + /** + * 添加一层 + * + * @param layer + */ + public void addLayer(Layer layer) { + layerEngineScreen.addLayer(layer); + } + + /** + * 在某层之上添加一层 + * + * @param layer + * @param name + */ + public void addLayerBefore(Layer layer, String name) { + layerEngineScreen.addLayerBefore(layer, name); + } + + /** + * 在某层之下添加一层 + * + * @param layer + * @param name + */ + public void addLayerAfter(Layer layer, String name) { + layerEngineScreen.addLayerAfter(layer, name); + } + + +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/Screen.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/Screen.java new file mode 100644 index 0000000..f16ea3c --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/Screen.java @@ -0,0 +1,597 @@ +package com.lfk.justweengine.engine.Layer; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.renderscript.Float2; +import android.renderscript.Float3; +import android.view.MotionEvent; +import android.view.SurfaceView; +import android.view.View; + +import com.lfk.justweengine.engine.GameTimer; +import com.lfk.justweengine.engine.TouchMode; +import com.lfk.justweengine.utils.logger.LogLevel; +import com.lfk.justweengine.utils.logger.Logger; + +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + * Screen SurfaceView封装视图 + * 负责绘制 + * Created by liufengkai on 16/5/5. + */ +public class Screen extends SurfaceView implements Runnable, View.OnTouchListener { + public static final int RESULT_OK = -1; + + private Canvas e_canvas; + // 主循环 + private Thread e_thread; + // 循环控制 + private boolean e_running, e_paused; + private int e_pauseCount; + private Paint e_paintDraw, e_paintFont; + private int e_numPoints; + private long e_prefferredFrameRate, e_sleepTime; + private Typeface e_typeface; + private Point[] e_touchPoints; + private boolean e_touchModesAble; + // 多点触控数 + private int e_touchNum; + private int e_backgroundColor; + private boolean e_isFrameOpen; + private TouchMode e_touch_Mode; + + private ArrayList e_layers; + private boolean isOpenDebug; + private ScreenListener screenListener; + private Context e_engine; + + public interface ScreenListener { + void Init(); + + void Load(); + + void Update(); + + void Touch(MotionEvent event); + } + + public Screen(Context context, ScreenListener screenListener) { + super(context); + this.e_engine = context; + this.setLayerListener(screenListener); + init(); + } + + public Screen(Context context, ScreenListener screenListener, boolean isOpenDebug) { + super(context); + this.isOpenDebug = isOpenDebug; + if (!isOpenDebug) { + Logger.init().logLevel(LogLevel.NONE); + } else { + Logger.init(); + } + this.setLayerListener(screenListener); + init(); + } + + private void init() { + e_canvas = null; + e_thread = null; + e_running = false; + e_paused = false; + e_paintDraw = null; + e_pauseCount = 0; + e_paintFont = null; + e_numPoints = 0; + e_prefferredFrameRate = 40; + e_sleepTime = 1000 / e_prefferredFrameRate; + e_typeface = null; + e_touchModesAble = true; + e_touchNum = 5; + e_isFrameOpen = true; + e_touch_Mode = TouchMode.SINGLE; + e_backgroundColor = Color.BLACK; + + e_layers = new ArrayList<>(); + this.setOnTouchListener(this); + this.destroyDrawingCache(); + this.setDrawingCacheEnabled(false); + this.setClickable(false); + this.setFocusable(true); + this.setFocusableInTouchMode(true); + this.setKeepScreenOn(true); + this.setLongClickable(false); + } + + /** + * 默认要放在onCreate()里面 + * 负责创建绘制页面 + */ + public void createScreen() { + screenListener.Init(); + + // draw paint + e_paintDraw = new Paint(); + e_paintDraw.setColor(Color.WHITE); + // font paint + e_paintFont = new Paint(); + e_paintFont.setColor(Color.WHITE); + e_paintFont.setTextSize(24); + + screenListener.Load(); + + // init thread + e_running = true; + e_thread = new Thread(this); + e_thread.start(); + + } + + @Override + public void run() { + Logger.d("engine run start"); + + GameTimer frameTimer = new GameTimer(); + int frameCount = 0; + int frameRate = 0; + long startTime; + long timeDiff; + + while (e_running) { + if (e_paused) continue; + + frameCount++; + startTime = frameTimer.getElapsed(); + + // frame rate + if (frameTimer.stopWatch(1000)) { + + frameRate = frameCount; + + frameCount = 0; + + // reset points + e_numPoints = 0; + } + + // update + screenListener.Update(); + + for (int i = 0; i < e_layers.size(); i++) { + e_layers.get(i).layerUpdate(); + if (e_layers.get(i).getLayerListener() != null) + e_layers.get(i).getLayerListener().Update(); + } + + for (int i = 0; i < e_layers.size(); i++) { + // lock canvas + + Layer layer = e_layers.get(i); + + if (beginDrawing(layer.getLayerField())) { + e_canvas.drawColor(e_backgroundColor); + + e_canvas.drawColor(layer.layerBackgroundColor); + // draw + // ahead of draw concrete sub + + layer.layerDraw(); + + // user method draw + if (layer.getLayerListener() != null) { + layer.getLayerListener().Draw(); + } + + if (e_isFrameOpen && isOpenDebug) { + int x = e_canvas.getWidth() - 150; + e_canvas.drawText("engine", x, 20, e_paintFont); + e_canvas.drawText(toString(frameRate) + "fps", x, 40, e_paintFont); + e_canvas.drawText("pauses:" + toString(e_pauseCount), x, 60, e_paintFont); + } + + // unlock the canvas + endDrawing(); + } + + // new collision + layer.layerCollision(); + } + + // lock frame + timeDiff = frameTimer.getElapsed() - startTime; + long updatePeriod = e_sleepTime - timeDiff; +// Logger.v("period", updatePeriod); + if (updatePeriod > 0) { + try { + Thread.sleep(updatePeriod); + } catch (InterruptedException e) { +// Logger.e("engine run start error:" + e); + } + } + } + Logger.d("engine run end"); + System.exit(RESULT_OK); + } + + + /** + * engine onTouch + * + * @param v + * @param event + * @return + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (e_touch_Mode) { + case SINGLE: + screenListener.Touch(event); + break; + case FULL: + stuffTouchPoints(event); + break; + case BUTTON: + findTouchButton(event); + break; + case SINGLE_BUTTON: + if (!findTouchButton(event)) + screenListener.Touch(event); + break; + case SINGLE_LAYER: + distributeTouchEventInLayer(event); + break; + } + return true; + } + + /** + * begin draw + * + * @return + */ + private boolean beginDrawing(Rect rect) { + if (!this.getHolder().getSurface().isValid()) { + return false; + } + e_canvas = this.getHolder().lockCanvas(rect); + return true; + } + + /** + * end draw + */ + private void endDrawing() { + this.getHolder().unlockCanvasAndPost(e_canvas); + } + + /** + * open frame count + * + * @param e_isFrameOpen + */ + public void setIsFrameOpen(boolean e_isFrameOpen) { + this.e_isFrameOpen = e_isFrameOpen; + } + + /** + * background color + * + * @param e_backgroundColor + */ + public void setBackgroundColor(int e_backgroundColor) { + this.e_backgroundColor = e_backgroundColor; + } + + /** + * set touch number + * + * @param e_touchNum + */ + public void setTouchNum(int e_touchNum) { + this.e_touchNum = e_touchNum; + } + + /** + * set touch mode able + * + * @param e_touchModesAble + */ + public void setTouchModesAble(boolean e_touchModesAble) { + this.e_touchModesAble = e_touchModesAble; + } + + /** + * shortcut method to duplicate existing Android methods + * + * @param msg + */ + public void fatalError(String msg) { + Logger.e("engine fatal error:" + msg); + System.exit(0); + } + + /** + * draw text + * + * @param text + * @param x + * @param y + */ + public void drawText(String text, int x, int y) { + e_canvas.drawText(text, x, y, e_paintFont); + } + + /** + * engine helper + */ + + /** + * @return surface + */ + public SurfaceView getSurfaceView() { + return this; + } + + /** + * @return canvas + */ + public Canvas getCanvas() { + return e_canvas; + } + + /** + * set frame rete + * + * @param rate + */ + public void setFrameRate(int rate) { + e_prefferredFrameRate = rate; + e_sleepTime = 1000 / e_prefferredFrameRate; + } + + /** + * get touch puts + * + * @return + */ + public int getTouchPoints() { + return e_numPoints; + } + + /** + * get touch point + * + * @param n + * @return + */ + public Point getTouchPoint(int n) { + if (n < 0) { + Logger.e("error", "without point" + n); + n = 0; + } + if (n > e_touchNum) { + n = e_touchNum; + } + return e_touchPoints[n]; + } + + /** + * set paint color + * + * @param color + */ + public void setDrawColor(int color) { + e_paintDraw.setColor(color); + } + + /** + * set text color + * + * @param color + */ + public void setTextColor(int color) { + e_paintFont.setColor(color); + } + + /** + * set text size + * + * @param size + */ + public void setTextSize(int size) { + e_paintFont.setTextSize(size); + } + + public void setTextSize(float size) { + e_paintFont.setTextSize((int) size); + } + + public enum FontStyles { + NORMAL(Typeface.NORMAL), + BOLD(Typeface.BOLD), + ITALIC(Typeface.ITALIC), + BOLD_ITALIC(Typeface.BOLD_ITALIC),; + int value; + + FontStyles(int value) { + this.value = value; + } + } + + /** + * set type face + * + * @param style + */ + public void setFontStyle(FontStyles style) { + e_typeface = Typeface.create(Typeface.DEFAULT, style.value); + e_paintFont.setTypeface(e_typeface); + } + + public void setFontStyle(Typeface style) { + e_paintFont.setTypeface(style); + } + + /** + * to string + * + * @param value + * @return + */ + public String toString(int value) { + return Integer.toString(value); + } + + public String toString(float value) { + return Float.toString(value); + } + + public String toString(double value) { + return Double.toString(value); + } + + public String toString(Float2 value) { + return "X:" + round(value.x) + "," + "Y:" + round(value.y); + } + + public String toString(Float3 value) { + return "X:" + round(value.x) + "," + "Y:" + round(value.y) + + "Z:" + round(value.z); + } + + public String toString(Rect value) { + RectF rectF = new RectF(value.left, value.top, value.right, value.bottom); + return toString(rectF); + } + + public String toString(RectF value) { + return "{" + round(value.left) + "," + + round(value.top) + "," + + round(value.right) + "," + + round(value.bottom) + "}"; + } + + /** + * double round + * + * @param value + * @return + */ + public double round(double value) { + return round(value, 2); + } + + private double round(double value, int precision) { + try { + BigDecimal bd = new BigDecimal(value); + BigDecimal rounded = bd.setScale(precision, BigDecimal.ROUND_HALF_UP); + return rounded.doubleValue(); + } catch (Exception e) { + Logger.e("engine", " round error:" + e); + } + Logger.e("engine", " round D:" + 0); + return 0; + } + + private void stuffTouchPoints(MotionEvent event) { + e_numPoints = event.getPointerCount(); + if (e_numPoints > e_touchNum) { + e_numPoints = e_touchNum; + } + + for (int n = 0; n < e_numPoints; n++) { + Logger.v("engine", e_touchNum + ":" + e_numPoints); + e_touchPoints[n].x = (int) event.getX(n); + e_touchPoints[n].y = (int) event.getY(n); + } + } + + private boolean findTouchButton(MotionEvent event) { + for (int i = 0; i < e_layers.size(); i++) { + if (e_layers.get(i).getLayerType() == Layer.LayerType.Button + && e_layers.get(i).getLayerField() + .contains((int) event.getX(), (int) event.getY())) { + e_layers.get(i).layerClick(event); + return true; + } + } + return false; + } + + private void distributeTouchEventInLayer(MotionEvent event) { + for (int i = 0; i < e_layers.size(); i++) { + if (e_layers.get(i).getLayerField() + .contains((int) event.getX(), (int) event.getY())) { + e_layers.get(i).layerListener.Touch(event); + break; + } + } + } + + + public void debugDraw(RectF bound) { + if (isOpenDebug) { + e_paintDraw.setColor(Color.RED); + e_paintDraw.setStyle(Paint.Style.STROKE); + e_canvas.drawRect(bound, e_paintDraw); + } + } + + public void setLayerListener(ScreenListener Listener) { + this.screenListener = Listener; + } + + public void setTouchMode(TouchMode e_touch_Mode) { + this.e_touch_Mode = e_touch_Mode; + } + + public ScreenListener getLayerListener() { + return screenListener; + } + + public void addLayer(Layer layer) { + this.e_layers.add(layer); + } + + public void addLayerBefore(Layer layer, String name) { + int index = 0; + for (; index < e_layers.size(); index++) { + if (e_layers.get(index).getLayerName().equals(name)) { + break; + } + } + this.e_layers.add(index, layer); + } + + public void addLayerAfter(Layer layer, String name) { + int index = 0; + for (; index < e_layers.size(); index++) { + if (e_layers.get(index).getLayerName().equals(name)) { + index++; + break; + } + } + this.e_layers.add(index, layer); + } + + + public void restart() { + this.e_paused = false; + } + + public void pause() { + this.e_paused = true; + } + + public void addPauseTime() { + this.e_pauseCount++; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/Layer/SimpleLayerEngine.java b/engine/src/main/java/com/lfk/justweengine/engine/Layer/SimpleLayerEngine.java new file mode 100644 index 0000000..672f8aa --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/Layer/SimpleLayerEngine.java @@ -0,0 +1,56 @@ +package com.lfk.justweengine.engine.Layer; + +import android.graphics.Rect; +import android.os.Bundle; + +import com.lfk.justweengine.info.UIdefaultData; + +/** + * 默认的分层引擎实现 + * 添加了默认的主布局层 + * Created by liufengkai on 16/5/9. + */ +public abstract class SimpleLayerEngine extends LayerEngine { + // 默认Layer层 + private DefaultLayer defaultMainLayer; + // 默认Layer监听器 + private Layer.LayerListener defaultMainLayerListener; + + public SimpleLayerEngine() { + + } + + public SimpleLayerEngine(boolean isOpenDebug) { + super(isOpenDebug); + + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addDefaultLayer(); + } + + /** + * 添加默认Layer + */ + private void addDefaultLayer() { + defaultMainLayer = new DefaultLayer(getScreen(), + new Rect(0, 0, UIdefaultData.screenWidth, + UIdefaultData.screenHeight)); + defaultMainLayer.setLayerName("MainLayer"); + layerEngineScreen.addLayer(defaultMainLayer); + } + + public Layer.LayerListener getDefaultMainLayerListener() { + return defaultMainLayerListener; + } + + public void setDefaultMainLayerListener(Layer.LayerListener defaultMainLayerListener) { + this.defaultMainLayerListener = defaultMainLayerListener; + } + + public DefaultLayer getDefaultMainLayer() { + return defaultMainLayer; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/ObjectPool.java b/engine/src/main/java/com/lfk/justweengine/engine/ObjectPool.java new file mode 100644 index 0000000..7c82332 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/ObjectPool.java @@ -0,0 +1,77 @@ +package com.lfk.justweengine.engine; + +import java.util.ArrayList; +import java.util.List; + +/** + * 对象回收池 + * 和自动的对象回收池可以选择使用 + * + * @author liufengkai + * Created by liufengkai on 16/1/17. + */ +public class ObjectPool { + public String poolName = null; + + public ObjectPool(publicObjectFactory factory, int maxSize) { + this.freeObjects = new ArrayList<>(maxSize); + this.factory = factory; + this.maxSize = maxSize; + } + + public interface publicObjectFactory { + T createObject(); + } + + protected final List freeObjects; + + protected final publicObjectFactory factory; + + private final int maxSize; + + /** + * 新建对象 + * + * @return object + */ + public T newObject() { + T object; + if (freeObjects.size() == 0) { + object = factory.createObject(); + } else + object = freeObjects.remove(freeObjects.size() - 1); + return object; + } + + /** + * 释放对象 + * + * @param object + */ + public void free(T object) { + if (freeObjects.size() < maxSize) + freeObjects.add(object); + } + + public T remove() { + return freeObjects.remove(freeObjects.size() - 1); + } + + public int size() { + return freeObjects.size(); + } + + /** + * 完全释放 + */ + public void clear() { + freeObjects.clear(); + } + + public static ObjectPool newInstance(Class clazz, publicObjectFactory factory, int maxSize) { + ObjectPool pool; + pool = new ObjectPool<>(factory, maxSize); + pool.poolName = clazz.getName(); + return pool; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/ObjectPoolGroup.java b/engine/src/main/java/com/lfk/justweengine/engine/ObjectPoolGroup.java new file mode 100644 index 0000000..c800eeb --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/ObjectPoolGroup.java @@ -0,0 +1,118 @@ +package com.lfk.justweengine.engine; + +import com.lfk.justweengine.drawable.Sprite.BaseSub; + +import java.util.HashMap; + +/** + * 对象池组 + * Created by liufengkai on 16/4/25. + */ +public class ObjectPoolGroup { + // ObjectPoolGroup + private final HashMap> freeObjectsHashMap; + // default factory method + private final ObjectPool.publicObjectFactory factory; + // default max size + private final int maxSize; + + /** + * 初始化对象池 + * + * @param factory 这里的工厂方法是BaseSub的默认生成方法, + * 如果你所需要的方法不存在则默认使用 + * @param maxSize 对象池的默认选项 + */ + public ObjectPoolGroup(ObjectPool.publicObjectFactory factory, int maxSize) { + this.maxSize = maxSize; + this.factory = factory; + this.freeObjectsHashMap = new HashMap<>(); + } + + /** + * 注册工厂方法 + * + * @param objectType 类 + * @param factory 工厂方法(注意泛型与上文一致) + * @param maxSize 最大数量 + * @param 泛型 + */ + public ObjectPool registerFactory(Class objectType, + ObjectPool.publicObjectFactory factory, + int maxSize) { + ObjectPool objectPool = ObjectPool.newInstance(objectType, factory, maxSize); + this.freeObjectsHashMap.put(objectType.getName(), objectPool); + return objectPool; + } + + public ObjectPool registerFactory(Class objectType, + ObjectPool.publicObjectFactory factory) { + ObjectPool objectPool = ObjectPool.newInstance(objectType, factory, maxSize); + this.freeObjectsHashMap.put(objectType.getName(), objectPool); + return objectPool; + } + + /** + * 注销工厂方法 + * + * @param objectType 类 + */ + public void unregisterFactory(Class objectType) { + this.freeObjectsHashMap.remove(objectType.getName()); + } + + /** + * 使用类型名进行生成调用 + * + * @param type BaseSub类型 + * @return 新建对象 + */ + public T newObject(Class type) { + T object; + if (freeObjectsHashMap.size() == 0) { + if (freeObjectsHashMap.containsKey(type.getName())) { + object = (getObjectPool(type)).newObject(); + } else { + object = (getPublicFactory(type)).createObject(); + } + } else + object = (getObjectPool(type)).remove(); + return object; + } + + /** + * 获取对象池 + * + * @param clazz 类 + * @param 泛型 + * @return 对应的对象池 + */ + @SuppressWarnings("unchecked") + public ObjectPool getObjectPool(Class clazz) { + return (ObjectPool) freeObjectsHashMap.get(clazz.getName()); + } + + @SuppressWarnings("unchecked") + public ObjectPool getObjectPool(String baseSub) { + return (ObjectPool) freeObjectsHashMap.get(baseSub); + } + + @SuppressWarnings("unchecked") + private ObjectPool.publicObjectFactory getPublicFactory(Class clazz) { + return (ObjectPool.publicObjectFactory) factory; + } + + /** + * baseSub 和 类有相同的名字 + * + * @param baseSub 物体 + * @param 泛型 + */ + public void free(T baseSub) { + getObjectPool(baseSub.s_name).free(baseSub); + } + + public void clear() { + freeObjectsHashMap.clear(); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/SimpleEngine.java b/engine/src/main/java/com/lfk/justweengine/engine/SimpleEngine.java new file mode 100644 index 0000000..c0dc703 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/SimpleEngine.java @@ -0,0 +1,806 @@ +package com.lfk.justweengine.engine; + +import android.content.pm.ActivityInfo; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.os.Bundle; +import android.renderscript.Float2; +import android.renderscript.Float3; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceView; +import android.view.View; +import android.view.Window; + +import com.lfk.justweengine.drawable.Button.BaseButton; +import com.lfk.justweengine.drawable.Sprite.BaseSub; +import com.lfk.justweengine.utils.logger.LogLevel; +import com.lfk.justweengine.utils.logger.Logger; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.concurrent.CopyOnWriteArrayList; + + +/** + * Engine nucleus + * + * @author liufengkai + * Created by liufengkai on 15/11/26. + */ +public abstract class SimpleEngine extends Engine implements Runnable, View.OnTouchListener { + private SurfaceView e_surfaceView; + private Canvas e_canvas; + // 主循环 + private Thread e_thread; + // 循环控制 + private boolean e_running, e_paused; + private int e_pauseCount; + private Paint e_paintDraw, e_paintFont; + private int e_numPoints; + private long e_preferredFrameRate, e_sleepTime; + private Typeface e_typeface; + private Point[] e_touchPoints; + private boolean e_touchModesAble; + // 多点触控数 + private int e_touchNum; + private int e_backgroundColor; + private boolean e_isFrameOpen; + private boolean isOpenDebug; + private boolean e_openAllDebug; + private TouchMode e_touch_Mode; + private CopyOnWriteArrayList e_sprite_group; + private CopyOnWriteArrayList e_sprite_recycle_group; + // for buttons + private HashMap e_button_group; + private boolean e_is_hit_button; + private BaseButton e_hit_button = null; + + + /** + * engine constructor + */ + public SimpleEngine() { + // init logger + Logger.init().logLevel(LogLevel.NONE); + Engine(); + } + + public SimpleEngine(boolean isOpenDebug) { + this.isOpenDebug = isOpenDebug; + if (!isOpenDebug) { + Logger.init().logLevel(LogLevel.NONE); + } else { + Logger.init(); + } + Engine(); + } + + private void Engine() { + e_surfaceView = null; + e_canvas = null; + e_thread = null; + e_running = false; + e_paused = false; + e_paintDraw = null; + e_pauseCount = 0; + e_paintFont = null; + e_numPoints = 0; + e_preferredFrameRate = 40; + e_sleepTime = 1000 / e_preferredFrameRate; + e_typeface = null; + e_touchModesAble = true; + e_touchNum = 5; + e_openAllDebug = false; + e_isFrameOpen = true; + e_touch_Mode = TouchMode.SINGLE; + e_backgroundColor = Color.BLACK; + e_sprite_group = new CopyOnWriteArrayList<>(); + e_sprite_recycle_group = new CopyOnWriteArrayList<>(); + e_button_group = new HashMap<>(); + e_is_hit_button = false; + e_hit_button = null; + Logger.d("Engine constructor"); + } + + public abstract void init(); + + public abstract void load(); + + public abstract void draw(); + + public abstract void update(); + + public abstract void touch(MotionEvent event); + + public abstract void collision(BaseSub baseSub); + + /** + * engine onCreate + * + * @param savedInstanceState + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Logger.d("engine onCreate start"); + // disable title bar + requestWindowFeature(Window.FEATURE_NO_TITLE); + // default landscape +// setScreenOrientation(ScreenMode.LANDSCAPE); + + // without it, screen will be black when init + this.getWindow().setFormat(PixelFormat.TRANSLUCENT); + + init(); + + // init surfaceView + e_surfaceView = new SurfaceView(this); + + // set content view + setContentView(e_surfaceView); + + // touch listener + e_surfaceView.setOnTouchListener(this); + + // init touch mode +// if (e_touchModesAble) { +// e_touchPoints = new Point[e_touchNum]; +// for (int i = 0; i < e_touchNum; i++) { +// e_touchPoints[i] = new Point(0, 0); +// } +// } + + // draw paint + e_paintDraw = new Paint(); + e_paintDraw.setColor(Color.WHITE); + // font paint + e_paintFont = new Paint(); + e_paintFont.setColor(Color.WHITE); + e_paintFont.setTextSize(24); + + load(); + + // init thread + e_running = true; + e_thread = new Thread(this); + e_thread.start(); + + Logger.d("engine onCreate end"); + } + + /** + * engine onResume + */ + @Override + protected void onResume() { + super.onResume(); + Logger.d("engine onResume"); + e_paused = false; + // need add... + } + + /** + * engine onPause + */ + @Override + protected void onPause() { + super.onPause(); + Logger.d("engine onPause"); + e_paused = true; + e_pauseCount++; + // need add... + } + + /** + * engine onTouch + * + * @param v + * @param event + * @return + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (e_touch_Mode) { + case SINGLE: + touch(event); + break; + case FULL: + stuffTouchPoints(event); + break; + case BUTTON: + findTouchButton(event); + break; + case SINGLE_BUTTON: + if (!findTouchButton(event)) + touch(event); + break; + } + return true; + } + + @Override + public void run() { + Logger.d("engine run start"); + GameTimer frameTimer = new GameTimer(); + int frameCount = 0; + int frameRate = 0; + long startTime; + long timeDiff; + + while (e_running) { + if (e_paused) continue; + + frameCount++; + startTime = frameTimer.getElapsed(); + + // frame rate + if (frameTimer.stopWatch(1000)) { + + frameRate = frameCount; + + frameCount = 0; + + // reset points + e_numPoints = 0; + } + + // update + update(); + + for (int i = 0; i < e_sprite_group.size(); i++) { + BaseSub A = e_sprite_group.get(i); + if (!A.getAlive()) continue; + + if (!A.isCollidable()) continue; + + if (A.isCollided()) continue; + + for (int j = 0; j < e_sprite_group.size(); j++) { + BaseSub B = e_sprite_group.get(j); + if (!B.getAlive()) continue; + + if (!B.isCollidable()) continue; + + if (B.isCollided()) continue; + + if (A == B) continue; + + if (A.getIdentifier() == + B.getIdentifier()) + continue; + + if (collisionCheck(A, B)) { + A.setCollided(true); + A.setOffender(B); + B.setCollided(true); + B.setOffender(A); + break; + } + } + } + + // lock canvas + if (beginDrawing()) { + e_canvas.drawColor(e_backgroundColor); + + for (String o : e_button_group.keySet()) { + BaseButton button = e_button_group.get(o); + button.animation(); + button.draw(); + } + // draw ahead of draw concrete sub + draw(); + + for (int k = 0; k < e_sprite_group.size(); k++) { + BaseSub baseSub = e_sprite_group.get(k); + if (baseSub.getAlive()) { + baseSub.animation(); + baseSub.draw(); + } + if (isOpenDebug && baseSub.isCollidable() && baseSub.isCollided()) { + drawDebugLine(baseSub.getBounds()); + } else if (e_openAllDebug) { + drawDebugLine(baseSub.getBounds()); + } + } + + if (e_isFrameOpen && isOpenDebug) { + int x = e_canvas.getWidth() - 150; + e_canvas.drawText("engine", x, 20, e_paintFont); + e_canvas.drawText(toString(frameRate) + "fps", x, 40, e_paintFont); + e_canvas.drawText("pauses:" + toString(e_pauseCount), x, 60, e_paintFont); + } + + // unlock the canvas + endDrawing(); + } + + // new collision + for (int l = 0; l < e_sprite_group.size(); l++) { + BaseSub baseSub = e_sprite_group.get(l); + if (!baseSub.getAlive()) { + e_sprite_recycle_group.add(baseSub); + e_sprite_group.remove(baseSub); + continue; + } + + if (baseSub.isCollidable()) { + if (baseSub.isCollided()) { + // Is it a valid object ? + if (baseSub.getOffender() != null) { + // collision + collision(baseSub); + // reset offender + baseSub.setOffender(null); + } + baseSub.setCollided(false); + } + } + + baseSub.setCollided(false); + } + + // lock frame + timeDiff = frameTimer.getElapsed() - startTime; + long updatePeriod = e_sleepTime - timeDiff; +// Logger.v("period", updatePeriod); + if (updatePeriod > 0) { + try { + Thread.sleep(updatePeriod); + } catch (InterruptedException e) { +// Logger.e("engine run start error:" + e); + } + } + } + Logger.d("engine run end"); + System.exit(RESULT_OK); + } + + /** + * begin draw + * + * @return + */ + private boolean beginDrawing() { + if (!e_surfaceView.getHolder().getSurface().isValid()) { + return false; + } + e_canvas = e_surfaceView.getHolder().lockCanvas(); + return true; + } + + /** + * end draw + */ + private void endDrawing() { + e_surfaceView.getHolder().unlockCanvasAndPost(e_canvas); + } + + /** + * open frame count + * + * @param e_isFrameOpen + */ + public void setIsFrameOpen(boolean e_isFrameOpen) { + this.e_isFrameOpen = e_isFrameOpen; + } + + /** + * background color + * + * @param e_backgroundColor + */ + public void setBackgroundColor(int e_backgroundColor) { + this.e_backgroundColor = e_backgroundColor; + } + + /** + * set touch number + * + * @param e_touchNum + */ + public void setTouchNum(int e_touchNum) { + this.e_touchNum = e_touchNum; + } + + /** + * set touch mode able + * + * @param e_touchModesAble + */ + public void setTouchModesAble(boolean e_touchModesAble) { + this.e_touchModesAble = e_touchModesAble; + } + + public enum ScreenMode { + LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), + PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + int value; + + ScreenMode(int mode) { + this.value = mode; + } + } + + /** + * set screenOrientation + * + * @param mode + */ + public void setScreenOrientation(ScreenMode mode) { + setRequestedOrientation(mode.value); + } + + /** + * shortcut method to duplicate existing Android methods + * + * @param msg + */ + public void fatalError(String msg) { + Logger.e("engine fatal error:" + msg); + System.exit(0); + } + + /** + * draw helper + */ + + /** + * draw text + * + * @param text + * @param x + * @param y + */ + public void drawText(String text, int x, int y) { + e_canvas.drawText(text, x, y, e_paintFont); + } + + /** + * engine helper + */ + + /** + * @return surface + */ + public SurfaceView getSurfaceView() { + return e_surfaceView; + } + + /** + * @return canvas + */ + public Canvas getCanvas() { + return e_canvas; + } + + /** + * set frame rete + * + * @param rate + */ + public void setFrameRate(int rate) { + e_preferredFrameRate = rate; + e_sleepTime = 1000 / e_preferredFrameRate; + } + + /** + * get touch puts + * + * @return + */ + public int getTouchPoints() { + return e_numPoints; + } + + /** + * get touch point + * + * @param n + * @return + */ + public Point getTouchPoint(int n) { + if (n < 0) { + Logger.e("error", "without point" + n); + n = 0; + } + if (n > e_touchNum) { + n = e_touchNum; + } + return e_touchPoints[n]; + } + + /** + * set paint color + * + * @param color + */ + public void setDrawColor(int color) { + e_paintDraw.setColor(color); + } + + /** + * set text color + * + * @param color + */ + public void setTextColor(int color) { + e_paintFont.setColor(color); + } + + /** + * set text size + * + * @param size + */ + public void setTextSize(int size) { + e_paintFont.setTextSize(size); + } + + public void setTextSize(float size) { + e_paintFont.setTextSize((int) size); + } + + public enum FontStyles { + NORMAL(Typeface.NORMAL), + BOLD(Typeface.BOLD), + ITALIC(Typeface.ITALIC), + BOLD_ITALIC(Typeface.BOLD_ITALIC),; + int value; + + FontStyles(int value) { + this.value = value; + } + } + + /** + * set type face + * + * @param style + */ + public void setFontStyle(FontStyles style) { + e_typeface = Typeface.create(Typeface.DEFAULT, style.value); + e_paintFont.setTypeface(e_typeface); + } + + public void setFontStyle(Typeface style) { + e_paintFont.setTypeface(style); + } + + /** + * double round + * + * @param value + * @return + */ + public double round(double value) { + return round(value, 2); + } + + private double round(double value, int precision) { + try { + BigDecimal bd = new BigDecimal(value); + BigDecimal rounded = bd.setScale(precision, BigDecimal.ROUND_HALF_UP); + return rounded.doubleValue(); + } catch (Exception e) { + Logger.e("engine", " round error:" + e); + } + Logger.e("engine", " round D:" + 0); + return 0; + } + + private boolean collisionCheck(BaseSub A, BaseSub B) { + return RectF.intersects(A.getBounds(), B.getBounds()); + } + + /** + * to string + * + * @param value + * @return + */ + public String toString(int value) { + return Integer.toString(value); + } + + public String toString(float value) { + return Float.toString(value); + } + + public String toString(double value) { + return Double.toString(value); + } + + public String toString(Float2 value) { + return "X:" + round(value.x) + "," + "Y:" + round(value.y); + } + + public String toString(Float3 value) { + return "X:" + round(value.x) + "," + "Y:" + round(value.y) + + "Z:" + round(value.z); + } + + public String toString(Rect value) { + RectF rectF = new RectF(value.left, value.top, value.right, value.bottom); + return toString(rectF); + } + + public String toString(RectF value) { + return "{" + round(value.left) + "," + + round(value.top) + "," + + round(value.right) + "," + + round(value.bottom) + "}"; + } + + /** + * add BaseSub to group + * + * @param sprite + */ + public void addToSpriteGroup(BaseSub sprite) { + e_sprite_group.add(sprite); + } + + /** + * remove from group + * + * @param sprite + */ + protected void removeFromSpriteGroup(BaseSub sprite) { + e_sprite_group.remove(sprite); + } + + protected void removeFromSpriteGroup(int index) { + e_sprite_group.remove(index); + } + + /** + * get size + * + * @return size + */ + protected int getSpriteGroupSize() { + return e_sprite_group.size(); + } + + protected int getRecycleGroupSize() { + return e_sprite_recycle_group.size(); + } + + protected void addToRecycleGroup(BaseSub baseSub) { + e_sprite_recycle_group.add(baseSub); + } + + protected void removeFromRecycleGroup(int index) { + e_sprite_recycle_group.remove(index); + } + + protected void removeFromRecycleGroup(BaseSub baseSub) { + e_sprite_recycle_group.remove(baseSub); + } + + protected boolean isRecycleGroupEmpty() { + return e_sprite_recycle_group.isEmpty(); + } + + protected BaseSub recycleSubFromGroup(int id) { + for (BaseSub baseSub : e_sprite_recycle_group) { + if (baseSub.getIdentifier() == id) { + return baseSub; + } + } + return null; + } + + protected int getTypeSizeFromRecycleGroup(int id) { + int num = 0; + for (BaseSub baseSub : e_sprite_recycle_group) { + if (baseSub.getIdentifier() == id) { + num++; + } + } + Log.e("num" + num, "id" + id); + return num; + } + + protected void addToButtonGroup(BaseButton button) { + e_button_group.put(button.getName(), button); + } + + protected void removeButtonFromGroup(String name) { + e_button_group.remove(name); + } + + private void stuffTouchPoints(MotionEvent event) { + e_numPoints = event.getPointerCount(); + if (e_numPoints > e_touchNum) { + e_numPoints = e_touchNum; + } + + for (int n = 0; n < e_numPoints; n++) { + Logger.v("engine", e_touchNum + ":" + e_numPoints); + e_touchPoints[n].x = (int) event.getX(n); + e_touchPoints[n].y = (int) event.getY(n); + } + } + + private boolean findTouchButton(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + for (String name : e_button_group.keySet()) { + BaseButton button = e_button_group.get(name); + if (button.getRect().contains((int) event.getX(), + (int) event.getY())) { + button.setNormal(false); + e_is_hit_button = true; + e_hit_button = button; + return true;//移入判断体,否则多个按钮会无法响应 + } +// return true; + } + break; + case MotionEvent.ACTION_UP: + if (e_hit_button != null && e_is_hit_button && + e_hit_button.getRect().contains((int) event.getX(), + (int) event.getY())) { + e_hit_button.setNormal(true); + e_hit_button.onClick(true); + resetHitButton(); + return true; + } else if (e_is_hit_button) { + if (e_hit_button != null) { + e_hit_button.setNormal(true); + resetHitButton(); + } + return true; + } + break; + } + return false; + } + + private void resetHitButton() { + e_is_hit_button = false; + e_hit_button = null; + } + + public void setTouchMode(TouchMode e_touch_Mode) { + this.e_touch_Mode = e_touch_Mode; + } + + public boolean isOpenDebug() { + return isOpenDebug; + } + + public void setOpenDebug(boolean openDebug) { + isOpenDebug = openDebug; + } + + /** + * 绘制debug模式下的边框 + * + * @param bound RectF轮廓 + */ + public void drawDebugLine(RectF bound) { + if (isOpenDebug()) { + e_paintDraw.setColor(Color.RED); + e_paintDraw.setStyle(Paint.Style.STROKE); + e_canvas.drawRect(bound, e_paintDraw); + } + } + + public boolean isOpenAllDebug() { + return e_openAllDebug; + } + + public void setOpenAllDebug(boolean e_openAllDebug) { + this.e_openAllDebug = e_openAllDebug; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/engine/TouchMode.java b/engine/src/main/java/com/lfk/justweengine/engine/TouchMode.java new file mode 100644 index 0000000..15fdf18 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/engine/TouchMode.java @@ -0,0 +1,25 @@ +package com.lfk.justweengine.engine; + +/** + * TouchMode + * + * @author liufengkai + * Created by liufengkai on 15/12/2. + */ +public enum TouchMode { + // Single touch + SINGLE(0), + // Single button + BUTTON(2), + // Touches + FULL(4), + // Single touch + button + SINGLE_BUTTON(6), + // distribute Touch Event In Layer + SINGLE_LAYER(8); + int mode; + + TouchMode(int type) { + this.mode = type; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/info/UIdefaultData.java b/engine/src/main/java/com/lfk/justweengine/info/UIdefaultData.java new file mode 100644 index 0000000..18a9c6d --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/info/UIdefaultData.java @@ -0,0 +1,41 @@ +package com.lfk.justweengine.info; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.Point; +import android.util.Log; + +/** + * UI 默认数据类 待修改 + * + * @author liufengkai + * Created by liufengkai on 15/11/27. + */ +public class UIdefaultData { + + private static Context context; + + public static void init(Context context) { + UIdefaultData.context = context; + scale = context.getResources().getDisplayMetrics().density; + screenWidth = context.getResources().getDisplayMetrics().widthPixels; + screenHeight = context.getResources().getDisplayMetrics().heightPixels; + center = new Point(screenWidth / 2, screenHeight / 2); + centerInHorizontalX = screenWidth / 2; + Log.e("h" + screenHeight, "w" + screenWidth); + } + + public static final int sprite_default_color_paint = Color.WHITE; + + public static int screenWidth; + + public static int screenHeight; + + public static int centerInHorizontalX; + + public static float scale; + + public static Point center; + + public static float defaultMusicVolume = 10; +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BlueToothServer.java b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BlueToothServer.java new file mode 100644 index 0000000..19f00f4 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BlueToothServer.java @@ -0,0 +1,277 @@ +package com.lfk.justweengine.utils.blueTooth; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.widget.Toast; + +import com.lfk.justweengine.R; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; + +/** + * Created by liufengkai on 16/1/20. + */ +public class BlueToothServer { + // Debugging + private static final String TAG = "BluetoothChat"; + private static final boolean D = true; + + // Message types sent from the BluetoothChatService Handler + public static final int MESSAGE_STATE_CHANGE = 1; + public static final int MESSAGE_READ = 2; + public static final int MESSAGE_WRITE = 3; + public static final int MESSAGE_DEVICE_NAME = 4; + public static final int MESSAGE_TOAST = 5; + + // Key names received from the BluetoothChatService Handler + public static final String DEVICE_NAME = "device_name"; + public static final String TOAST = "toast"; + + // Intent request codes + private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; + private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2; + private static final int REQUEST_ENABLE_BT = 3; + + // Name of the connected device + private String mConnectedDeviceName = null; + // Array adapter for the conversation thread + + private BluetoothChatService mChatService = null; + + private BluetoothAdapter mBluetoothAdapter = null; + + private Activity context; + + private CharSequence mBlueToothState = null; + + // msg handler + private BlueToothMsgHandler mHandler; + + private ArrayList mNewDeviceList; + + private OnMessageBack onMessageBack = null; + + public BlueToothServer(Activity context, OnMessageBack messageBack) { + this.context = context; + + this.onMessageBack = messageBack; + + this.mHandler = new BlueToothMsgHandler(); + // Get local Bluetooth adapter + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + + // If the adapter is null, then Bluetooth is not supported + if (mBluetoothAdapter == null) { + Toast.makeText(context, "Bluetooth is not available", Toast.LENGTH_LONG).show(); + } + } + + public void init() { + if (!mBluetoothAdapter.isEnabled()) { + Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + context.startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + // Otherwise, setup the chat session + } else { + if (mChatService == null) setupChat(); + } + + // Register for broadcasts when a device is discovered + IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); + context.registerReceiver(mReceiver, filter); + + // Register for broadcasts when discovery has finished + filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + context.registerReceiver(mReceiver, filter); + } + + public void unBindService() { + if (mChatService != null) mChatService.stop(); + + if (mBluetoothAdapter != null) { + mBluetoothAdapter.cancelDiscovery(); + } + + // Unregister broadcast listeners + context.unregisterReceiver(mReceiver); + } + + private void setupChat() { + Log.d(TAG, "setupChat()"); + + // Initialize the BluetoothChatService to perform bluetooth connections + mChatService = new BluetoothChatService(context, mHandler); + + this.mNewDeviceList = new ArrayList<>(); + } + + /** + * handler for message + */ + @SuppressLint("HandlerLeak") + private class BlueToothMsgHandler extends Handler { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case MESSAGE_STATE_CHANGE: + if (D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); + switch (msg.arg1) { + case BluetoothChatService.STATE_CONNECTED: + setStatus(context.getString(R.string.title_connected_to, mConnectedDeviceName)); + break; + case BluetoothChatService.STATE_CONNECTING: + setStatus(R.string.title_connecting); + break; + case BluetoothChatService.STATE_LISTEN: + case BluetoothChatService.STATE_NONE: + setStatus(R.string.title_not_connected); + break; + } + break; + case MESSAGE_WRITE: + byte[] writeBuf = (byte[]) msg.obj; + // construct a string from the buffer + onMessageBack.sendMessage(Arrays.toString(writeBuf)); + break; + case MESSAGE_READ: + byte[] readBuf = (byte[]) msg.obj; + // construct a string from the valid bytes in the buffer + onMessageBack.getMessage(Arrays.toString(readBuf)); + break; + case MESSAGE_DEVICE_NAME: + // save the connected device's name + mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); + Toast.makeText(context, "Connected to " + + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); + break; + case MESSAGE_TOAST: + Toast.makeText(context, msg.getData().getString(TOAST), + Toast.LENGTH_SHORT).show(); + break; + } + } + } + + + /** + * set BlueTooth state + * + * @param s + */ + private void setStatus(CharSequence s) { + this.mBlueToothState = s; + } + + private void setStatus(int res) { + this.mBlueToothState = context.getString(res); + } + + /** + * enable for discover by others' phone + */ + public void ensureDiscoverable() { + if (D) Log.d(TAG, "ensure discoverable"); + if (mBluetoothAdapter.getScanMode() != + BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { + Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); + discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); + context.startActivity(discoverableIntent); + } + } + + /** + * send message + * + * @param message + */ + public void sendMessage(String message) { + // Check that we're actually connected before trying anything + if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) { + Toast.makeText(context, R.string.not_connected, Toast.LENGTH_SHORT).show(); + return; + } + + // Check that there's actually something to send + if (message.length() > 0) { + // Get the message bytes and tell the BluetoothChatService to write + byte[] send = message.getBytes(); + mChatService.write(send); + } + } + + /** + * do discovery + */ + public void doDiscovery() { + if (D) Log.d(TAG, "doDiscovery()"); + // If we're already discovering, stop it + if (mBluetoothAdapter.isDiscovering()) { + mBluetoothAdapter.cancelDiscovery(); + } + + // Request discover from BluetoothAdapter + mBluetoothAdapter.startDiscovery(); + } + + // The BroadcastReceiver that listens for discovered devices and + // changes the title when discovery is finished + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + // When discovery finds a device + if (BluetoothDevice.ACTION_FOUND.equals(action)) { + // Get the BluetoothDevice object from the Intent + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + // If it's already paired, skip it, because it's been listed already + if (device.getBondState() != BluetoothDevice.BOND_BONDED) { + mNewDeviceList.add(device.getName() + "\n" + device.getAddress()); + } + // When discovery is finished, change the Activity title + } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { + if (mNewDeviceList.size() == 0) { + mNewDeviceList.clear(); + } + onMessageBack.getDevice(mNewDeviceList); + } + } + }; + + /** + * connect to a device + * + * @param address mac + * @param secure is secure? + */ + public void connectToDevice(String address, boolean secure) { + // Get the BluetoothDevice object + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + // Attempt to connect to the device + mChatService.connect(device, secure); + } + + public ArrayList getPairedDevices() { + ArrayList arrayList = new ArrayList<>(); + Set pairedDevices = mBluetoothAdapter.getBondedDevices(); + // If there are paired devices, add each one to the ArrayAdapter + if (pairedDevices.size() > 0) { + for (BluetoothDevice device : pairedDevices) { + arrayList.add(device.getName() + "\n" + device.getAddress()); + } + } else { + arrayList.clear(); + } + return arrayList; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BluetoothChatService.java b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BluetoothChatService.java new file mode 100755 index 0000000..2c3ade3 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/BluetoothChatService.java @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lfk.justweengine.utils.blueTooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothServerSocket; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.UUID; + +/** + * This class does all the work for setting up and managing Bluetooth + * connections with other devices. It has a thread that listens for + * incoming connections, a thread for connecting with a device, and a + * thread for performing data transmissions when connected. + */ +public class BluetoothChatService { + // Debugging + private static final String TAG = "BluetoothChatService"; + private static final boolean D = true; + + // Name for the SDP record when creating server socket + private static final String NAME_SECURE = "BluetoothChatSecure"; + private static final String NAME_INSECURE = "BluetoothChatInsecure"; + + // Unique UUID for this application + + private static final UUID MY_UUID_SECURE = + UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); + private static final UUID MY_UUID_INSECURE = + UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"); + + // Member fields + private final BluetoothAdapter mAdapter; + private final Handler mHandler; + private AcceptThread mSecureAcceptThread; + private AcceptThread mInsecureAcceptThread; + private ConnectThread mConnectThread; + private ConnectedThread mConnectedThread; + private int mState; + + // Constants that indicate the current connection state + public static final int STATE_NONE = 0; // we're doing nothing + public static final int STATE_LISTEN = 1; // now listening for incoming connections + public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection + public static final int STATE_CONNECTED = 3; // now connected to a remote device + + /** + * Constructor. Prepares a new BluetoothChat session. + * + * @param context The UI Activity Context + * @param handler A Handler to send messages back to the UI Activity + */ + public BluetoothChatService(Context context, Handler handler) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mState = STATE_NONE; + mHandler = handler; + } + + /** + * Set the current state of the chat connection + * + * @param state An integer defining the current connection state + */ + private synchronized void setState(int state) { + if (D) Log.d(TAG, "setState() " + mState + " -> " + state); + mState = state; + + // Give the new state to the Handler so the UI Activity can update + mHandler.obtainMessage(BlueToothServer.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); + } + + /** + * Return the current connection state. + */ + public synchronized int getState() { + return mState; + } + + /** + * Start the chat service. Specifically start AcceptThread to begin a + * session in listening (server) mode. Called by the Activity onResume() + */ + public synchronized void start() { + if (D) Log.d(TAG, "start"); + + // Cancel any thread attempting to make a connection + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + + // Cancel any thread currently running a connection + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + setState(STATE_LISTEN); + + // Start the thread to listen on a BluetoothServerSocket + if (mSecureAcceptThread == null) { + mSecureAcceptThread = new AcceptThread(true); + mSecureAcceptThread.start(); + } + if (mInsecureAcceptThread == null) { + mInsecureAcceptThread = new AcceptThread(false); + mInsecureAcceptThread.start(); + } + } + + /** + * Start the ConnectThread to initiate a connection to a remote device. + * + * @param device The BluetoothDevice to connect + * @param secure Socket Security type - Secure (true) , Insecure (false) + */ + public synchronized void connect(BluetoothDevice device, boolean secure) { + if (D) Log.d(TAG, "connect to: " + device); + + // Cancel any thread attempting to make a connection + if (mState == STATE_CONNECTING) { + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + } + + // Cancel any thread currently running a connection + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + // Start the thread to connect with the given device + mConnectThread = new ConnectThread(device, secure); + mConnectThread.start(); + setState(STATE_CONNECTING); + } + + /** + * Start the ConnectedThread to begin managing a Bluetooth connection + * + * @param socket The BluetoothSocket on which the connection was made + * @param device The BluetoothDevice that has been connected + */ + public synchronized void connected(BluetoothSocket socket, BluetoothDevice + device, final String socketType) { + if (D) Log.d(TAG, "connected, Socket Type:" + socketType); + + // Cancel the thread that completed the connection + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + + // Cancel any thread currently running a connection + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + // Cancel the accept thread because we only want to connect to one device + if (mSecureAcceptThread != null) { + mSecureAcceptThread.cancel(); + mSecureAcceptThread = null; + } + if (mInsecureAcceptThread != null) { + mInsecureAcceptThread.cancel(); + mInsecureAcceptThread = null; + } + + // Start the thread to manage the connection and perform transmissions + mConnectedThread = new ConnectedThread(socket, socketType); + mConnectedThread.start(); + + // Send the name of the connected device back to the UI Activity + Message msg = mHandler.obtainMessage(BlueToothServer.MESSAGE_DEVICE_NAME); + Bundle bundle = new Bundle(); + bundle.putString(BlueToothServer.DEVICE_NAME, device.getName()); + msg.setData(bundle); + mHandler.sendMessage(msg); + + setState(STATE_CONNECTED); + } + + /** + * Stop all threads + */ + public synchronized void stop() { + if (D) Log.d(TAG, "stop"); + + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + if (mSecureAcceptThread != null) { + mSecureAcceptThread.cancel(); + mSecureAcceptThread = null; + } + + if (mInsecureAcceptThread != null) { + mInsecureAcceptThread.cancel(); + mInsecureAcceptThread = null; + } + setState(STATE_NONE); + } + + /** + * Write to the ConnectedThread in an unsynchronized manner + * + * @param out The bytes to write + * @see ConnectedThread#write(byte[]) + */ + public void write(byte[] out) { + // Create temporary object + ConnectedThread r; + // Synchronize a copy of the ConnectedThread + synchronized (this) { + if (mState != STATE_CONNECTED) return; + r = mConnectedThread; + } + // Perform the write unsynchronized + r.write(out); + } + + /** + * Indicate that the connection attempt failed and notify the UI Activity. + */ + private void connectionFailed() { + // Send a failure message back to the Activity + Message msg = mHandler.obtainMessage(BlueToothServer.MESSAGE_TOAST); + Bundle bundle = new Bundle(); + bundle.putString(BlueToothServer.TOAST, "Unable to connect device"); + msg.setData(bundle); + mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); + } + + /** + * Indicate that the connection was lost and notify the UI Activity. + */ + private void connectionLost() { + // Send a failure message back to the Activity + Message msg = mHandler.obtainMessage(BlueToothServer.MESSAGE_TOAST); + Bundle bundle = new Bundle(); + bundle.putString(BlueToothServer.TOAST, "Device connection was lost"); + msg.setData(bundle); + mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); + } + + /** + * This thread runs while listening for incoming connections. It behaves + * like a server-side client. It runs until a connection is accepted + * (or until cancelled). + */ + private class AcceptThread extends Thread { + // The local server socket + private final BluetoothServerSocket mmServerSocket; + private String mSocketType; + + public AcceptThread(boolean secure) { + BluetoothServerSocket tmp = null; + mSocketType = secure ? "Secure" : "Insecure"; + + // Create a new listening server socket + try { + if (secure) { + tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, + MY_UUID_SECURE); + } else { + tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord( + NAME_INSECURE, MY_UUID_INSECURE); + } + } catch (IOException e) { + Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e); + } + mmServerSocket = tmp; + } + + public void run() { + if (D) Log.d(TAG, "Socket Type: " + mSocketType + + "BEGIN mAcceptThread" + this); + setName("AcceptThread" + mSocketType); + + BluetoothSocket socket = null; + + // Listen to the server socket if we're not connected + while (mState != STATE_CONNECTED) { + try { + // This is a blocking call and will only return on a + // successful connection or an exception + socket = mmServerSocket.accept(); + } catch (IOException e) { + Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e); + break; + } + + // If a connection was accepted + if (socket != null) { + synchronized (BluetoothChatService.this) { + switch (mState) { + case STATE_LISTEN: + case STATE_CONNECTING: + // Situation normal. Start the connected thread. + connected(socket, socket.getRemoteDevice(), + mSocketType); + break; + case STATE_NONE: + case STATE_CONNECTED: + // Either not ready or already connected. Terminate new socket. + try { + socket.close(); + } catch (IOException e) { + Log.e(TAG, "Could not close unwanted socket", e); + } + break; + } + } + } + } + if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType); + + } + + public void cancel() { + if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this); + try { + mmServerSocket.close(); + } catch (IOException e) { + Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e); + } + } + } + + + /** + * This thread runs while attempting to make an outgoing connection + * with a device. It runs straight through; the connection either + * succeeds or fails. + */ + private class ConnectThread extends Thread { + private final BluetoothSocket mmSocket; + private final BluetoothDevice mmDevice; + private String mSocketType; + + public ConnectThread(BluetoothDevice device, boolean secure) { + mmDevice = device; + BluetoothSocket tmp = null; + mSocketType = secure ? "Secure" : "Insecure"; + + // Get a BluetoothSocket for a connection with the + // given BluetoothDevice + try { + if (secure) { + tmp = device.createRfcommSocketToServiceRecord( + MY_UUID_SECURE); + } else { + tmp = device.createInsecureRfcommSocketToServiceRecord( + MY_UUID_INSECURE); + } + } catch (IOException e) { + Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); + } + mmSocket = tmp; + } + + public void run() { + Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); + setName("ConnectThread" + mSocketType); + + // Always cancel discovery because it will slow down a connection + mAdapter.cancelDiscovery(); + + // Make a connection to the BluetoothSocket + try { + // This is a blocking call and will only return on a + // successful connection or an exception + mmSocket.connect(); + } catch (IOException e) { + // Close the socket + try { + mmSocket.close(); + } catch (IOException e2) { + Log.e(TAG, "unable to close() " + mSocketType + + " socket during connection failure", e2); + } + connectionFailed(); + return; + } + + // Reset the ConnectThread because we're done + synchronized (BluetoothChatService.this) { + mConnectThread = null; + } + + // Start the connected thread + connected(mmSocket, mmDevice, mSocketType); + } + + public void cancel() { + try { + mmSocket.close(); + } catch (IOException e) { + Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); + } + } + } + + /** + * This thread runs during a connection with a remote device. + * It handles all incoming and outgoing transmissions. + */ + private class ConnectedThread extends Thread { + private final BluetoothSocket mmSocket; + private final InputStream mmInStream; + private final OutputStream mmOutStream; + + public ConnectedThread(BluetoothSocket socket, String socketType) { + Log.d(TAG, "create ConnectedThread: " + socketType); + mmSocket = socket; + InputStream tmpIn = null; + OutputStream tmpOut = null; + + // Get the BluetoothSocket input and output streams + try { + tmpIn = socket.getInputStream(); + tmpOut = socket.getOutputStream(); + } catch (IOException e) { + Log.e(TAG, "temp sockets not created", e); + } + + mmInStream = tmpIn; + mmOutStream = tmpOut; + } + + public void run() { + Log.i(TAG, "BEGIN mConnectedThread"); + byte[] buffer = new byte[50000]; + int bytes; + + // Keep listening to the InputStream while connected + while (true) { + try { + // Read from the InputStream + bytes = mmInStream.read(buffer); + + // Send the obtained bytes to the UI Activity + mHandler.obtainMessage(BlueToothServer.MESSAGE_READ, bytes, -1, buffer) + .sendToTarget(); + } catch (IOException e) { + Log.e(TAG, "disconnected", e); + connectionLost(); + // Start the service over to restart listening mode + BluetoothChatService.this.start(); + break; + } + } + } + + /** + * Write to the connected OutStream. + * + * @param buffer The bytes to write + */ + public void write(byte[] buffer) { + try { + mmOutStream.write(buffer); + + // Share the sent message back to the UI Activity + mHandler.obtainMessage(BlueToothServer.MESSAGE_WRITE, -1, -1, buffer) + .sendToTarget(); + } catch (IOException e) { + Log.e(TAG, "Exception during write", e); + } + } + + public void cancel() { + try { + mmSocket.close(); + } catch (IOException e) { + Log.e(TAG, "close() of connect socket failed", e); + } + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/OnMessageBack.java b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/OnMessageBack.java new file mode 100644 index 0000000..715adc5 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/blueTooth/OnMessageBack.java @@ -0,0 +1,14 @@ +package com.lfk.justweengine.utils.blueTooth; + +import java.util.ArrayList; + +/** + * Created by liufengkai on 16/1/20. + */ +public interface OnMessageBack { + void getMessage(String msg); + + void sendMessage(String msg); + + void getDevice(ArrayList msg); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/AfterCrashListener.java b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/AfterCrashListener.java new file mode 100644 index 0000000..f83856b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/AfterCrashListener.java @@ -0,0 +1,12 @@ +package com.lfk.justweengine.utils.crashHandler; + +/** + * AfterCrashListener + * save info after crash + * + * @author liufengkai + * Created by liufengkai on 16/1/17. + */ +public interface AfterCrashListener { + void AfterCrash(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandler.java b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandler.java new file mode 100644 index 0000000..47fa841 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandler.java @@ -0,0 +1,243 @@ +package com.lfk.justweengine.utils.crashHandler; + +import android.annotation.SuppressLint; +import android.app.AlarmManager; +import android.app.Application; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * CrashHandler + * Solve thread crash + * + * @author liufengkai + * Created by liufengkai on 16/1/16. + */ +public class CrashHandler implements Thread.UncaughtExceptionHandler { + private static final String TAG = "CrashHandler"; + + private Application context; + + private HashMap info; + + private DateFormat formatter; + + private static CrashHandler instance; + + private Thread.UncaughtExceptionHandler uncaughtExceptionHandler; + + // Restart activity + private Class Activity = null; + + private String ActivityName = null; + + private ArrayList listener; + + /** + * get CrashHandler Instance + * + * @return CrashHandler + */ + public static CrashHandler getInstance() { + if (instance == null) { + instance = new CrashHandler(); + } + return instance; + } + + public void setRestartActivity(Class activity) { + this.Activity = activity; + } + + public void setActivityName(String activityName) { + ActivityName = activityName; + } + + /** + * init + * + * @param context + */ + @SuppressLint("SimpleDateFormat") + public void init(Application context) { + this.context = context; + uncaughtExceptionHandler = + Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(this); + + info = new HashMap<>(); + listener = new ArrayList<>(); + formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + CrashHandlerDefault.init(); + } + + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + handleException(ex); + uncaughtExceptionHandler + .uncaughtException(thread, ex); + } + + + private boolean handleException(Throwable throwable) { + if (throwable == null) + return false; + if (listener != null) { + for (int i = 0; i < listener.size(); i++) { + listener.get(i).AfterCrash(); + } + } + collectDeviceInfo(context); + writeCrashInfoToFile(throwable); + if (Activity != null) + restart(Activity); + else if (ActivityName != null) { + restart(ActivityName); + } + return true; + } + + /** + * Collect Device Info + * + * @param ctx context + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), + PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" + : pi.versionName; + String versionCode = pi.versionCode + ""; + info.put("versionName", versionName); + info.put("versionCode", versionCode); + info.put("crashTime", formatter.format(new Date())); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occurred when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + info.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + " : " + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occurred when collect crash info", e); + } + } + } + + /** + * Write crash info To File + * + * @param ex throwable message + */ + private void writeCrashInfoToFile(Throwable ex) { + StringBuilder sb = new StringBuilder(); + sb.append("crash log by JustWeEngine \n"); + for (Map.Entry entry : info.entrySet()) { + sb.append(entry.getKey()) + .append("---------->") + .append(entry.getValue()) + .append("\n"); + } + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + writeLog(sb.toString()); + } + + /** + * write log in file + * + * @param log log + */ + private void writeLog(String log) { + File file = new File(CrashHandlerDefault.Log_Default_Path + + "/" + formatter.format(new Date()) + ".log"); + try { + FileOutputStream fileOutputStream = new FileOutputStream(file); + byte[] bytes = log.getBytes(); + fileOutputStream.write(bytes); + fileOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * restart Activity + * + * @param activity classZ + */ + private void restart(Class activity) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } + Intent intent = new Intent(context.getApplicationContext(), activity); + restart(intent); + } + + + private void restart(String className) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } + Intent intent = new Intent(); + intent.setClassName(context.getApplicationContext(), className); + restart(intent); + } + + private void restart(Intent intent) { + PendingIntent restartIntent = PendingIntent.getActivity( + context.getApplicationContext(), 0, intent, + Intent.FLAG_ACTIVITY_CLEAR_TASK); + + // 使用PendingIntent重启 + AlarmManager mgr = + (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, + restartIntent); + } + + public void addCrashListener(AfterCrashListener listener) { + this.listener.add(listener); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandlerDefault.java b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandlerDefault.java new file mode 100644 index 0000000..c0d7009 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/crashHandler/CrashHandlerDefault.java @@ -0,0 +1,20 @@ +package com.lfk.justweengine.utils.crashHandler; + +import android.os.Environment; + +import java.io.File; + +/** + * Created by liufengkai on 16/1/16. + */ +public class CrashHandlerDefault { + public static final String Log_Default_Path = + Environment.getExternalStorageDirectory() + "/CrashLog"; + + public static void init() { + File file = new File(CrashHandlerDefault.Log_Default_Path); + if (!file.exists()) { + file.mkdirs(); + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/database/DataBase.java b/engine/src/main/java/com/lfk/justweengine/utils/database/DataBase.java new file mode 100644 index 0000000..370e52e --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/database/DataBase.java @@ -0,0 +1,367 @@ +package com.lfk.justweengine.utils.database; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by liufengkai on 16/3/18. + */ +public class DataBase { + // 数据库相关信息类 + private DataBaseMessage mDBMessage; + // 数据库新建 + private DataBaseHelper mDBHelper; + // 实体数据库 + private SQLiteDatabase mDB; + + public DataBase() { + } + + public DataBase(DataBaseMessage mDBMessage) { + this.mDBMessage = mDBMessage; + } + + // 入口方法 + public static DataBase initAndOpen(String name, Class clazz) { + DataBase dataBase = new DataBase(); + dataBase.mDBMessage = dataBase.getCreateSQL(clazz); + dataBase.mDBMessage.SQL_NAME = name; + return dataBase; + } + + public boolean open(Context context) { + try { + mDBHelper = new DataBaseHelper(context, mDBMessage.SQL_NAME, 1); + mDB = mDBHelper.getWritableDatabase(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + return true; + } + + public void close() { + mDB.close(); + mDBHelper.close(); + } + + /** + * 尺寸 + * + * @return 数据库存储条目 + */ + public int size() { + int size = 0; + Cursor mCursor = mDB.query(mDBMessage.TABLE_NAME, new String[]{mDBMessage.PRIMARY_KEY}, null, null, null, null, + null, null); + if (mCursor != null) { + size = mCursor.getCount(); + mCursor.close(); + } + return size; + } + + /** + * 插入条目 + * + * @param node + * @return + */ + public boolean insert(Node node) { + Log.e("node", node.toString()); + ContentValues values = new ContentValues(); + for (int i = 0; i < mDBMessage.LABEL_NAME.size(); i++) { + if (node.arrayList.get(i) instanceof Integer) + values.put(mDBMessage.LABEL_NAME.get(i), (Integer) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof String) + values.put(mDBMessage.LABEL_NAME.get(i), (String) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Float) + values.put(mDBMessage.LABEL_NAME.get(i), (Float) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Long) + values.put(mDBMessage.LABEL_NAME.get(i), (Long) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Boolean) + values.put(mDBMessage.LABEL_NAME.get(i), (Boolean) node.arrayList.get(i)); + } + node.key = mDB.insert(mDBMessage.TABLE_NAME, null, values); + if (node.key == -1) { + Log.e("DATABASE", "db insert fail!"); + return false; + } + return true; + } + + /** + * 更新 + * + * @param node + * @return + */ + public boolean update(Node node) { + if (node.key == -1) { + return false; + } + ContentValues values = new ContentValues(); + for (int i = 0; i < mDBMessage.LABEL_NAME.size(); i++) { + if (node.arrayList.get(i) instanceof Integer) + values.put(mDBMessage.LABEL_NAME.get(i), (Integer) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof String) + values.put(mDBMessage.LABEL_NAME.get(i), (String) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Float) + values.put(mDBMessage.LABEL_NAME.get(i), (Float) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Long) + values.put(mDBMessage.LABEL_NAME.get(i), (Long) node.arrayList.get(i)); + else if (node.arrayList.get(i) instanceof Boolean) + values.put(mDBMessage.LABEL_NAME.get(i), (Boolean) node.arrayList.get(i)); + } + String condition = mDBMessage.PRIMARY_KEY + "=" + "\'" + node.key + "\'"; + return update(values, condition, null); + } + + protected boolean update(ContentValues values, String whereClause, String[] whereArgs) { + int rows = mDB.update(mDBMessage.TABLE_NAME, values, whereClause, whereArgs); + if (rows <= 0) { + Log.d("DATABASE", "db update fail!"); + return false; + } + return true; + } + + /** + * 删除指定条目 + * + * @param position + * @return + */ + public boolean delete(int position) { + long key = getKey(position, null); + if (key == -1) { + return false; + } + String condition = mDBMessage.PRIMARY_KEY + "=" + "\'" + key + "\'"; + return delete(condition, null); + } + + protected boolean delete(String whereClause, String[] whereArgs) { + int rows = mDB.delete(mDBMessage.TABLE_NAME, whereClause, whereArgs); + if (rows <= 0) { + Log.e("DATABASE", "db delete fail!"); + return false; + } + return true; + } + + public boolean clear() { + return delete(null, null); + } + + /** + * 一坨get方法 + * + * @param position + * @return + */ + public List get(int position) { + return get(position, null); + } + + public List get(long id) { + String condition = mDBMessage.PRIMARY_KEY + "=" + "\'" + id + "\'"; + List notes = query(condition); + if (notes.isEmpty()) { + return null; + } + return notes; + } + + public List get(int position, String condition) { + Cursor cursor = mDB.query(mDBMessage.TABLE_NAME, null, condition, null, null, null, + mDBMessage.PRIMARY_KEY + " DESC", null); + List notes = extract(position, cursor); + if (notes.isEmpty()) { + return null; + } + return notes; + } + + + public List query() { + Cursor cursor = mDB.query(mDBMessage.TABLE_NAME, null, null, null, null, null, + mDBMessage.PRIMARY_KEY + " DESC", null); + return extract(0, cursor); + } + + public List query(String condition) { + Cursor cursor = mDB.query(mDBMessage.TABLE_NAME, null, condition, null, null, null, + mDBMessage.PRIMARY_KEY + " DESC", null); + return extract(0, cursor); + } + + public List query(int offset, int limit) { + return query(null, offset, limit); + } + + public List query(String condition, int offset, int limit) { + Cursor cursor = mDB.query(mDBMessage.TABLE_NAME, null, condition, null, null, null, + mDBMessage.PRIMARY_KEY + " DESC", offset + "," + limit); + return extract(0, cursor); + } + + /** + * 从某个位置进行查询 + * + * @param offset + * @param cursor + * @return + */ + protected List extract(int offset, Cursor cursor) { + + List notes = new ArrayList<>(); + if (cursor == null || cursor.getCount() <= offset) { + return notes; + } + + cursor.moveToFirst(); + cursor.moveToPosition(offset); + + do { + Node note = new Node(); + note.key = cursor.getLong(cursor.getColumnIndex(mDBMessage.PRIMARY_KEY)); + for (int i = 0; i < mDBMessage.LABEL_NAME.size(); i++) { + note.arrayList.add(cursor.getColumnIndex(mDBMessage.LABEL_NAME.get(i))); + } + notes.add(note); + } while (cursor.moveToNext()); + + cursor.close(); + + return notes; + } + + /** + * 获取存储键值 + * + * @param position 位置 + * @param condition 信息 + * @return + */ + protected long getKey(int position, String condition) { + long key = -1; + Cursor cursor = mDB.query(true, mDBMessage.TABLE_NAME, new String[]{mDBMessage.PRIMARY_KEY}, condition, null, null, null, + mDBMessage.PRIMARY_KEY + " DESC", null); + if (cursor != null && cursor.getCount() > 0) { + cursor.moveToPosition(position); + key = cursor.getLong(cursor.getColumnIndex(mDBMessage.PRIMARY_KEY)); + cursor.close(); + } + return key; + } + + private class DataBaseHelper extends SQLiteOpenHelper { + + public DataBaseHelper(Context context, String name, int version) { + super(context, name, null, version); + } + + public DataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { + super(context, name, factory, version); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(mDBMessage.CREATE_SQL); + Log.d("create", mDBMessage.CREATE_SQL); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + mDBMessage.TABLE_NAME); + onCreate(db); + } + } + + + /** + * SQL辅助信息 + */ + public class DataBaseMessage { + String SQL_NAME; + // 创建 + String CREATE_SQL; + // 表名 + String TABLE_NAME; + // 主键 + String PRIMARY_KEY; + // 存放 + ArrayList LABEL_NAME; + + public DataBaseMessage() { + LABEL_NAME = new ArrayList<>(); + } + } + + /** + * 反射方法 + * 通过注释类产生SQL语句 + * + * @param clazz + * @return + */ + public DataBaseMessage getCreateSQL(Class clazz) { + DataBaseMessage msg = new DataBaseMessage(); + + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE "); + + if (clazz.isAnnotationPresent(TableName.class)) { + TableName t = clazz.getAnnotation(TableName.class); + if (t.ifNotExist()) + builder.append(" ").append("IF NOT EXISTS "); + builder.append(t.tableName()); + // table name + msg.TABLE_NAME = t.tableName(); + } + + builder.append(" ("); + + Field[] fields = clazz.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].isAnnotationPresent(LabelName.class)) { + + LabelName f = fields[i].getAnnotation(LabelName.class); + + builder.append(f.columnName()); + builder.append(" ").append(f.type()); + msg.LABEL_NAME.add(f.columnName()); + + if (f.generatedId()) { + builder.append(" ").append("PRIMARY KEY"); + msg.PRIMARY_KEY = f.columnName(); + + if (f.autoincrement()) { + builder.append(" ").append("AUTOINCREMENT"); + msg.LABEL_NAME.remove(msg.LABEL_NAME.size() - 1); + } + } + + builder.append(","); + } + } + + builder.delete(builder.length() - 1, builder.length()); + + builder.append(") "); + + msg.CREATE_SQL = builder.toString(); + + return msg; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/database/LabelName.java b/engine/src/main/java/com/lfk/justweengine/utils/database/LabelName.java new file mode 100644 index 0000000..25a8c9b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/database/LabelName.java @@ -0,0 +1,23 @@ +package com.lfk.justweengine.utils.database; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by liufengkai on 16/3/18. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface LabelName { + String columnName() default "label"; + + boolean generatedId() default false; + + boolean autoincrement() default false; + + enum Type {NULL, BLOB, INTEGER, REAL, TEXT} + + Type type() default Type.NULL; +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/database/Node.java b/engine/src/main/java/com/lfk/justweengine/utils/database/Node.java new file mode 100644 index 0000000..635a839 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/database/Node.java @@ -0,0 +1,27 @@ +package com.lfk.justweengine.utils.database; + +import java.util.ArrayList; + +/** + * Created by liufengkai on 16/3/18. + */ +public class Node { + public ArrayList arrayList; + + public long key; + + public Node(Object... obj) { + arrayList = new ArrayList<>(); + for (int i = 0; i < obj.length; i++) { + arrayList.add(obj[i]); + } + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < arrayList.size(); i++) { + builder.append(arrayList.get(i).toString()); + } + return builder.toString(); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/database/TableName.java b/engine/src/main/java/com/lfk/justweengine/utils/database/TableName.java new file mode 100644 index 0000000..9376323 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/database/TableName.java @@ -0,0 +1,20 @@ +package com.lfk.justweengine.utils.database; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by liufengkai on 16/3/18. + */ + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TableName { + String tableName() default "table"; + + boolean ifNotExist() default false; +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/database/User.java b/engine/src/main/java/com/lfk/justweengine/utils/database/User.java new file mode 100644 index 0000000..e0b34a7 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/database/User.java @@ -0,0 +1,39 @@ +package com.lfk.justweengine.utils.database; + +/** + * Demo for DataBase + * + * @author liufengkai + * Created by liufengkai on 16/3/18. + */ +@TableName(tableName = "lfkdsk", ifNotExist = true) +public class User extends Node { + + @LabelName(autoincrement = true, type = LabelName.Type.INTEGER, columnName = "name", generatedId = true) + private int name; + + @LabelName(type = LabelName.Type.TEXT, columnName = "user_name") + private String user_name; + + public User(int name, String user_name) { + super(name, user_name); + this.name = name; + this.user_name = user_name; + } + + public int getName() { + return name; + } + + public void setName(int name) { + this.name = name; + } + + public String getUser_name() { + return user_name; + } + + public void setUser_name(String user_name) { + this.user_name = user_name; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/io/FileIO.java b/engine/src/main/java/com/lfk/justweengine/utils/io/FileIO.java new file mode 100644 index 0000000..2c5337c --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/io/FileIO.java @@ -0,0 +1,20 @@ +package com.lfk.justweengine.utils.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * FileIO + * get File from asset / File + * + * @author liufengkai + * Created by liufengkai on 16/1/17. + */ +public interface FileIO { + InputStream readAsset(String name) throws IOException; + + InputStream readFile(String name) throws IOException; + + OutputStream writeFile(String name) throws IOException; +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/io/GameIO.java b/engine/src/main/java/com/lfk/justweengine/utils/io/GameIO.java new file mode 100644 index 0000000..74a33a8 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/io/GameIO.java @@ -0,0 +1,47 @@ +package com.lfk.justweengine.utils.io; + +import android.content.Context; +import android.content.res.AssetManager; +import android.os.Environment; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * GameIO + * Read File + * + * @author liufengkai + * Created by liufengkai on 16/1/17. + */ +public class GameIO implements FileIO { + private Context context; + private AssetManager manager; + private String externalPath; + + public GameIO(Context context) { + this.context = context; + this.manager = context.getAssets(); + this.externalPath = Environment.getExternalStorageDirectory() + .getAbsolutePath() + File.separator; + } + + @Override + public InputStream readAsset(String name) throws IOException { + return manager.open(name); + } + + @Override + public InputStream readFile(String name) throws IOException { + return new FileInputStream(externalPath + name); + } + + @Override + public OutputStream writeFile(String name) throws IOException { + return new FileOutputStream(externalPath + name); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/AndroidLogTool.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/AndroidLogTool.java new file mode 100755 index 0000000..e38b1e1 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/AndroidLogTool.java @@ -0,0 +1,35 @@ +package com.lfk.justweengine.utils.logger; + +import android.util.Log; + +public class AndroidLogTool implements LogTool { + @Override + public void d(String tag, String message) { + Log.d(tag, message); + } + + @Override + public void e(String tag, String message) { + Log.e(tag, message); + } + + @Override + public void w(String tag, String message) { + Log.w(tag, message); + } + + @Override + public void i(String tag, String message) { + Log.i(tag, message); + } + + @Override + public void v(String tag, String message) { + Log.v(tag, message); + } + + @Override + public void wtf(String tag, String message) { + Log.wtf(tag, message); + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/LogCat.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogCat.java new file mode 100644 index 0000000..7943eaf --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogCat.java @@ -0,0 +1,96 @@ +package com.lfk.justweengine.utils.logger; + +import android.text.TextUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Jack Tony + * @date 2015/12/4 + */ +public class LogCat { + + private static final List DEFAULT_COMMAND = new ArrayList<>(); + + static { + DEFAULT_COMMAND.add("logcat"); + } + + private List commandLine; + + private static LogCat mInstance = null; + + public static LogCat getInstance() { + if (mInstance == null) { + mInstance = new LogCat(); + } + return mInstance; + } + + private LogCat() { + commandLine = new ArrayList<>(DEFAULT_COMMAND); + } + + public LogCat options(Options options) { + commandLine.add(LogParser.parse(options)); + return this; + } + + public LogCat recentLines(int lineSize) { + commandLine.add("-t"); + commandLine.add(String.valueOf(lineSize)); + return this; + } + + /** + * @param tag log的tag + */ + public LogCat filter(String tag) { + return filter(tag, LogLevel.VERBOSE); // 默认显示所有信息 + } + + /** + * logcat Tag:I *:S + * + * @param tag log的tag 不输入代表仅仅通过lev做筛选 + * @param lev log的级别 + */ + public LogCat filter(String tag, LogLevel lev) { + String levStr = LogParser.parse(lev); + + if (!TextUtils.isEmpty(tag)) { + commandLine.add(tag.trim() + ":" + levStr); + // Log.d("ddd", "filter: " + commandLine.get(commandLine.size()-1)); + commandLine.add("*:S"); + } else { + commandLine.add("*:" + levStr); + } + return this; + } + + public LogCat withTime() { + commandLine.add("-v"); + commandLine.add("time"); + return this; + } + + public LogCat clear() { + commandLine.add("-c"); + return this; + } + + public Process commit() { + Process exec = null; + try { + exec = Runtime.getRuntime().exec(commandLine.toArray(new String[this.commandLine.size()])); + } catch (IOException e) { + e.printStackTrace(); + } finally { + commandLine = new ArrayList<>(DEFAULT_COMMAND); + } + return exec; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/LogLevel.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogLevel.java new file mode 100755 index 0000000..adc5b60 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogLevel.java @@ -0,0 +1,17 @@ +package com.lfk.justweengine.utils.logger; + +public enum LogLevel { + + /** + * Prints all logs + */ + FULL, + + /** + * No log will be printed + */ + NONE, + + VERBOSE, DEBUG, INFO, WARN, ERROR, FATAL, ASSERT + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/LogParser.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogParser.java new file mode 100644 index 0000000..2ca66d1 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogParser.java @@ -0,0 +1,104 @@ +package com.lfk.justweengine.utils.logger; + +/** + * @author Kale + * @date 2016/3/25 + */ +public class LogParser { + + private static final String SILENT = "-s"; // Set default filter to SILENT. Like '*:s' + + private static final String FILE = "-f"; // Log to FILE. Default to stdout + + private static final String BYTES = "-r"; // Rotate log every bytes(k). (16 if unspecified). Requires -f + + private static final String COUNT = "-n"; // Sets max number of rotated logs to , default 4 + + private static final String FORMAT = "-v"; // Sets the log print format, where is one of: brief process tag thread raw time + + private static final String CLEAR = "-c"; // clear (flush) the entire log and e // thread time + + private static final String DUMP = "-d"; // dump the log and then exit (don't block) // 不会引起线程阻塞 + + /////////////////////////////////////////////////////////////////////////// + // lev + /////////////////////////////////////////////////////////////////////////// + + public static final String VERBOSE = "V"; // Verbose (明细) + + public static final String DEBUG = "D"; // Debug (调试) + + public static final String INFO = "I"; // Info (信息) + + public static final String WARN = "W"; // Warn (警告) + + public static final String ERROR = "E"; // Error (错误) + + private static final String FATAL = "F"; // Fatal (严重错误) + + private static final String ASSERT = "S"; // Silent(Super all output) (最高的优先级, 前所未有的错误); + + public static String parse(Options options) { + switch (options) { + case SILENT: + return SILENT; + case FILE: + return FILE; + case BYTES: + return BYTES; + case COUNT: + return COUNT; + case FORMAT: + return FORMAT; + case CLEAR: + return CLEAR; + case DUMP: + //return DUMP; + default: + return DUMP; + } + } + + public static String parse(LogLevel level) { + switch (level) { + case VERBOSE: + return VERBOSE; + case DEBUG: + return DEBUG; + case INFO: + return INFO; + case WARN: + return WARN; + case ERROR: + return ERROR; + case FATAL: + return FATAL; + case ASSERT: + //return ASSERT; + default: + return ASSERT; + } + } + + public static LogLevel parseLev(String level) { + switch (level) { + case VERBOSE: + return LogLevel.VERBOSE; + case DEBUG: + return LogLevel.DEBUG; + case INFO: + return LogLevel.INFO; + case WARN: + return LogLevel.WARN; + case ERROR: + return LogLevel.ERROR; + case FATAL: + return LogLevel.FATAL; + case ASSERT: + return LogLevel.ASSERT; + default: + return LogLevel.ASSERT; + } + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/LogTool.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogTool.java new file mode 100755 index 0000000..61f3b78 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/LogTool.java @@ -0,0 +1,15 @@ +package com.lfk.justweengine.utils.logger; + +public interface LogTool { + void d(String tag, String message); + + void e(String tag, String message); + + void w(String tag, String message); + + void i(String tag, String message); + + void v(String tag, String message); + + void wtf(String tag, String message); +} \ No newline at end of file diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/Logger.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/Logger.java new file mode 100755 index 0000000..dcf7cee --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/Logger.java @@ -0,0 +1,100 @@ +package com.lfk.justweengine.utils.logger; + + +/** + * Logger is a wrapper of {@link android.util.Log} + * But more pretty, simple and powerful + */ +public final class Logger { + private static final String DEFAULT_TAG = "PRETTYLOGGER"; + + private static Printer printer = new LoggerPrinter(); + + //no instance + private Logger() { + + } + + /** + * It is used to get the settings object in order to change settings + * + * @return the settings object + */ + public static Settings init() { + return init(DEFAULT_TAG); + } + + /** + * It is used to change the tag + * + * @param tag is the given string which will be used in Logger as TAG + */ + public static Settings init(String tag) { + printer = new LoggerPrinter(); + return printer.init(tag); + } + + public static void clear() { + printer.clear(); + printer = null; + } + + public static Printer t(String tag) { + return printer.t(tag, printer.getSettings().getMethodCount()); + } + + public static Printer t(int methodCount) { + return printer.t(null, methodCount); + } + + public static Printer t(String tag, int methodCount) { + return printer.t(tag, methodCount); + } + + public static void d(String message, Object... args) { + printer.d(message, args); + } + + public static void e(String message, Object... args) { + printer.e(null, message, args); + } + + public static void e(Throwable throwable, String message, Object... args) { + printer.e(throwable, message, args); + } + + public static void i(String message, Object... args) { + printer.i(message, args); + } + + public static void v(String message, Object... args) { + printer.v(message, args); + } + + public static void w(String message, Object... args) { + printer.w(message, args); + } + + public static void wtf(String message, Object... args) { + printer.wtf(message, args); + } + + /** + * Formats the json content and print it + * + * @param json the json content + */ + public static void json(String json) { + printer.json(json); + } + + /** + * Formats the json content and print it + * + * @param xml the xml content + */ + public static void xml(String xml) { + printer.xml(xml); + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/LoggerPrinter.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/LoggerPrinter.java new file mode 100755 index 0000000..f5b8ac1 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/LoggerPrinter.java @@ -0,0 +1,389 @@ +package com.lfk.justweengine.utils.logger; + +import android.text.TextUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +/** + * Logger is a wrapper for logging utils + * But more pretty, simple and powerful + */ +final class LoggerPrinter implements Printer { + + private static final int DEBUG = 3; + private static final int ERROR = 6; + private static final int ASSERT = 7; + private static final int INFO = 4; + private static final int VERBOSE = 2; + private static final int WARN = 5; + + /** + * Android's max limit for a log entry is ~4076 bytes, + * so 4000 bytes is used as chunk size since default charset + * is UTF-8 + */ + private static final int CHUNK_SIZE = 4000; + + /** + * It is used for json pretty print + */ + private static final int JSON_INDENT = 4; + + /** + * The minimum stack trace index, starts at this class after two native calls. + */ + private static final int MIN_STACK_OFFSET = 3; + + /** + * Drawing toolbox + */ + private static final char TOP_LEFT_CORNER = '╔'; + private static final char BOTTOM_LEFT_CORNER = '╚'; + private static final char MIDDLE_CORNER = '╟'; + private static final char HORIZONTAL_DOUBLE_LINE = '║'; + private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════"; + private static final String SINGLE_DIVIDER = "────────────────────────────────────────────"; + private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; + private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; + private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER; + + /** + * tag is used for the Log, the name is a little different + * in order to differentiate the logs easily with the filter + */ + private String tag; + + /** + * Localize single tag and method count for each thread + */ + private final ThreadLocal localTag = new ThreadLocal<>(); + private final ThreadLocal localMethodCount = new ThreadLocal<>(); + + /** + * It is used to determine log settings such as method count, thread info visibility + */ + private Settings settings; + + /** + * It is used to change the tag + * + * @param tag is the given string which will be used in Logger + */ + @Override + public Settings init(String tag) { + if (tag == null) { + throw new NullPointerException("tag may not be null"); + } + if (tag.trim().length() == 0) { + throw new IllegalStateException("tag may not be empty"); + } + this.tag = tag; + this.settings = new Settings(); + return settings; + } + + @Override + public Settings getSettings() { + return settings; + } + + @Override + public Printer t(String tag, int methodCount) { + if (tag != null) { + localTag.set(tag); + } + localMethodCount.set(methodCount); + return this; + } + + @Override + public void d(String message, Object... args) { + log(DEBUG, message, args); + } + + @Override + public void e(String message, Object... args) { + e(null, message, args); + } + + @Override + public void e(Throwable throwable, String message, Object... args) { + if (throwable != null && message != null) { + message += " : " + throwable.toString(); + } + if (throwable != null && message == null) { + message = throwable.toString(); + } + if (message == null) { + message = "No message/exception is set"; + } + log(ERROR, message, args); + } + + @Override + public void w(String message, Object... args) { + log(WARN, message, args); + } + + @Override + public void i(String message, Object... args) { + log(INFO, message, args); + } + + @Override + public void v(String message, Object... args) { + log(VERBOSE, message, args); + } + + @Override + public void wtf(String message, Object... args) { + log(ASSERT, message, args); + } + + /** + * Formats the json content and print it + * + * @param json the json content + */ + @Override + public void json(String json) { + if (TextUtils.isEmpty(json)) { + d("Empty/Null json content"); + return; + } + try { + if (json.startsWith("{")) { + JSONObject jsonObject = new JSONObject(json); + String message = jsonObject.toString(JSON_INDENT); + d(message); + return; + } + if (json.startsWith("[")) { + JSONArray jsonArray = new JSONArray(json); + String message = jsonArray.toString(JSON_INDENT); + d(message); + } + } catch (JSONException e) { + e(e.getCause().getMessage() + "\n" + json); + } + } + + /** + * Formats the json content and print it + * + * @param xml the xml content + */ + @Override + public void xml(String xml) { + if (TextUtils.isEmpty(xml)) { + d("Empty/Null xml content"); + return; + } + try { + Source xmlInput = new StreamSource(new StringReader(xml)); + StreamResult xmlOutput = new StreamResult(new StringWriter()); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + transformer.transform(xmlInput, xmlOutput); + d(xmlOutput.getWriter().toString().replaceFirst(">", ">\n")); + } catch (TransformerException e) { + e(e.getCause().getMessage() + "\n" + xml); + } + } + + @Override + public void clear() { + settings = null; + } + + /** + * This method is synchronized in order to avoid messy of logs' order. + */ + private synchronized void log(int logType, String msg, Object... args) { + if (settings.getLogLevel() == LogLevel.NONE) { + return; + } + String tag = getTag(); + String message = createMessage(msg, args); + int methodCount = getMethodCount(); + + logTopBorder(logType, tag); + logHeaderContent(logType, tag, methodCount); + + //get bytes of message with system's default charset (which is UTF-8 for Android) + byte[] bytes = message.getBytes(); + int length = bytes.length; + if (length <= CHUNK_SIZE) { + if (methodCount > 0) { + logDivider(logType, tag); + } + logContent(logType, tag, message); + logBottomBorder(logType, tag); + return; + } + if (methodCount > 0) { + logDivider(logType, tag); + } + for (int i = 0; i < length; i += CHUNK_SIZE) { + int count = Math.min(length - i, CHUNK_SIZE); + //create a new String with system's default charset (which is UTF-8 for Android) + logContent(logType, tag, new String(bytes, i, count)); + } + logBottomBorder(logType, tag); + } + + private void logTopBorder(int logType, String tag) { + logChunk(logType, tag, TOP_BORDER); + } + + private void logHeaderContent(int logType, String tag, int methodCount) { + StackTraceElement[] trace = Thread.currentThread().getStackTrace(); + if (settings.isShowThreadInfo()) { + logChunk(logType, tag, HORIZONTAL_DOUBLE_LINE + " Thread: " + Thread.currentThread().getName()); + logDivider(logType, tag); + } + String level = ""; + + int stackOffset = getStackOffset(trace) + settings.getMethodOffset(); + + //corresponding method count with the current stack may exceeds the stack trace. Trims the count + if (methodCount + stackOffset > trace.length) { + methodCount = trace.length - stackOffset - 1; + } + + for (int i = methodCount; i > 0; i--) { + int stackIndex = i + stackOffset; + if (stackIndex >= trace.length) { + continue; + } + StringBuilder builder = new StringBuilder(); + builder.append("║ ") + .append(level) + .append(getSimpleClassName(trace[stackIndex].getClassName())) + .append(".") + .append(trace[stackIndex].getMethodName()) + .append(" ") + .append(" (") + .append(trace[stackIndex].getFileName()) + .append(":") + .append(trace[stackIndex].getLineNumber()) + .append(")"); + level += " "; + logChunk(logType, tag, builder.toString()); + } + } + + private void logBottomBorder(int logType, String tag) { + logChunk(logType, tag, BOTTOM_BORDER); + } + + private void logDivider(int logType, String tag) { + logChunk(logType, tag, MIDDLE_BORDER); + } + + private void logContent(int logType, String tag, String chunk) { + String[] lines = chunk.split(System.getProperty("line.separator")); + for (String line : lines) { + logChunk(logType, tag, HORIZONTAL_DOUBLE_LINE + " " + line); + } + } + + private void logChunk(int logType, String tag, String chunk) { + String finalTag = formatTag(tag); + switch (logType) { + case ERROR: + settings.getLogTool().e(finalTag, chunk); + break; + case INFO: + settings.getLogTool().i(finalTag, chunk); + break; + case VERBOSE: + settings.getLogTool().v(finalTag, chunk); + break; + case WARN: + settings.getLogTool().w(finalTag, chunk); + break; + case ASSERT: + settings.getLogTool().wtf(finalTag, chunk); + break; + case DEBUG: + // Fall through, log debug by default + default: + settings.getLogTool().d(finalTag, chunk); + break; + } + } + + private String getSimpleClassName(String name) { + int lastIndex = name.lastIndexOf("."); + return name.substring(lastIndex + 1); + } + + private String formatTag(String tag) { + if (!TextUtils.isEmpty(tag) && !TextUtils.equals(this.tag, tag)) { + return this.tag + "-" + tag; + } + return this.tag; + } + + /** + * @return the appropriate tag based on local or global + */ + private String getTag() { + String tag = localTag.get(); + if (tag != null) { + localTag.remove(); + return tag; + } + return this.tag; + } + + private String createMessage(String message, Object... args) { + return args.length == 0 ? message : String.format(message, args); + } + + private int getMethodCount() { + Integer count = localMethodCount.get(); + int result = settings.getMethodCount(); + if (count != null) { + localMethodCount.remove(); + result = count; + } + if (result < 0) { + throw new IllegalStateException("methodCount cannot be negative"); + } + return result; + } + + /** + * Determines the starting index of the stack trace, after method calls made by this class. + * + * @param trace the stack trace + * @return the stack offset + */ + private int getStackOffset(StackTraceElement[] trace) { + for (int i = MIN_STACK_OFFSET; i < trace.length; i++) { + StackTraceElement e = trace[i]; + String name = e.getClassName(); + if (!name.equals(LoggerPrinter.class.getName()) && !name.equals(Logger.class.getName())) { + return --i; + } + } + return -1; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/Options.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/Options.java new file mode 100644 index 0000000..8a95a59 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/Options.java @@ -0,0 +1,9 @@ +package com.lfk.justweengine.utils.logger; + +/** + * @author Kale + * @date 2016/3/25 + */ +public enum Options { + SILENT, FILE, BYTES, COUNT, FORMAT, CLEAR, DUMP +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/Printer.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/Printer.java new file mode 100755 index 0000000..369dd40 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/Printer.java @@ -0,0 +1,30 @@ +package com.lfk.justweengine.utils.logger; + +public interface Printer { + + Printer t(String tag, int methodCount); + + Settings init(String tag); + + Settings getSettings(); + + void d(String message, Object... args); + + void e(String message, Object... args); + + void e(Throwable throwable, String message, Object... args); + + void w(String message, Object... args); + + void i(String message, Object... args); + + void v(String message, Object... args); + + void wtf(String message, Object... args); + + void json(String json); + + void xml(String xml); + + void clear(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/logger/Settings.java b/engine/src/main/java/com/lfk/justweengine/utils/logger/Settings.java new file mode 100755 index 0000000..b1da5e1 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/logger/Settings.java @@ -0,0 +1,89 @@ +package com.lfk.justweengine.utils.logger; + +public final class Settings { + + private int methodCount = 2; + private boolean showThreadInfo = true; + private int methodOffset = 0; + private LogTool logTool; + + /** + * Determines how logs will printed + */ + private LogLevel logLevel = LogLevel.FULL; + + public Settings hideThreadInfo() { + showThreadInfo = false; + return this; + } + + /** + * Use {@link #methodCount} + */ + @Deprecated + public Settings setMethodCount(int methodCount) { + return methodCount(methodCount); + } + + public Settings methodCount(int methodCount) { + if (methodCount < 0) { + methodCount = 0; + } + this.methodCount = methodCount; + return this; + } + + /** + * Use {@link #logLevel} + */ + @Deprecated + public Settings setLogLevel(LogLevel logLevel) { + return logLevel(logLevel); + } + + public Settings logLevel(LogLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Use {@link #methodOffset} + */ + @Deprecated + public Settings setMethodOffset(int offset) { + return methodOffset(offset); + } + + public Settings methodOffset(int offset) { + this.methodOffset = offset; + return this; + } + + public Settings logTool(LogTool logTool) { + this.logTool = logTool; + return this; + } + + public int getMethodCount() { + return methodCount; + } + + public boolean isShowThreadInfo() { + return showThreadInfo; + } + + public LogLevel getLogLevel() { + return logLevel; + } + + public int getMethodOffset() { + return methodOffset; + } + + public LogTool getLogTool() { + if (logTool == null) { + logTool = new AndroidLogTool(); + } + return logTool; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/music/Music.java b/engine/src/main/java/com/lfk/justweengine/utils/music/Music.java new file mode 100644 index 0000000..2877187 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/music/Music.java @@ -0,0 +1,28 @@ +package com.lfk.justweengine.utils.music; + +/** + * music interface + * + * @author liufengkai + * Created by liufengkai on 16/2/5. + */ +public interface Music { + void play(); + + void stop(); + + void pause(); + + void setLooping(boolean isLooping); + + void setVolume(float volume); + + float getVolume(); + + boolean isPlaying(); + + boolean isLooping(); + + void dispose(); + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/music/MusicPlayer.java b/engine/src/main/java/com/lfk/justweengine/utils/music/MusicPlayer.java new file mode 100644 index 0000000..65a6cab --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/music/MusicPlayer.java @@ -0,0 +1,126 @@ +package com.lfk.justweengine.utils.music; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.MediaPlayer; + +import java.io.IOException; + +/** + * MusicPlayer + * + * @author liufengkai + * Created by liufengkai on 16/2/5. + */ +public class MusicPlayer implements Music, MediaPlayer.OnCompletionListener { + private MediaPlayer player; + // 准备好? + private boolean isPrepared; + // 是否循环 + private boolean isLooping; + // 音量 + private float volume; + + public MusicPlayer(Context context, String fileName) { + player = new MediaPlayer(); + // init + initMusicPlayer(); + try { + // get file descriptor + AssetFileDescriptor descriptor = context.getAssets().openFd(fileName); + // setData + player.setDataSource(descriptor.getFileDescriptor(), + descriptor.getStartOffset(), + descriptor.getLength()); + player.prepare(); + isPrepared = true; + player.setOnCompletionListener(this); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("Couldn't load music"); + } + } + + private void initMusicPlayer() { + volume = 10; + isPrepared = false; + isLooping = false; + } + + @Override + public void play() { + if (player.isPlaying()) + return; + + try { + synchronized (this) { + if (isPrepared) { + player.prepare(); + } + player.start(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + + @Override + public void stop() { + player.stop(); + synchronized (this) { + isPrepared = false; + } + } + + @Override + public void pause() { + if (player.isPlaying()) + player.pause(); + } + + @Override + public void setLooping(boolean isLooping) { + this.isLooping = isLooping; + if (player != null) + player.setLooping(isLooping); + } + + @Override + public void setVolume(float volume) { + this.volume = volume; + + if (player != null) + player.setVolume(volume, volume); + } + + @Override + public float getVolume() { + return volume; + } + + @Override + public boolean isPlaying() { + return player.isPlaying(); + } + + @Override + public boolean isLooping() { + return isLooping; + } + + @Override + public void dispose() { + if (player.isPlaying()) { + player.stop(); + } + player.release(); + } + + @Override + public void onCompletion(MediaPlayer mp) { + synchronized (this) { + isPrepared = false; + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/music/SoundManager.java b/engine/src/main/java/com/lfk/justweengine/utils/music/SoundManager.java new file mode 100644 index 0000000..49bb302 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/music/SoundManager.java @@ -0,0 +1,140 @@ +package com.lfk.justweengine.utils.music; + +import android.content.res.AssetManager; +import android.media.AudioManager; +import android.media.SoundPool; + +import com.lfk.justweengine.engine.Engine; +import com.lfk.justweengine.info.UIdefaultData; +import com.lfk.justweengine.utils.logger.Logger; + +import java.io.IOException; +import java.util.HashMap; + +/** + * SoundManager sound manger + * + * @author liufengkai + * Created by liufengkai on 16/2/5. + */ +public class SoundManager { + private AssetManager assetManager; + // sound pool + private SoundPool soundPool; + + // musicName musicID + private HashMap musicMap; + + public SoundManager(Engine engine, int size) { + engine.setVolumeControlStream(AudioManager.STREAM_MUSIC); + // init + this.assetManager = engine.getAssets(); + this.soundPool = new SoundPool(size, AudioManager.STREAM_MUSIC, 0); + this.musicMap = new HashMap<>(); + } + + public void addSound(String musicName) { + try { + musicMap.put(musicName, soundPool.load(assetManager.openFd(musicName), 0)); + } catch (IOException e) { + e.printStackTrace(); + Logger.e("Couldn't found music"); + } + } + + public void removeSound(String musicName) { + if (musicMap.containsKey(musicName)) { + soundPool.unload(musicMap.get(musicName)); + musicMap.remove(musicName); + } else { + Logger.e("Couldn't found music"); + } + } + + /** + * play sound + * + * @param musicName name in assets + * @param volume sound's volume + */ + public void play(String musicName, float volume) { + if (musicMap.containsKey(musicName)) { + soundPool.play(musicMap.get(musicName), volume, volume, 0, 0, 1); + } + } + + /** + * play sound with defaultMusicVolume + * + * @param musicName name in assets + */ + public void play(String musicName) { + if (musicMap.containsKey(musicName)) { + soundPool.play(musicMap.get(musicName), + UIdefaultData.defaultMusicVolume, + UIdefaultData.defaultMusicVolume, + 0, 0, 1); + } + } + + /** + * play sound with musicID in SoundPool + * + * @param musicID musicID in SoundPool + */ + public void play(int musicID) { + if (musicMap.containsValue(musicID)) { + soundPool.play(musicID, + UIdefaultData.defaultMusicVolume, + UIdefaultData.defaultMusicVolume, + 0, 0, 1); + } + } + + /** + * play sound with musicID in SoundPool + * + * @param musicID musicID in SoundPool + * @param volume volume + */ + public void play(int musicID, float volume) { + if (musicMap.containsValue(musicID)) { + soundPool.play(musicID, + volume, + volume, + 0, 0, 1); + } + } + + /** + * Is music in map? + * + * @param soundName soundName + * @return Is music in map? + */ + public boolean containSound(String soundName) { + return musicMap.containsKey(soundName); + } + + /** + * Is music in map? + * + * @param soundID soundID + * @return Is music in map? + */ + public boolean containSoundID(int soundID) { + return musicMap.containsValue(soundID); + } + + /** + * get Music from Name + * + * @param soundName soundName + * @return soundID + */ + public int getSoundID(String soundName) { + return musicMap.get(soundName); + } + + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/music/SoundPlayer.java b/engine/src/main/java/com/lfk/justweengine/utils/music/SoundPlayer.java new file mode 100644 index 0000000..03e8e3f --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/music/SoundPlayer.java @@ -0,0 +1,150 @@ +package com.lfk.justweengine.utils.music; + +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +/** + * SoundPlayer + * + * @author liufengkai + * Created by liufengkai on 16/2/5. + */ +public class SoundPlayer { + // get SoundManager from + private SoundManager manager; + // musicID list + private ArrayList musicList; + // Sound clock + private SoundClock soundClock; + + private boolean isPlaying; + + private long delay; + + private int numTicks; + + /** + * Sound player + * + * @param manager a soundManager have a soundPool. + * @param delay The number of milliseconds to delay between ticks. + * @param numTicks Starts the clock running for a specific number of ticks. + */ + public SoundPlayer(SoundManager manager, + long delay, + int numTicks) { + this.manager = manager; + this.musicList = new ArrayList<>(); + this.isPlaying = false; + this.delay = delay; + this.numTicks = numTicks; + this.soundClock = new SoundClock(delay, numTicks); + } + + /** + * add a sound to player + * + * @param soundName soundName + */ + public void addSound(String soundName) { + if (manager.containSound(soundName)) { + musicList.add(soundName); + } + } + + /** + * remove a sound from player + * + * @param soundName soundName + */ + public void removeSound(String soundName) { + if (manager.containSound(soundName)) { + musicList.remove(soundName); + } + } + + public void play() { + if (!musicList.isEmpty() && + !isPlaying) { + if (soundClock.getTickNumber() == 0) { +// soundClock.restart(); + soundClock = null; + soundClock = new SoundClock(delay, numTicks); + soundClock.start(); + } else + soundClock.start(); + isPlaying = true; + } + } + + private class SoundClock extends TimerTask { + // timer + private Timer timer; + // Starts the clock running for a specific number of ticks. + private int tickLeft; + + private int tickLeftSave; + + // The number of milliseconds to delay between ticks. + private long delay; + + public SoundClock(long delay, int numTicks) { + init(); + this.tickLeft = numTicks; + this.tickLeftSave = numTicks; + this.delay = delay; + } + + private void init() { + this.timer = new Timer(); + } + + // tick 心跳 + private void tick() { + if (tickLeft == 0) + this.stop(); + else { + for (int i = 0; i < musicList.size(); i++) { + manager.play(musicList.get(i)); + } + if (tickLeft > 0) + tickLeft--; + } + } + + @Override + public void run() { + tick(); + } + + public void start(int numTicks) { + this.tickLeft = numTicks; + this.timer.schedule(this, 0, delay); + } + + public void start() { + if (tickLeft != 0) + start(tickLeft); + } + + public void stop() { + this.cancel(); + this.timer.cancel(); + isPlaying = false; + } + + public int getTickNumber() { + return tickLeft; + } + + public void restart() { + this.tickLeft = tickLeftSave; + this.timer.purge(); + this.timer = null; + init(); + start(); + } + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/quad/Collisionable.java b/engine/src/main/java/com/lfk/justweengine/utils/quad/Collisionable.java new file mode 100644 index 0000000..83e81b9 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/quad/Collisionable.java @@ -0,0 +1,8 @@ +package com.lfk.justweengine.utils.quad; + +/** + * Created by liufengkai on 16/9/18. + */ +public interface Collisionable { + boolean isCollision(T object); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/quad/QuadTree.java b/engine/src/main/java/com/lfk/justweengine/utils/quad/QuadTree.java new file mode 100644 index 0000000..3dcf49b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/quad/QuadTree.java @@ -0,0 +1,164 @@ +package com.lfk.justweengine.utils.quad; + +import android.graphics.RectF; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by liufengkai on 16/9/18. + */ +public class QuadTree { + private int MAX_OBJECTS = 10; + + private int MAX_LEVELS = 5; + + private int level; + + private List objects; + + private RectF bounds; + + private QuadTree[] nodes; + + public QuadTree(int level, RectF bounds) { + this.level = level; + this.objects = new ArrayList<>(); + this.bounds = bounds; + this.nodes = new QuadTree[4]; + } + + /** + * clear all sub nodes + */ + public void clear() { + objects.clear(); + + for (int i = 0; i < nodes.length; i++) { + if (nodes[i] != null) { + nodes[i].clear(); + nodes[i] = null; + } + } + } + + /** + * split nodes + */ + private void split() { + // width & height + int subWidth = (int) (bounds.width() / 2); + int subHeight = (int) (bounds.height() / 2); + // x & y + int x = (int) bounds.left; + int y = (int) bounds.top; + // split to four nodes + nodes[0] = new QuadTree(level + 1, new RectF(x + subWidth, y, subWidth, subHeight)); + nodes[1] = new QuadTree(level + 1, new RectF(x, y, subWidth, subHeight)); + nodes[2] = new QuadTree(level + 1, new RectF(x, y + subHeight, subWidth, subHeight)); + nodes[3] = new QuadTree(level + 1, new RectF(x + subWidth, y + subHeight, subWidth, subHeight)); + + } + + /** + * 获取rect 所在的 index + * + * @param rectF 传入对象所在的矩形 + * @return index 使用类别区分所在象限 + */ + private int getIndex(RectF rectF) { + int index = -1; + double verticalMidpoint = bounds.left + (bounds.width() / 2); + double horizontalMidpoint = bounds.top + (bounds.height() / 2); + + // contain top + boolean topQuadrant = rectF.top < horizontalMidpoint + && rectF.top + rectF.height() < horizontalMidpoint; + // contain bottom + boolean bottomQuadrant = rectF.top > horizontalMidpoint; + + // contain left + if (rectF.left < verticalMidpoint + && rectF.left + rectF.width() < verticalMidpoint) { + if (topQuadrant) { + index = 1; + } else if (bottomQuadrant) { + index = 2; + } + // contain right + } else if (rectF.left > verticalMidpoint) { + if (topQuadrant) { + index = 0; + } else if (bottomQuadrant) { + index = 3; + } + } + + return index; + } + + /** + * insert object to tree + * + * @param rectF object + */ + public void insert(RectF rectF) { + if (nodes[0] != null) { + int index = getIndex(rectF); + + if (index != -1) { + nodes[index].insert(rectF); + + return; + } + } + + objects.add(rectF); + + if (objects.size() > MAX_OBJECTS + && level < MAX_OBJECTS) { + // don't have subNodes + // split node + if (nodes[0] == null) { + split(); + } + + int i = 0; + while (i < objects.size()) { + + int index = getIndex(objects.get(i)); + + if (index != -1) { + + nodes[index].insert(objects.remove(i)); + + } else { + + // don't in subNode save to parent node. + // eq: object on line + i++; + + } + } + } + } + + /** + * return all the object collision with the object + * + * @param returnObjects return list + * @param rectF object + * @return list of collision + */ + public List> retrieve(List> returnObjects, RectF rectF) { + int index = getIndex(rectF); + + if (index != -1 && nodes[0] != null) { + nodes[index].retrieve(returnObjects, rectF); + } + + returnObjects.add(objects); + return returnObjects; + } +} + diff --git a/engine/src/main/java/com/lfk/justweengine/utils/script/Exp.java b/engine/src/main/java/com/lfk/justweengine/utils/script/Exp.java new file mode 100644 index 0000000..ba33592 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/script/Exp.java @@ -0,0 +1,286 @@ +package com.lfk.justweengine.utils.script; + +import java.util.HashMap; +import java.util.Random; + +public class Exp { + + private static final int MAX_LENGTH = 128; + + public static final int STACK_VARIABLE = 11; + + public static final int STACK_RAND = -1; + + public static final int STACK_NUM = 0; + + public static final int PLUS = 1; + + public static final int MINUS = 2; + + public static final int MULTIPLE = 3; + + public static final int DIVISION = 4; + + public static final int MODULO = 5; + + private HashMap computes = new HashMap<>(); + + private char[] expChr; + + /** + * 是否包含运算符号 + * + * @param exp + * @return + */ + public boolean exp(String exp) { + return exp.contains("+") || exp.contains("-") + || exp.contains("*") || exp.contains("/") + || exp.contains("%"); + } + + public float parse(Object v) { + return parse(v.toString()); + } + + public float parse(String v) { + if (!exp(v)) { + // 不含有直接翻译 + if (NumberUtils.isNan(v)) { + return Float.parseFloat(v); + } else { + throw new RuntimeException(v + " not parse !"); + } + } + // 含有进行分析 + return eval(v); + } + + private void evalFloatValue(Compute compute, int stIdx, int lgt, + float sign) { + if (expChr[stIdx] == '$') { + String label = new String(expChr, stIdx + 1, lgt - 1); + if (label.equals("rand")) { + compute.push(0, STACK_RAND); + } else { + int idx; + try { + idx = Integer.parseInt(label) - 1; + } catch (NumberFormatException e) { + compute.push(0, STACK_NUM); + return; + } + compute.push(0, STACK_VARIABLE + idx); + } + } else { + try { + compute.push(Float.parseFloat(new String(expChr, stIdx, lgt)) + * sign, STACK_NUM); + } catch (NumberFormatException e) { + compute.push(0, STACK_NUM); + } + } + } + + private void evalExp(Compute compute, int stIdx, int edIdx) { + int op[] = new int[]{-1, -1}; + while (expChr[stIdx] == '(' && expChr[edIdx - 1] == ')') { + stIdx++; + edIdx--; + } + for (int i = edIdx - 1; i >= stIdx; i--) { + char c = expChr[i]; + if (c == ')') { + do { + i--; + } while (expChr[i] != '('); + } else if (op[0] < 0 && (c == '*' || c == '/' || c == '%')) { + op[0] = i; + } else if (c == '+' || c == '-') { + op[1] = i; + break; + } + } + if (op[1] < 0) { + if (op[0] < 0) { + evalFloatValue(compute, stIdx, edIdx - stIdx, 1); + } else { + switch (expChr[op[0]]) { + case '*': + evalExp(compute, stIdx, op[0]); + evalExp(compute, op[0] + 1, edIdx); + compute.setOperator(MULTIPLE); + break; + case '/': + evalExp(compute, stIdx, op[0]); + evalExp(compute, op[0] + 1, edIdx); + compute.setOperator(DIVISION); + break; + case '%': + evalExp(compute, stIdx, op[0]); + evalExp(compute, op[0] + 1, edIdx); + compute.setOperator(MODULO); + break; + } + } + } else { + if (op[1] == stIdx) { + switch (expChr[op[1]]) { + case '-': + evalFloatValue(compute, stIdx + 1, edIdx - stIdx - 1, + -1); + break; + case '+': + evalFloatValue(compute, stIdx + 1, edIdx - stIdx - 1, 1); + break; + } + } else { + switch (expChr[op[1]]) { + case '+': + evalExp(compute, stIdx, op[1]); + evalExp(compute, op[1] + 1, edIdx); + compute.setOperator(PLUS); + break; + case '-': + evalExp(compute, stIdx, op[1]); + evalExp(compute, op[1] + 1, edIdx); + compute.setOperator(MINUS); + break; + } + } + } + } + + public float eval(String exp) { + Compute compute = computes.get(exp); + if (compute == null) { + expChr = new char[exp.length()]; + int ecIdx = 0; + boolean skip = false; + StringBuilder buf = new StringBuilder(exp); + int depth = 0; + boolean balance = true; + char ch; + for (int i = 0; i < buf.length(); i++) { + ch = buf.charAt(i); + switch (ch) { + case ' ': + case '\n': + skip = true; + break; + case ')': + depth--; + if (depth < 0) + balance = false; + break; + case '(': + depth++; + break; + } + if (skip) { + skip = false; + } else { + expChr[ecIdx] = ch; + ecIdx++; + } + } + if (depth != 0 || !balance) { + return 0; + } + compute = new Compute(); + evalExp(compute, 0, ecIdx); + computes.put(exp, compute); + } + return compute.calc(); + } + + final private class Compute { + + private float[] num = new float[MAX_LENGTH]; + + private int[] opr = new int[MAX_LENGTH]; + + private int idx; + + private float[] stack = new float[MAX_LENGTH]; + + public Compute() { + idx = 0; + } + + private float calcOp(int op, float n1, float n2) { + switch (op) { + case PLUS: + return n1 + n2; + case MINUS: + return n1 - n2; + case MULTIPLE: + return n1 * n2; + case DIVISION: + return n1 / n2; + case MODULO: + return n1 % n2; + } + return 0; + } + + public void setOperator(int op) { + if (idx >= MAX_LENGTH) { + return; + } + if (opr[idx - 1] == STACK_NUM && opr[idx - 2] == STACK_NUM) { + num[idx - 2] = calcOp(op, num[idx - 2], num[idx - 1]); + idx--; + } else { + opr[idx] = op; + idx++; + } + } + + public void push(float nm, int vr) { + if (idx >= MAX_LENGTH) { + return; + } + num[idx] = nm; + opr[idx] = vr; + idx++; + } + + public final float calc() { + int stkIdx = 0; + for (int i = 0; i < idx; i++) { + switch (opr[i]) { + case STACK_NUM: + stack[stkIdx] = num[i]; + stkIdx++; + break; + case STACK_RAND: + stack[stkIdx] = new Random().nextFloat(); + stkIdx++; + break; + default: + if (opr[i] >= STACK_VARIABLE) { + stkIdx++; + } else { + stack[stkIdx - 2] = calcOp(opr[i], + stack[stkIdx - 2], stack[stkIdx - 1]); + stkIdx--; + } + break; + } + } + return stack[0]; + } + } + + public void dispose() { + if (computes != null) { + computes.clear(); + } + } + + public static void main(String[] args) { + Exp exp = new Exp(); + System.out.print(exp.parse("(1 + 1) /2")); + } +} \ No newline at end of file diff --git a/engine/src/main/java/com/lfk/justweengine/utils/script/Function.java b/engine/src/main/java/com/lfk/justweengine/utils/script/Function.java new file mode 100644 index 0000000..71d2618 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/script/Function.java @@ -0,0 +1,35 @@ +package com.lfk.justweengine.utils.script; + +/** + * Function 函数 + * + * @author liufengkai + * Created by liufengkai on 16/2/8. + */ +public class Function { + // 函数开始位置 + private long startIndex; + // 函数结束位置 + private long endIndex; + + public Function(long startIndex, long endIndex) { + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + public long getStartIndex() { + return startIndex; + } + + public void setStartIndex(long startIndex) { + this.startIndex = startIndex; + } + + public long getEndIndex() { + return endIndex; + } + + public void setEndIndex(long endIndex) { + this.endIndex = endIndex; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/script/KeyCode.java b/engine/src/main/java/com/lfk/justweengine/utils/script/KeyCode.java new file mode 100644 index 0000000..1222314 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/script/KeyCode.java @@ -0,0 +1,52 @@ +package com.lfk.justweengine.utils.script; + +/** + * Created by liufengkai on 16/2/8. + */ +public interface KeyCode { + + // 用于注释 + // single annotate + String FLAG_S_ANNO_TAG = "//"; + + String FLAG_INCULDE_TAG = "INCLUDE"; + + // 条件分支 + + String FLAG_IF_TAG = "IF"; + + String FLAG_ELSE_TAG = "ELSE"; + + String FLAG_ELSE_IF_TAG = "ELSEIF"; + + String FLAG_END_IF_TAG = "ENDIF"; + + String FLAG_EQUAL_TAG = "=="; + + String FLAG_UN_EQUAL_TAG = "!="; + + String FLAG_BIGGER_EQUAL_TAG = ">="; + + String FLAG_SMALLER_EQUAL_TAG = "<="; + + String FLAG_SMALLER_TAG = "<"; + + String FLAG_BIGGER_TAG = ">"; + + String FLAG_SET_TAG = "="; + // 运行 + + String FLAG_RUN_TAG = "RUN"; + + // 开始 + + String FLAG_BEGIN_TAG = "BEGIN"; + + // 结束 + + String FLAG_END_TAG = "END"; + + // 主函数 + + String FLAG_MAIN_TAG = "MAIN"; +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/script/NumberUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/script/NumberUtils.java new file mode 100644 index 0000000..9ddac39 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/script/NumberUtils.java @@ -0,0 +1,140 @@ +package com.lfk.justweengine.utils.script; + +public class NumberUtils { + + private NumberUtils() { + + } + + public static int mid(int i, int min, int max) { + return (int) Math.max(i, Math.min(min, max)); + } + + public static int[] getLimit(float x, float y, float width, float height, + float rotate) { + double rotation = Math.toRadians(rotate); + double angSin = Math.sin(rotation); + double angCos = Math.cos(rotation); + int newW = (int) Math.floor((width * Math.abs(angCos)) + + (height * Math.abs(angSin))); + int newH = (int) Math.floor((height * Math.abs(angCos)) + + (width * Math.abs(angSin))); + int centerX = (int) (x + (width / 2)); + int centerY = (int) (y + (height / 2)); + int newX = (int) (centerX - (newW / 2)); + int newY = (int) (centerY - (newH / 2)); + return new int[]{newX, newY, newW, newH}; + } + + final static private String[] zeros = {"", "0", "00", "000", "0000", + "00000", "000000", "0000000", "00000000", "000000000", "0000000000"}; + + /** + * 为指定数值补足位数 + * + * @param number + * @param numDigits + * @return + */ + public static String addZeros(long number, int numDigits) { + return addZeros(String.valueOf(number), numDigits); + } + + /** + * 为指定数值补足位数 + * + * @param number + * @param numDigits + * @return + */ + public static String addZeros(String number, int numDigits) { + int length = numDigits - number.length(); + if (length != 0) { + number = zeros[length] + number; + } + return number; + } + + /** + * 判断是否为数字 + * + * @param param + * @return + */ + public static boolean isNan(String param) { + boolean result = false; + if (param == null || "".equals(param)) { + return result; + } + param = param.replace('d', '_').replace('f', '_'); + try { + Double test = new Double(param); + test.intValue(); + result = true; + } catch (NumberFormatException ex) { + return result; + } + return result; + } + + /** + * 检查一个数字是否为空 + * + * @param val + * @return + */ + public static boolean isEmpty(int val) { + return (val == Integer.MIN_VALUE) ? true : 0 == val; + } + + /** + * 检查一个字符串数字是否为空 + * + * @param val + * @return + */ + public static boolean isEmpty(String val) { + return (val == null | "".equals(val) | (val != null && val.equals(Integer + .toString(Integer.MAX_VALUE)))); + } + + /** + * 单纯计算两个数值的百分比 + * + * @param divisor + * @param dividend + * @return + */ + public static double toPercent(long divisor, long dividend) { + if (divisor == 0 || dividend == 0) { + return 0f; + } + double cf = divisor * 1f; + double pf = dividend * 1f; + + return (Math.round(cf / pf * 10000f) * 1f) / 100f; + } + + /** + * 获得100%进制剩余数值百分比。 + * + * @param maxValue + * @param minusValue + * @return + */ + public static double minusPercent(double maxValue, double minusValue) { + return 100 - ((minusValue / maxValue) * 100); + } + + /** + * 获得100%进制数值百分比。 + * + * @param maxValue + * @param minusValue + * @return + */ + public static double percent(double maxValue, double minValue) { + return (minValue / maxValue) * 100; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/script/ScriptManager.java b/engine/src/main/java/com/lfk/justweengine/utils/script/ScriptManager.java new file mode 100644 index 0000000..6984217 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/script/ScriptManager.java @@ -0,0 +1,412 @@ +package com.lfk.justweengine.utils.script; + +import com.lfk.justweengine.utils.tools.ValidatorsUtils; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * ScriptManager + * + * @author liufengkai + * Created by liufengkai on 16/2/8. + */ +public class ScriptManager implements KeyCode { + + private HashMap functionIndex; + + private Stack indexStack; + + private Stack ifStack; + + private RandomAccessFile file; + + private long fileLength; + + private long fileLines = 0; + + private final Object lock = new Object(); + + private Exp exp = new Exp(); + + private static HashMap flagDefaultMap = new HashMap<>(); + + + public ScriptManager() { + functionIndex = new HashMap<>(); + indexStack = new Stack<>(); + ifStack = new Stack<>(); + } + + + public void open(String name) { + try { + file = new RandomAccessFile(name, "rw"); + fileLength = file.length(); + } catch (IOException e) { + e.printStackTrace(); + } + + CodeThread thread = new CodeThread(); + thread.start(); + + thread.setPreTreatment(new OnAfterPreTreatment() { + @Override + public void AfterPreTreatment() { + + for (int i = 0; i < 50; i++) { + doExecute(); + } + + } + }); + } + + /** + * 预处理线程: + * 接到脚本后进行预处理,把方法的开始和末尾的位置保存 + * 并且定位主函数入栈 + * + * @example : + *

+ * 位置入栈: + * BEGIN FUNCTION: + * ... + * END FUNCTION + *

+ * 主函数标记: + *

+ * MAIN: + */ + private class CodeThread extends Thread { + private long startIndex; + private long endIndex; + private String functionName; + private OnAfterPreTreatment preTreatment; + + public void setPreTreatment(OnAfterPreTreatment preTreatment) { + this.preTreatment = preTreatment; + } + + public CodeThread() { + clearData(); + fileLines = 0; + } + + private void clearData() { + startIndex = 0; + endIndex = 0; + functionName = null; + } + + @Override + public void run() { + super.run(); + synchronized (lock) { + try { + // 处理整个脚本 + while (file.getFilePointer() < fileLength) { + // 读入每一行 + String line = new String((file.readLine()). + getBytes("iso-8859-1"), "UTF-8").trim(); + fileLines++; + // 检测开始标记 + if (line.startsWith(KeyCode.FLAG_BEGIN_TAG)) { + startIndex = file.getFilePointer(); + functionName = line.substring(6, line.length() - 1); + // 检测结束标记 + } else if (line.startsWith(KeyCode.FLAG_END_TAG) && + !line.startsWith(KeyCode.FLAG_END_IF_TAG)) { + // 方法名字相同 然后保存 + if (functionName.equals(line.substring(4, line.length()))) { + endIndex = file.getFilePointer(); + functionIndex.put(functionName, + new Function(startIndex, endIndex)); + } else { + // 清理数据 + clearData(); + } + // 寻找主函数 + } else if (line.startsWith("MAIN")) { + indexStack.add(file.getFilePointer()); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + // 指针放到主函数位置 + setIndex(indexStack.peek()); + + if (preTreatment != null) + preTreatment.AfterPreTreatment(); + } + } + } + + public interface OnAfterPreTreatment { + void AfterPreTreatment(); + } + + public synchronized void doExecute() { + try { + + if (file.getFilePointer() == fileLength) { + return; + } + + String line = new String((file.readLine()). + getBytes("iso-8859-1"), "UTF-8").trim(); + + updateIndex(); + + // 判断空行 + if (line.equals("")) { + line = file.readLine(); + updateIndex(); + } + + if (!ifStack.empty()) { + // false + if (!ifStack.peek()) { + while (true) { + line = file.readLine(); + if (hasRax(KeyCode.FLAG_ELSE_TAG, line)) { + ifStack.pop(); + break; + } else if (hasRax(KeyCode.FLAG_ELSE_IF_TAG, line)) { + break; + } else if (hasRax(KeyCode.FLAG_END_IF_TAG, line)) { + ifStack.pop(); + return; + } + } + } + } + + if (line.startsWith(KeyCode.FLAG_RUN_TAG)) { + runParse(line); + } else if (line.startsWith(KeyCode.FLAG_END_TAG) && + !line.startsWith(KeyCode.FLAG_END_IF_TAG)) { + endParse(); + } else if (hasRax("=", line)) { + evalParse(line); + } else if (hasRax(KeyCode.FLAG_IF_TAG, line)) { + ifStack.push(ifParse(line)); + } else if (hasRax(KeyCode.FLAG_ELSE_IF_TAG, line)) { + if (!ifStack.peek()) { + ifStack.pop(); + ifStack.push(elseIfParse(line)); + } else { + ifEndParse(); + } + } else if (hasRax(KeyCode.FLAG_ELSE_TAG, line)) { + doExecute(); + } + + } catch (IOException e) { + e.printStackTrace(); + } + + } + + private void updateIndex() { + try { + indexStack.pop(); + indexStack.push(file.getFilePointer()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public boolean setIndex(long index) { + if (index <= fileLength) { + try { + file.seek(index); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + return false; + } + + private void ifEndParse() { + while (true) { + String line = null; + try { + line = file.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + if (hasRax(KeyCode.FLAG_END_IF_TAG, line)) { + ifStack.pop(); + break; + } + } + } + + private void runParse(String command) { + String name = command.substring(4, command.length()); + if (functionIndex.containsKey(name)) { + long index = functionIndex.get(name).getStartIndex(); + setIndex(index); + indexStack.push(index); + } + } + + private void endParse() { + indexStack.pop(); + setIndex(indexStack.peek()); + } + + private boolean elseIfParse(String command) { + return coverParse(command.substring(7, command.length() - 1)); + } + + private boolean ifParse(String command) { + return coverParse(command.substring(3, command.length() - 1)); + } + + private boolean coverParse(String command) { + List list = commandToCondition(command); + Object valueA = list.get(1); + Object valueB = list.get(2); + valueA = !flagDefaultMap.containsKey(valueA.toString()) ? + valueA : flagDefaultMap.get(valueA.toString()); + valueB = !flagDefaultMap.containsValue(valueB.toString()) ? + valueB : flagDefaultMap.get(valueB.toString()); + String condition = list.get(0).toString(); + if ("==".equals(condition)) { + return valueA.toString().equals(valueB.toString()); + // 非等 + } else if ("!=".equals(condition)) { + return !valueA.toString().equals(valueB.toString()); + // 大于 + } else if (">".equals(condition)) { + float numberA = Float.parseFloat(valueA.toString()); + float numberB = Float.parseFloat(valueB.toString()); + return numberA > numberB; + // 小于 + } else if ("<".equals(condition)) { + float numberA = Float.parseFloat(valueA.toString()); + float numberB = Float.parseFloat(valueB.toString()); + return numberA < numberB; + + // 大于等于 + } else if (">=".equals(condition)) { + float numberA = Float.parseFloat(valueA.toString()); + float numberB = Float.parseFloat(valueB.toString()); + return numberA >= numberB; + // 小于等于 + } else if ("<=".equals(condition)) { + float numberA = Float.parseFloat(valueA.toString()); + float numberB = Float.parseFloat(valueB.toString()); + return numberA <= numberB; + } + return false; + } + + private void evalParse(String command) { + String com = command.replace(" ", ""); + int index = com.indexOf("="); + String left = com.substring(0, index); + String right = com.substring(index + 1); + float rightNum; + // 不是字符串 + // 是表达式 + if (exp.exp(right)) { + // 替换 + for (Object o : flagDefaultMap.entrySet()) { + Map.Entry entry = (Map.Entry) o; + right = rax(entry.getKey().toString(), right); + } + // 计算 + rightNum = exp.parse(right); + flagDefaultMap.put(left, rightNum); + } else if (ValidatorsUtils.isNumeric(right)) { + rightNum = exp.parse(right); + flagDefaultMap.put(left, rightNum); + } + } + + private String rax(String rax, String command) { + String X = "([^a-zA-Z0-9]|^)" + rax + "([^a-zA-Z0-9]|$)"; + Pattern pattern = Pattern.compile(X); + Matcher matcher = pattern.matcher(command); +// printIt(command + "\n"); + while (matcher.find()) { + System.out.println("start:" + matcher.start()); + System.out.println("end:" + matcher.end()); + command = command.substring(0, matcher.start() + 1) + + flagDefaultMap.get(rax).toString() + + command.substring(matcher.end() - 1); + } + return command; + } + + public List commandToCondition(String command) { + List list = new ArrayList<>(); + int index; + if (command.contains(KeyCode.FLAG_EQUAL_TAG)) { + list.add(KeyCode.FLAG_EQUAL_TAG); + } else if (command.contains(KeyCode.FLAG_UN_EQUAL_TAG)) { + list.add(KeyCode.FLAG_UN_EQUAL_TAG); + } else if (command.contains(KeyCode.FLAG_SMALLER_TAG) + && !command.contains(KeyCode.FLAG_SMALLER_EQUAL_TAG)) { + list.add(KeyCode.FLAG_SMALLER_TAG); + } else if (command.contains(KeyCode.FLAG_BIGGER_TAG) + && !command.contains(KeyCode.FLAG_BIGGER_EQUAL_TAG)) { + list.add(KeyCode.FLAG_BIGGER_TAG); + } else if (command.contains(KeyCode.FLAG_SMALLER_EQUAL_TAG)) { + list.add(KeyCode.FLAG_SMALLER_EQUAL_TAG); + } else if (command.contains(KeyCode.FLAG_BIGGER_EQUAL_TAG)) { + list.add(KeyCode.FLAG_BIGGER_EQUAL_TAG); + } + index = command.indexOf(list.get(0)); + list.add(command.substring(0, index).trim()); + list.add(command.substring(index + list.get(0).length())); + return list; + } + + private boolean hasRax(String rax, String command) { + String X = "([^a-zA-Z0-9]|^)" + rax + "([^a-zA-Z0-9]|$)"; + Pattern pattern = Pattern.compile(X); + Matcher matcher = pattern.matcher(command); + return matcher.find(); + } + + public void printIt() { +// printIt(functionIndex.size() + ""); + for (Object o : functionIndex.entrySet()) { + Map.Entry entry = (Map.Entry) o; + Object key = entry.getKey(); + Function val = (Function) entry.getValue(); + System.out.print("key:" + key + + "val:" + val.getStartIndex() + "\n" + ); + } + +// printIt(flagDefaultMap.size() + ""); + for (Object o : flagDefaultMap.entrySet()) { + Map.Entry entry = (Map.Entry) o; + Object key = entry.getKey(); + System.out.print("key:" + key + + "val:" + entry.getValue().toString() + "\n" + ); + } + } + + private static void printIt(String name) { + System.out.print(name + "\n"); + } + + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogHandler.java b/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogHandler.java new file mode 100644 index 0000000..6b2c715 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogHandler.java @@ -0,0 +1,155 @@ +package com.lfk.justweengine.utils.showLogger; + +import android.os.Handler; +import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; + +import com.lfk.justweengine.utils.logger.LogCat; +import com.lfk.justweengine.utils.logger.LogLevel; +import com.lfk.justweengine.utils.logger.Options; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * LogPrintHandler + *

+ * Created by liufengkai on 16/4/15. + */ +public class LogHandler { + + private static LogHandler mInstance = null; + + private static int darningTime = 3; + + public static final int LOGCAT = 100; + + private static Handler sentHandler; + + private ScheduledExecutorService service; + + public class Line implements Parcelable { + String line; + String lev; + String time; + String tag; + + public Line() { + + } + + protected Line(Parcel in) { + line = in.readString(); + lev = in.readString(); + time = in.readString(); + tag = in.readString(); + } + + public final Creator CREATOR = new Creator() { + @Override + public Line createFromParcel(Parcel in) { + return new Line(in); + } + + @Override + public Line[] newArray(int size) { + return new Line[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(line); + dest.writeString(lev); + dest.writeString(time); + dest.writeString(tag); + } + } + + + public static LogHandler getInstance() { + if (mInstance == null) { + synchronized (LogHandler.class) { + if (mInstance == null) + mInstance = new LogHandler(); + } + } + return mInstance; + } + + private class GetLogger implements Runnable { + @Override + public void run() { + getLogger(); + } + } + + private void getLogger() { + Process process = LogCat.getInstance() + .options(Options.DUMP) + .withTime() + .recentLines(1000) + .filter("", LogLevel.VERBOSE) + .commit(); + BufferedReader bufferedReader = null; + try { + bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = bufferedReader.readLine()) != null) { + if (sentHandler != null) { + Message msg = sentHandler.obtainMessage(); + msg.obj = getLine(line); + msg.what = LOGCAT; + sentHandler.sendMessage(msg); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + private Line getLine(String line) { + Line log = new Line(); + int tagStart = line.indexOf("/"); + int msgStart = line.indexOf("):"); + if (msgStart == -1 || tagStart == -1) { + return null; + } + log.tag = line.substring(tagStart + 1, msgStart + 1); + log.line = line.substring(msgStart + 2); + log.lev = line.substring(tagStart - 1, tagStart); + log.time = line.substring(0, tagStart - 2); + return log; + } + + + public LogHandler() { + service = Executors.newSingleThreadScheduledExecutor(); + + service.scheduleAtFixedRate(new GetLogger(), 0, darningTime, TimeUnit.SECONDS); + } + + public static void init(Handler handler, int time) { + sentHandler = handler; + darningTime = time; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogPrinter.java b/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogPrinter.java new file mode 100644 index 0000000..fd2d8ce --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/showLogger/LogPrinter.java @@ -0,0 +1,105 @@ +package com.lfk.justweengine.utils.showLogger; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.lfk.justweengine.info.UIdefaultData; +import com.lfk.justweengine.utils.logger.LogLevel; +import com.lfk.justweengine.utils.logger.LogParser; +import com.lfk.justweengine.utils.tools.DisplayUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Created by liufengkai on 16/4/15. + */ +public class LogPrinter { + + public static Map colorMap = new HashMap<>(); + + private CopyOnWriteArrayList logLinesList; + + // 多少行弹幕 + private int logListSize; + + private int left_X; + + private int left_Y; + + private int line_width; + + private Paint textPaint; + + static { + colorMap.put(LogLevel.VERBOSE, 0XFF717171); + colorMap.put(LogLevel.DEBUG, 0XFF2980b9); + colorMap.put(LogLevel.INFO, 0XFF27ae60); + colorMap.put(LogLevel.WARN, 0XFFf39c12); + colorMap.put(LogLevel.ERROR, 0XFFc0392b); + colorMap.put(LogLevel.FATAL, 0XFFc0392b); + colorMap.put(LogLevel.ASSERT, 0XFFc0392b); + } + + + public LogPrinter(int d_time) { + logLinesList = new CopyOnWriteArrayList<>(); + init(d_time); + } + + private void init(int d_time) { + + this.left_X = (int) (DisplayUtils.dip2px(2)); + this.left_Y = (int) (DisplayUtils.dip2px(2)); + + this.textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + this.textPaint.setColor(colorMap.get(LogLevel.VERBOSE)); + this.textPaint.setTextSize(20); + + float[] widths = new float[1]; + textPaint.getTextWidths("H", widths); + + this.logListSize = + (int) ((UIdefaultData.screenHeight - DisplayUtils.dip2px(4)) + / widths[0] + DisplayUtils.dip2px(4)); + + this.line_width = (int) (widths[0] + DisplayUtils.dip2px(2)); + + Log.e("listX", left_X + " "); + + LogHandler.init(new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case LogHandler.LOGCAT: + while (logLinesList.size() >= logListSize) + logLinesList.remove(0); + logLinesList.add((LogHandler.Line) msg.obj); + break; + } + } + }, d_time); + LogHandler.getInstance(); + } + + + public void draw(Canvas engine) { + int index = 0; + for (LogHandler.Line line : logLinesList) { + if (index == logListSize) index = 0; + if (line != null) { + textPaint.setColor(colorMap.get(LogParser.parseLev(line.lev))); + engine.drawText(line.line, + left_X, + left_Y + index * line_width, + textPaint); + index++; + } + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/DisplayUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/DisplayUtils.java new file mode 100644 index 0000000..12bf007 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/DisplayUtils.java @@ -0,0 +1,93 @@ +package com.lfk.justweengine.utils.tools; + +import android.content.Context; +import android.util.TypedValue; + +import com.lfk.justweengine.info.UIdefaultData; + +/** + * Created by liufengkai on 15/11/8. + */ +public class DisplayUtils { + /** + * px to dip 尺寸不变 + * + * @param context + * @param pxValue + * @return + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + + /** + * dip to px 尺寸不变 + * + * @param context + * @param dipValue + * @return + */ + public static int dip2px(Context context, float dipValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dipValue * scale + 0.5f); + } + + public static float dip2px(float dipValue) { + return (dipValue * UIdefaultData.scale + 0.5f); + } + + /** + * dp to px + * + * @param context + * @param dp + * @return + */ + public static int dp2px(Context context, int dp) { + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + dp, + context.getResources().getDisplayMetrics()); + } + + /** + * px to sp 文字不变 + * + * @param context + * @param pxValue + * @return + */ + public static float px2sp(Context context, float pxValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (pxValue / fontScale + 0.5f); + } + + /** + * sp to px 文字不变 + * + * @param context + * @param spValue + * @return + */ + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + /** + * sp to px + * + * @param context + * @param px + * @return + */ + public static int sp2px(Context context, int px) { + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + px, + context.getResources().getDisplayMetrics()); + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/ImageHelper.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/ImageHelper.java new file mode 100644 index 0000000..ecdd764 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/ImageHelper.java @@ -0,0 +1,136 @@ +package com.lfk.justweengine.utils.tools; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; + +/** + * Created by liufengkai on 15/11/10. + */ +public class ImageHelper { + + /** + * 设置图片的色调\饱和度\亮度 + * + * @param bm + * @param hue 色调 + * @param saturation 饱和度 + * @param lum 亮度 + * @return + */ + public static Bitmap handleImageEffect(Bitmap bm, + float hue, + float saturation, + float lum) { + Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), + Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bmp); + Paint paint = new Paint(); + + ColorMatrix hueMatrix = new ColorMatrix(); + hueMatrix.setRotate(0, hue); + hueMatrix.setRotate(1, hue); + hueMatrix.setRotate(2, hue); + + ColorMatrix saturationMatrix = new ColorMatrix(); + saturationMatrix.setSaturation(saturation); + + ColorMatrix lumMatrix = new ColorMatrix(); + lumMatrix.setScale(lum, lum, lum, 1); + + ColorMatrix imageMatrix = new ColorMatrix(); + imageMatrix.postConcat(hueMatrix); + imageMatrix.postConcat(saturationMatrix); + imageMatrix.postConcat(lumMatrix); + + paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix)); + canvas.drawBitmap(bm, 0, 0, paint); + return bmp; + } + + public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) { + Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), + Bitmap.Config.ARGB_8888); + int width = bm.getWidth(); + int height = bm.getHeight(); + int color = 0; + int r, g, b, a, r1, g1, b1; + + int[] oldPx = new int[width * height]; + int[] newPx = new int[width * height]; + + bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height); + for (int i = 0; i < width * height; i++) { + color = oldPx[i]; + a = Color.alpha(color); + r = Color.red(color); + g = Color.green(color); + b = Color.blue(color); + + r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b); + g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b); + b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b); + + if (r1 > 255) { + r1 = 255; + } + if (g1 > 255) { + g1 = 255; + } + if (b1 > 255) { + b1 = 255; + } + + newPx[i] = Color.argb(a, r1, g1, b1); + } + bmp.setPixels(newPx, 0, width, 0, 0, width, height); + return bmp; + } + + public static Bitmap handleImagePixelsRelief(Bitmap bm) { + Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), + Bitmap.Config.ARGB_8888); + int width = bm.getWidth(); + int height = bm.getHeight(); + int color = 0, colorBefore = 0; + int a, r, g, b; + int r1, g1, b1; + + int[] oldPx = new int[width * height]; + int[] newPx = new int[width * height]; + + bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height); + for (int i = 1; i < width * height; i++) { + colorBefore = oldPx[i - 1]; + a = Color.alpha(colorBefore); + r = Color.red(colorBefore); + g = Color.green(colorBefore); + b = Color.blue(colorBefore); + + color = oldPx[i]; + r1 = Color.red(color); + g1 = Color.green(color); + b1 = Color.blue(color); + + r = (r - r1 + 127); + g = (g - g1 + 127); + b = (b - b1 + 127); + if (r > 255) { + r = 255; + } + if (g > 255) { + g = 255; + } + if (b > 255) { + b = 255; + } + newPx[i] = Color.argb(a, r, g, b); + } + bmp.setPixels(newPx, 0, width, 0, 0, width, height); + return bmp; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/NetUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/NetUtils.java new file mode 100644 index 0000000..9ff3ff3 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/NetUtils.java @@ -0,0 +1,90 @@ +package com.lfk.justweengine.utils.tools; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.location.LocationManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * 判断网络状态的工具类 + * + * @author liufengkai + */ +public class NetUtils { + + private NetUtils() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + /** + * 判断网络是否连接 + * + * @param context + * @return 是否已连接网络 + */ + public static boolean isConnected(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (null != connectivity) { + NetworkInfo info = connectivity.getActiveNetworkInfo(); + if (null != info && info.isConnected()) { + if (info.getState() == NetworkInfo.State.CONNECTED) { + return true; + } + } + } + return false; + } + + /** + * 判断是否是wifi连接 + * + * @param context + * @return 是否连接Wi-Fi + */ + public static boolean isWifi(Context context) { + // 先判断是否连接 + if (!isConnected(context)) { + return false; + } + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + + if (cm == null) + return false; + return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI; + } + + /** + * 打开网络设置界面 + * + * @param activity + */ + public static void openSetting(Activity activity) { + Intent intent = new Intent("/"); + ComponentName cm = new ComponentName("com.android.settings", + "com.android.settings.WirelessSettings"); + intent.setComponent(cm); + intent.setAction("android.intent.action.VIEW"); + activity.startActivityForResult(intent, 0); + } + + /** + * 判断GPS是否打开 + * + * @param context + * @return + */ + public static boolean isGpsEnabled(Context context) { + LocationManager alm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + if (!alm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + return false; + } + return true; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/PicUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/PicUtils.java new file mode 100644 index 0000000..e7499cc --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/PicUtils.java @@ -0,0 +1,554 @@ +package com.lfk.justweengine.utils.tools; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.util.Base64; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; +import android.widget.ScrollView; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * 图片处理工具类 + * + * @author liufengkai + */ +public class PicUtils { + + /** + * 将Bitmap转换成字符串 + * + * @param bitmap 传入图片的bitmap + * @return String + */ + public static String bitmapToString(Bitmap bitmap) { + String bitmapString = null; + ByteArrayOutputStream bStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, bStream); + byte[] bytes = bStream.toByteArray(); + bitmapString = Base64.encodeToString(bytes, Base64.DEFAULT); + return bitmapString; + } + + /** + * 将字符串转换成Bitmap类型 + * + * @param string 传入图片转出的字符串 + * @return Bitmap + */ + public static Bitmap stringToBitmap(String string) { + Bitmap bitmap = null; + try { + byte[] bitmapArray; + bitmapArray = Base64.decode(string, Base64.DEFAULT); + bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length); + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + /** + * 生成截图,不包含ActionBar + * + * @param context 传入Context + * @return Bitmap + */ + public static Bitmap printScreenWithOutActionBar(Activity context) { + // 获取屏幕 + View view = context.getWindow().getDecorView(); + Display display = context.getWindowManager().getDefaultDisplay(); + view.layout(0, 0, display.getWidth(), display.getHeight()); + view.setDrawingCacheEnabled(true); + // 以一个矩形进行截图 + Rect frame = new Rect(); + context.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); + // 获取高度 + int statusBarHeight = frame.top; + int width = context.getWindowManager().getDefaultDisplay().getWidth(); + int height = context.getWindowManager().getDefaultDisplay() + .getHeight(); + // 获取ActionBar的高度 + TypedArray actionbarSizeTypedArray = context.obtainStyledAttributes(new int[]{ + android.R.attr.actionBarSize}); + int h = (int) actionbarSizeTypedArray.getDimension(0, 0); + // 生成Bitmap + return Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight + h, width, height + - statusBarHeight - h); + // 生成文件 +// File f = new File(Environment.getExternalStorageDirectory(), +// "output_image.jpg"); +// FileOutputStream fOut = null; +// try { +// fOut = new FileOutputStream(f); +// bmp.compress(Bitmap.CompressFormat.JPEG, 100, fOut); +// fOut.flush(); +// fOut.close(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// return Uri.fromFile(f); + } + + /** + * 截取整个屏幕 + * + * @param context + * @return Bitmap + */ + public Bitmap printAllScreen(Activity context) { + View view = context.getWindow().getDecorView(); + Display display = context.getWindowManager().getDefaultDisplay(); + view.layout(0, 0, display.getWidth(), display.getHeight()); + view.setDrawingCacheEnabled(true); + return Bitmap.createBitmap(view.getDrawingCache()); + } + + + /** + * 合成图层 + * + * @param background 背景 + * @param foreground 前景 + * @return Bitmap + */ + private Bitmap toConformBitmap(Bitmap background, Bitmap foreground) { + if (background == null || foreground == null) { + return null; + } + int bgWidth = background.getWidth(); + int bgHeight = background.getHeight(); + Bitmap bitmap = Bitmap.createBitmap(bgWidth, bgHeight, Bitmap.Config.ARGB_8888); + Canvas cv = new Canvas(bitmap); + cv.drawBitmap(background, 0, 0, null); + cv.drawBitmap(foreground, 0, 0, null); + // 保存 + cv.save(Canvas.ALL_SAVE_FLAG); + // 存储 + cv.restore(); + return bitmap; + } + + /** + * 将View转换为图片 + * + * @param view 传入一个View + * @return Bitmap + */ + public static Bitmap getBitmapFromView(View view) { + Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(returnedBitmap); + Drawable bgDrawable = view.getBackground(); + if (bgDrawable != null) + bgDrawable.draw(canvas); + else + canvas.drawColor(Color.WHITE); + view.draw(canvas); + return returnedBitmap; + } + + /** + * 自动压缩图片 + * + * @param image 传入图片bitmap + * @return bitmap + */ + public static Bitmap compressImage(Bitmap image) { + ByteArrayOutputStream baoS = new ByteArrayOutputStream(); + // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baoS中 + int options = 100; + image.compress(Bitmap.CompressFormat.JPEG, 100, baoS); + // 循环判断如果压缩后图片是否大于100kb,大于继续压缩 + while (baoS.toByteArray().length / 1024 > 100) { + // 重置baoS即清空baoS + baoS.reset(); + // 压缩options%,把压缩后的数据存放到baos中 + image.compress(Bitmap.CompressFormat.JPEG, options, baoS); + options -= 10; + } + // 把压缩后的数据baos存放到ByteArrayInputStream中 + ByteArrayInputStream isBm = new ByteArrayInputStream(baoS.toByteArray()); + // 把ByteArrayInputStream数据生成图片 + return BitmapFactory.decodeStream(isBm, null, null); + } + + /** + * 指定压缩的质量压缩图片 + * + * @param image 传入图片的Bitmap + * @param options 压缩图片质量 + * @return bitmap + */ + public static Bitmap compressImage(Bitmap image, int options) { + ByteArrayOutputStream baoS = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.JPEG, options, baoS); + ByteArrayInputStream isBm = new ByteArrayInputStream(baoS.toByteArray()); + return BitmapFactory.decodeStream(isBm, null, null); + } + + /** + * 按照比例进行缩放 + * + * @param image 传入的Bitmap + * @param width 传入的宽度 + * @param height 传入的高度 + * @return Bitmap + */ + private static Bitmap compressWithMeasure(Bitmap image, int width, int height) { + ByteArrayOutputStream baoS = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.JPEG, 100, baoS); + // 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 + if (baoS.toByteArray().length / 1024 > 1024) { + // 重置baoS即清空baoS + baoS.reset(); + // 这里压缩50%,把压缩后的数据存放到baoS中 + image.compress(Bitmap.CompressFormat.JPEG, 50, baoS); + } + ByteArrayInputStream isBm = new ByteArrayInputStream(baoS.toByteArray()); + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 + newOpts.inJustDecodeBounds = true; + Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); + newOpts.inJustDecodeBounds = false; + int w = newOpts.outWidth; + int h = newOpts.outHeight; + // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 + // be = 1表示不缩放 + int be = 1; + if (w > h && w > width) { + // 如果宽度大的话根据宽度固定大小缩放 + be = newOpts.outWidth / width; + } else if (w < h && h > height) { + // 如果高度高的话根据宽度固定大小缩放 + be = newOpts.outHeight / height; + } + if (be <= 0) + be = 1; + // 设置缩放比例 + newOpts.inSampleSize = be; + // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 + isBm = new ByteArrayInputStream(baoS.toByteArray()); + bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); + // 压缩好比例大小后再进行质量压缩 + return compressImage(bitmap); + } + + /** + * 按照原比例进行缩放 + * + * @param image + * @return Bitmap + */ + public static Bitmap compressWithMeasure(Bitmap image) { + return compressWithMeasure(image, image.getWidth(), image.getHeight()); + } + + /** + * 获取网络上的图片 + * + * @param url + * @return + */ + public static Bitmap getHttpBitmap(String url) { + URL myFileURL; + Bitmap bitmap = null; + try { + myFileURL = new URL(url); + + // 获得连接 + HttpURLConnection conn = (HttpURLConnection) myFileURL.openConnection(); + + conn.setConnectTimeout(6000);// 设置超时时间为6000毫秒,conn.setConnectionTiem(0);表示没有时间限制 + conn.setDoInput(true);// 连接设置获得数据流 + conn.setUseCaches(false);// 不使用缓存 + InputStream is = conn.getInputStream();// 得到数据流,这里会有调用conn.connect(); + + // 解析得到图片 + bitmap = BitmapFactory.decodeStream(is); + is.close();// 关闭数据流 + } catch (Exception e) { + e.printStackTrace(); + } + + return bitmap; + } + + /** + * 从资源中获取Bitmap + * + * @param context + * @param resid 例如这样:R.drawable.icon + * @return + */ + public static Bitmap getBitmapFromResources(Context context, int resid) { + Resources res = context.getResources(); + Bitmap bitmap = BitmapFactory.decodeResource(res, resid); + return bitmap; + } + + /** + * Bitmap转字节 + * + * @param bitmap + * @return + */ + public byte[] Bitmap2Bytes(Bitmap bitmap) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); + return baos.toByteArray(); + } + + /** + * 字节转Bitmap + * + * @param bytes + * @return + */ + public Bitmap Bytes2Bimap(byte[] bytes) { + if (bytes.length != 0) { + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } else { + return null; + } + } + + /** + * Bitmap缩放,可能比例要注意一下 + * + * @param bitmap + * @param width + * @param height + * @return + */ + public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) width / w); + float scaleHeight = ((float) height / h); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); + return newbmp; + } + + /** + * 将Drawable转化为Bitmap + * + * @param drawable + * @return + */ + public static Bitmap drawable2Bitmap(Drawable drawable) { + // 取 drawable 的长宽 + int w = drawable.getIntrinsicWidth(); + int h = drawable.getIntrinsicHeight(); + + // 取 drawable 的颜色格式 + Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565; + + // 建立对应 bitmap + Bitmap bitmap = Bitmap.createBitmap(w, h, config); + + // 建立对应 bitmap 的画布 + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, w, h); + + // 把 drawable 内容画到画布中 + drawable.draw(canvas); + return bitmap; + } + + /** + * Bitmap转换成Drawable + * + * @param context + * @param bitmap + * @return + */ + public static Drawable Bitmap2Drawable(Context context, Bitmap bitmap) { + BitmapDrawable bd = new BitmapDrawable(context.getResources(), bitmap); + return bd; + } + + /** + * 获得圆角图片 + * + * @param bitmap + * @param roundPx + * @return + */ + public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Bitmap output = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, w, h); + final RectF rectF = new RectF(rect); + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + + /** + * 获得带倒影的图片 + * + * @param bitmap + * @return + */ + public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { + final int reflectionGap = 4; + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + Matrix matrix = new Matrix(); + matrix.preScale(1, -1); + + Bitmap reflectionImage; + reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w, h / 2, matrix, false); + + Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2), Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmapWithReflection); + canvas.drawBitmap(bitmap, 0, 0, null); + + canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null); + + Paint paint = new Paint(); + LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, bitmapWithReflection.getHeight() + + reflectionGap, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP); + paint.setShader(shader); + // Set the Transfer mode to be porter duff and destination in + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + // Draw a rectangle using the paint with our linear gradient + canvas.drawRect(0, h, w, bitmapWithReflection.getHeight() + reflectionGap, paint); + + return bitmapWithReflection; + } + + public static class ImagePiece { + public Bitmap bitmap = null; + public int index = 0; + + public ImagePiece(Bitmap bitmap) { + this.bitmap = bitmap; + this.index = 0; + } + + public ImagePiece(Bitmap bitmap, int index) { + this.bitmap = bitmap; + this.index = index; + } + } + + /** + * 截图分片 + * + * @param context + * @param bitmap + * @return + */ + public static List spilt(Context context, Bitmap bitmap) { + int screenHeight = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getHeight(); + List list = new ArrayList<>(); + if (bitmap.getHeight() <= screenHeight) { + list.add(new ImagePiece(bitmap)); + return list; + } + + int pageNum = Math.round(bitmap.getHeight() * 1.0f / screenHeight); + for (int i = 0; i < pageNum; i++) { + int xValue = 0; + int yValue = i * screenHeight + DisplayUtils.dp2px(context, 16); + list.add(new ImagePiece( + Bitmap.createBitmap(bitmap, xValue, yValue, + bitmap.getWidth(), screenHeight), + i)); + } + + return list; + } + + /** + * 截取ScrollView + * + * @param v + * @return + */ + public static Bitmap createBitmap(Context context, ScrollView v) { + int width = 0, height = 0; + for (int i = 0; i < v.getChildCount(); i++) { + width += v.getChildAt(i).getWidth(); + height += v.getChildAt(i).getHeight(); + } + if (width <= 0 || height <= 0) { + return null; + } + int h = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight(); + if (height < h) + height = h; + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + v.draw(canvas); + return bitmap; + } + + /** + * 制作圆形图片 + * + * @param rect + */ + public static Bitmap rectBitmapToCircle(Bitmap rect) { + Shader mBitmapShader = new BitmapShader(rect, Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP); + Paint paint = new Paint(); + paint.setShader(mBitmapShader); + Bitmap output = Bitmap.createBitmap(rect.getWidth(), rect.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + canvas.drawCircle(rect.getWidth() / 2, + rect.getHeight() / 2, + Math.min(rect.getWidth(), rect.getHeight()) / 2 + , paint); + return output; + } + + public static Bitmap getMaskBitmap(int w, int h) { + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawColor(Color.BLACK); + return bitmap; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/ServiceUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/ServiceUtils.java new file mode 100644 index 0000000..8c6868d --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/ServiceUtils.java @@ -0,0 +1,65 @@ +package com.lfk.justweengine.utils.tools; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; + +import java.util.List; + +/** + * 服务工具类 + * + * @author liufengkai + */ +public class ServiceUtils { + /** + * 判断service是否正在运行 + * + * @param context + * @param className + * @return + */ + public static boolean isServiceRunning(Context context, String className) { + boolean isRunning = false; + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List serviceList = activityManager.getRunningServices(Integer.MAX_VALUE); + + if (serviceList.size() <= 0) { + return false; + } + + for (int i = 0; i < serviceList.size(); i++) { + if (serviceList.get(i).service.getClassName().equals(className)) { + isRunning = true; + break; + } + } + + return isRunning; + } + + /** + * 启动服务,不会重复启动 + * + * @param context + * @param clazz + */ + public static void startService(Context context, Class clazz, Intent intent) { + if (!isServiceRunning(context, clazz.getName())) { + context.startService(intent); + } + } + + /** + * 关闭服务,会判断服务是否启动着 + * + * @param context + * @param clazz + */ + public static void stopService(Context context, Class clazz) { + if (isServiceRunning(context, clazz.getName())) { + context.stopService(new Intent(context, clazz)); + } + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/SpUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/SpUtils.java new file mode 100644 index 0000000..5189eb2 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/SpUtils.java @@ -0,0 +1,282 @@ +package com.lfk.justweengine.utils.tools; + +import android.content.Context; +import android.content.SharedPreferences; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 简化Sp存储的工具类 + * + * @author liufengkai + */ +public class SpUtils { + + public SpUtils() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + /** + * Sp文件名 + */ + public static final String FILE_NAME = "share_data"; + + /** + * 保存数据的方法,添加具体数据类型 + * + * @param context + * @param key + * @param object + */ + public static void put(Context context, String key, Object object) { + + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + + // 判断数据类型 + if (object instanceof String) { + editor.putString(key, (String) object); + } else if (object instanceof Integer) { + editor.putInt(key, (Integer) object); + } else if (object instanceof Boolean) { + editor.putBoolean(key, (Boolean) object); + } else if (object instanceof Float) { + editor.putFloat(key, (Float) object); + } else if (object instanceof Long) { + editor.putLong(key, (Long) object); + } else { + editor.putString(key, object.toString()); + } + + SharedPreferencesCompat.apply(editor); + } + + /** + * 获取保存数据的方法,添加具体数据类型 + * + * @param context + * @param key + * @param defaultObject + * @return object + */ + public static Object get(Context context, String key, Object defaultObject) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + + if (defaultObject instanceof String) { + return sp.getString(key, (String) defaultObject); + } else if (defaultObject instanceof Integer) { + return sp.getInt(key, (Integer) defaultObject); + } else if (defaultObject instanceof Boolean) { + return sp.getBoolean(key, (Boolean) defaultObject); + } else if (defaultObject instanceof Float) { + return sp.getFloat(key, (Float) defaultObject); + } else if (defaultObject instanceof Long) { + return sp.getLong(key, (Long) defaultObject); + } + + return null; + } + + /** + * 存放数组 + * + * @param context + * @param list + * @param key + */ + public static void putList(Context context, List list, String key) { + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < list.size(); i++) { + JSONObject object = new JSONObject(); + try { + object.put(i + "", list.get(i)); + jsonArray.put(object); + } catch (JSONException e) { + e.printStackTrace(); + } + } + put(context, key, jsonArray.toString()); + } + + /** + * 获取数组 + * + * @param context + * @param key + * @return list + */ + + public static List getList(Context context, String key) { + List list = new ArrayList(); + try { + JSONArray jsonArray = new JSONArray((String) get(context, key, "")); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + list.add(i, object.getString(i + "")); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return list; + } + + /** + * 存入哈希表 + * + * @param context + * @param map + * @param key + */ + public static void putMap(Context context, Map map, String key) { + JSONArray jsonArray = new JSONArray(); + Set set = map.entrySet(); + Iterator iterator = set.iterator(); + for (int i = 0; i < map.size(); i++) { + Map.Entry mapEntry = (Map.Entry) iterator.next(); + try { + JSONObject object = new JSONObject(); + object.put("key", mapEntry.getKey()); + object.put("value", mapEntry.getValue()); + jsonArray.put(object); + } catch (JSONException e) { + e.printStackTrace(); + } + } + put(context, key, jsonArray.toString()); + } + + /** + * 读取哈希表 + * + * @param context + * @param key + * @return map + */ + public static Map getMap(Context context, String key) { + Map map = new HashMap(); + try { + JSONArray jsonArray = new JSONArray((String) get(context, key, "")); + for (int i = 0; i < jsonArray.length(); i++) { + try { + JSONObject object = jsonArray.getJSONObject(i); + map.put(object.getString("key"), object.getString("value")); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + return map; + } + + /** + * 移除某个key值已经对应的值 + * + * @param context + * @param key + */ + public static void remove(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.remove(key); + SharedPreferencesCompat.apply(editor); + } + + /** + * 清除所有数据 + * + * @param context + */ + public static void clear(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.clear(); + SharedPreferencesCompat.apply(editor); + } + + /** + * 查询某个key是否存在 + * + * @param context + * @param key + * @return + */ + public static boolean contains(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + return sp.contains(key); + } + + /** + * 返回所有的键值对 + * + * @param context + * @return map + */ + public static Map getAll(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, + Context.MODE_PRIVATE); + return sp.getAll(); + } + + /** + * 解决SharedPreferencesCompat.apply方法的兼容类 + * + * @author liufengkai + */ + private static class SharedPreferencesCompat { + + private static final Method sApplyMethod = findApplyMethod(); + + /** + * 反射查找apply的方法 + * + * @return method + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private static Method findApplyMethod() { + try { + Class clz = SharedPreferences.Editor.class; + return clz.getMethod("apply"); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 如果找到则使用apply执行,否则使用commit + * + * @param editor + */ + public static void apply(SharedPreferences.Editor editor) { + try { + if (sApplyMethod != null) { + sApplyMethod.invoke(editor); + return; + } + } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + editor.commit(); + } + } + +} \ No newline at end of file diff --git a/engine/src/main/java/com/lfk/justweengine/utils/tools/ValidatorsUtils.java b/engine/src/main/java/com/lfk/justweengine/utils/tools/ValidatorsUtils.java new file mode 100644 index 0000000..f60b6d2 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/tools/ValidatorsUtils.java @@ -0,0 +1,371 @@ +package com.lfk.justweengine.utils.tools; + +import java.util.Collection; +import java.util.regex.Pattern; + +/** + * 正则表达式处理类 + * + * @author liufengkai + */ +public class ValidatorsUtils { + + /** + * 简体中文的正则表达式。 + */ + private static final String REGEX_SIMPLE_CHINESE = "^[\u4E00-\u9FA5]+$"; + + /** + * 字母数字的正则表达式。 + */ + private static final String REGEX_ALPHANUMERIC = "[a-zA-Z0-9]+"; + + /** + * 移动手机号码的正则表达式。 + */ + private static final String REGEX_CHINA_MOBILE = "1(3[4-9]|4[7]|5[012789]|8[278])\\d{8}"; + + /** + * 联通手机号码的正则表达式。 + */ + private static final String REGEX_CHINA_UNICOM = "1(3[0-2]|5[56]|8[56])\\d{8}"; + + /** + * 电信手机号码的正则表达式。 + */ + private static final String REGEX_CHINA_TELECOM = "(?!00|015|013)(0\\d{9,11})|(1(33|53|80|89)\\d{8})"; + + /** + * 整数或浮点数的正则表达式。 + */ + private static final String REGEX_NUMERIC = "(\\+|-){0,1}(\\d+)([.]?)(\\d*)"; + + /** + * 身份证号码的正则表达式。 + */ + private static final String REGEX_ID_CARD = "(\\d{14}|\\d{17})(\\d|x|X)"; + + /** + * 电子邮箱的正则表达式。 + */ + private static final String REGEX_EMAIL = ".+@.+\\.[a-z]+"; + + /** + * 电话号码的正则表达式。 + */ + private static final String REGEX_PHONE_NUMBER = "(([\\((]\\d+[\\))])?|(\\d+[--]?)*)\\d+"; + + /** + * 判断字符串是否只包含字母和数字. + * + * @param str 字符串 + * @return 如果字符串只包含字母和数字, 则返回 true, 否则返回 false. + */ + public static boolean isAlphanumeric(String str) { + return isRegexMatch(str, REGEX_ALPHANUMERIC); + } + + /** + *

+ * Checks if a String is whitespace, empty ("") or null. + *

+ *

+ *

+     *   StringUtils.isBlank(null)                = true
+     *   StringUtils.isBlank("")        = true
+     *   StringUtils.isBlank(" ")       = true
+     *   StringUtils.isBlank("bob")     = false
+     *   StringUtils.isBlank("  bob  ") = false
+     * 
+ * + * @param str the String to check, may be null + * @return true if the String is null, empty or whitespace + */ + public static boolean isBlank(String str) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if ((!Character.isWhitespace(str.charAt(i)))) { + return false; + } + } + return true; + } + + /** + * 是否为中国移动手机号码。 + * + * @param str 字符串 + * @return 如果是移动号码,返回 true,否则返回 false。 + */ + public static boolean isChinaMobile(String str) { + return isRegexMatch(str, REGEX_CHINA_MOBILE); + } + + /** + * 是否为中国联通手机号码。 + * + * @param str 字符串 + * @return 如果是联通号码,返回 true,否则返回 false。 + */ + public static boolean isChinaUnicom(String str) { + return isRegexMatch(str, REGEX_CHINA_UNICOM); + } + + /** + * 判断是否为电信手机。 + * + * @param str 字符串 + * @return 如果是电信号码,返回 true,否则返回 false。 + */ + public static boolean isChinaTelecom(String str) { + return isRegexMatch(str, REGEX_CHINA_TELECOM); + } + + /** + * 判断是否为小灵通手机(Personal Access Phone System, PAS)。 + * + * @param str 字符串 + * @return 如果是小灵通号码,返回 true,否则返回 false。 + * @deprecated 已经被 {@link #isChinaTelecom(String)} 取代 + */ + @Deprecated + public static boolean isChinaPAS(String str) { + return isChinaTelecom(str); + } + + + /** + * 判断字符串是否是合法的电子邮箱地址. + * + * @param str 字符串 + * @return 是true,否则false + */ + public static boolean isEmail(String str) { + return isRegexMatch(str, REGEX_EMAIL); + } + + /** + * 当数组为null, 或者长度为0, 或者长度为1且元素的值为null时返回 true. + * + * @param args + * @return true/false + */ + public static boolean isEmpty(Object[] args) { + return args == null || args.length == 0 || (args.length == 1 && args[0] == null); + } + + /** + * 字符串是否为Empty,null和空格都算是Empty + * + * @param str 字符串 + * @return true/false + */ + public static boolean isEmpty(String str) { + return str == null || str.trim().length() == 0; + } + + /** + * 判断集合是否为空。 + * + * @param 集合泛型 + * @param collection 集合对象 + * @return 当集合对象为 null 或者长度为零时返回 true,否则返回 false。 + */ + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + /** + *

+ * Validating for ID card number. + *

+ * + * @param str string to be validated + * @return If the str is valid ID card number return true, otherwise return false. + */ + public static boolean isIdCardNumber(String str) { + // 15位或18数字, 14数字加x(X)字符或17数字加x(X)字符才是合法的 + return isRegexMatch(str, REGEX_ID_CARD); + } + + /** + * 是否为手机号码, 包括移动, 联通, 小灵通等手机号码. + * + * @param str 字符串 + * @return 若是合法的手机号码返回 true, 否则返回 false. + */ + public static boolean isMobile(String str) { + return isChinaMobile(str) || isChinaUnicom(str) || isChinaPAS(str); + } + + /** + * 是否为数字的字符串。 + * + * @param str 字符串 + * @return true/false + */ + public static boolean isNumber(String str) { + if (isEmpty(str)) { + return false; + } + + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) > '9' || str.charAt(i) < '0') { + return false; + } + } + return true; + } + + /** + * 是否是固定范围内的数字的字符串 + * + * @param str + * @param min + * @param max + * @return true/false + */ + public static boolean isNumber(String str, int min, int max) { + if (!isNumber(str)) { + return false; + } + + int number = Integer.parseInt(str); + return number >= min && number <= max; + } + + /** + * 判断字符是否为整数或浮点数.
+ * + * @param str 字符串 + * @return 若为整数或浮点数则返回 true, 否则返回 false + */ + public static boolean isNumeric(String str) { + return isRegexMatch(str, REGEX_NUMERIC); + } + + /** + * 判断字符是否为符合精度要求的整数或浮点数。 + * + * @param str 字符串 + * @param fractionNum 小数部分的最多允许的位数 + * @return 若为整数或浮点数则返回 true, 否则返回 false + */ + public static boolean isNumeric(String str, int fractionNum) { + if (isEmpty(str)) { + return false; + } + + // 整数或浮点数 + String regex = "(\\+|-)?(\\d+)([.]?)(\\d{0," + fractionNum + "})"; + return Pattern.matches(regex, str); + } + + /** + *

+ * Validating for phone number. + *

+ *

+ * e.g.

  • 78674585 --> valid
  • 6872-4585 --> valid
  • (6872)4585 --> valid
  • 0086-10-6872-4585 + * --> valid
  • 0086-(10)-6872-4585 --> invalid
  • 0086(10)68724585 --> invalid
  • + * + * @param str string to be validated + * @return If the str is valid phone number return true, otherwise return false. + */ + public static boolean isPhoneNumber(String str) { + // Regex for checking phone number + return isRegexMatch(str, REGEX_PHONE_NUMBER); + } + + /** + * 判断是否是合法的邮编 + * + * @param str 字符串 + * @return true/false + */ + public static boolean isPostcode(String str) { + if (isEmpty(str)) { + return false; + } + + if (str.length() != 6 || !isNumber(str)) { + return false; + } + + return true; + } + + /** + * 判断是否是固定长度范围内的字符串 + * + * @param str + * @param minLength + * @param maxLength + * @return true/false + */ + public static boolean isString(String str, int minLength, int maxLength) { + if (str == null) { + return false; + } + + if (minLength < 0) { + return str.length() <= maxLength; + } else if (maxLength < 0) { + return str.length() >= minLength; + } else { + return str.length() >= minLength && str.length() <= maxLength; + } + } + + /** + * 判断是否是合法的时间字符串。 + * + * @param str 字符串 + * @return true/false + */ + public static boolean isTime(String str) { + if (isEmpty(str) || str.length() > 8) { + return false; + } + + String[] items = str.split(":"); + + if (items.length != 2 && items.length != 3) { + return false; + } + + for (int i = 0; i < items.length; i++) { + if (items[i].length() != 2 && items[i].length() != 1) { + return false; + } + } + + return !(!isNumber(items[0], 0, 23) || !isNumber(items[1], 0, 59) || (items.length == 3 && !isNumber(items[2], + 0, 59))); + } + + /** + * 是否是简体中文字符串。 + * + * @param str 字符串 + * @return true/false + */ + public static boolean isSimpleChinese(String str) { + return isRegexMatch(str, REGEX_SIMPLE_CHINESE); + } + + /** + * 判断字符串是否匹配了正则表达式。 + * + * @param str 字符串 + * @param regex 正则表达式 + * @return true/false + */ + public static boolean isRegexMatch(String str, String regex) { + return str != null && str.matches(regex); + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/ChangeCharset.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/ChangeCharset.java new file mode 100644 index 0000000..d920b88 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/ChangeCharset.java @@ -0,0 +1,132 @@ +package com.lfk.justweengine.utils.webServer; + +import java.io.UnsupportedEncodingException; + +/** + * 转换字符串的编码 + */ +public class ChangeCharset { + /** + * 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 + */ + public static final String US_ASCII = "US-ASCII"; + + /** + * ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1 + */ + public static final String ISO_8859_1 = "ISO-8859-1"; + + /** + * 8 位 UCS 转换格式 + */ + public static final String UTF_8 = "UTF-8"; + + /** + * 16 位 UCS 转换格式,Big Endian(最低地址存放高位字节)字节顺序 + */ + public static final String UTF_16BE = "UTF-16BE"; + + /** + * 16 位 UCS 转换格式,Little-endian(最高地址存放低位字节)字节顺序 + */ + public static final String UTF_16LE = "UTF-16LE"; + + /** + * 16 位 UCS 转换格式,字节顺序由可选的字节顺序标记来标识 + */ + public static final String UTF_16 = "UTF-16"; + + /** + * 中文超大字符集 + */ + public static final String GBK = "GBK"; + + /** + * 将字符编码转换成US-ASCII码 + */ + public static String toASCII(String str) throws UnsupportedEncodingException { + return changeCharset(str, US_ASCII); + } + + /** + * 将字符编码转换成ISO-8859-1码 + */ + public static String toISO_8859_1(String str) throws UnsupportedEncodingException { + return changeCharset(str, ISO_8859_1); + } + + /** + * 将字符编码转换成UTF-8码 + */ + public static String toUTF_8(String str) throws UnsupportedEncodingException { + return changeCharset(str, UTF_8); + } + + /** + * 将字符编码转换成UTF-16BE码 + */ + public static String toUTF_16BE(String str) throws UnsupportedEncodingException { + return changeCharset(str, UTF_16BE); + } + + /** + * 将字符编码转换成UTF-16LE码 + */ + public static String toUTF_16LE(String str) throws UnsupportedEncodingException { + return changeCharset(str, UTF_16LE); + } + + /** + * 将字符编码转换成UTF-16码 + */ + public static String toUTF_16(String str) throws UnsupportedEncodingException { + return changeCharset(str, UTF_16); + } + + /** + * 将字符编码转换成GBK码 + */ + public static String toGBK(String str) throws UnsupportedEncodingException { + return changeCharset(str, GBK); + } + + /** + * 字符串编码转换的实现方法 + * + * @param str 待转换编码的字符串 + * @param newCharset 目标编码 + * @return + * @throws UnsupportedEncodingException + */ + public static String changeCharset(String str, String newCharset) + throws UnsupportedEncodingException { + if (str != null) { + //用默认字符编码解码字符串。 + byte[] bs = str.getBytes(); + //用新的字符编码生成字符串 + return new String(bs, newCharset); + } + return null; + } + + /** + * 字符串编码转换的实现方法 + * + * @param str 待转换编码的字符串 + * @param oldCharset 原编码 + * @param newCharset 目标编码 + * @return + * @throws UnsupportedEncodingException + */ + public static String changeCharset(String str, String oldCharset, String newCharset) + throws UnsupportedEncodingException { + if (str != null) { + // 用旧的字符编码解码字符串。解码可能会出现异常。 + byte[] bs = str.getBytes(oldCharset); + // 用新的字符编码生成字符串 + return new String(bs, newCharset); + } + return null; + } + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnLogResult.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnLogResult.java new file mode 100644 index 0000000..18a7d1b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnLogResult.java @@ -0,0 +1,23 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +/** + * OnLogResult 接收Log信息和Error信息 + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public interface OnLogResult { + /** + * OnResult 接收Log信息 + * + * @param log log信息 + */ + void OnResult(String log); + + /** + * OnError Error信息 + * + * @param error error信息 + */ + void OnError(String error); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPermissionFile.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPermissionFile.java new file mode 100644 index 0000000..b00f1b0 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPermissionFile.java @@ -0,0 +1,14 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +import java.io.File; + +/** + * OnPermissionFile set permission path, + * the path's all father paths can get. + * + * @author liufengkai + * Created by liufengkai on 16/1/14. + */ +public interface OnPermissionFile extends OnWebResult { + File OnPermissionFile(String name); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPostData.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPostData.java new file mode 100644 index 0000000..b84561d --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnPostData.java @@ -0,0 +1,17 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +import java.util.HashMap; + +/** + * OnPostData get post data + * Created by liufengkai on 16/1/14. + */ +public interface OnPostData extends OnWebResult { + /** + * get post data + * + * @param hashMap return post data + * @return return state code + */ + String OnPostData(HashMap hashMap); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebFileResult.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebFileResult.java new file mode 100644 index 0000000..fce1c06 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebFileResult.java @@ -0,0 +1,18 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +import java.io.File; + +/** + * OnWebFileResult return file + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public interface OnWebFileResult extends OnWebResult { + /** + * return file + * + * @return such as : html / js / css and other file + */ + File returnFile(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebResult.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebResult.java new file mode 100644 index 0000000..96b3e1b --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebResult.java @@ -0,0 +1,11 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +/** + * OnWebResult empty interface for result + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public interface OnWebResult { + +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebStringResult.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebStringResult.java new file mode 100644 index 0000000..f4c3812 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Interface/OnWebStringResult.java @@ -0,0 +1,11 @@ +package com.lfk.justweengine.utils.webServer.Interface; + +/** + * OnWebStringResult easy method for return string + * + * @author liufengkai + * Created by liufengkai on 16/1/14. + */ +public interface OnWebStringResult extends OnWebResult { + String OnResult(); +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/RequestSolve.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/RequestSolve.java new file mode 100644 index 0000000..9cd7097 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/RequestSolve.java @@ -0,0 +1,183 @@ +package com.lfk.justweengine.utils.webServer; + +import com.lfk.justweengine.utils.webServer.Interface.OnPostData; +import com.lfk.justweengine.utils.webServer.Interface.OnWebFileResult; +import com.lfk.justweengine.utils.webServer.Interface.OnWebResult; +import com.lfk.justweengine.utils.webServer.Interface.OnWebStringResult; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.util.HashMap; + +/** + * Solve request + * + * @author liufengkai + * Created by liufengkai on 16/1/14. + */ +public class RequestSolve extends Thread { + private Socket client; + private BufferedReader clientReader; + // url in link + private String url; + private HashMap params; + // private String urlName = ""; + private int type; + + public RequestSolve(Socket s) { + super(); + this.client = s; + + } + + @Override + public void run() { + super.run(); + try { + clientReader = new BufferedReader( + new InputStreamReader(client.getInputStream(), "UTF-8")); + + while (true) { + String s = clientReader.readLine().trim(); + + if (s.equals("")) { + break; + } + +// Logger.e(s + '\n'); + Servers.getLogResult().OnResult(s); + + int httpHeader = s.indexOf(" HTTP/"); + switch (s.substring(0, 4)) { + case "GET ": + // get request link + url = s.substring(4, httpHeader); + Servers.getLogResult().OnResult("visiting" + url); + break; + case "POST": + int last = s.indexOf('?'); + params = new HashMap<>(); + if (last > 0) { + url = s.substring(5, last); + getParams(s.substring(last + 1, httpHeader)); + } else + url = s.substring(5, httpHeader); + break; + } + } + } catch (IOException e) { + e.printStackTrace(); + Servers.getLogResult().OnError(e.getMessage()); + } + + exeResult(url); + } + + private void exeResult(String Url) { + OnWebResult result = WebServer.getRule(Url); + if (result != null) { + if (result instanceof OnWebStringResult) { + returnString(((OnWebStringResult) result).OnResult()); + } else if (result instanceof OnWebFileResult) { + returnFile(((OnWebFileResult) result).returnFile()); + } else if (result instanceof OnPostData) { + returnString(((OnPostData) result).OnPostData(params)); + } + } else { + // 在新的权限管理之前,先允许所有服务器根目录下的文件访问 + File file = new File(WebServerDefault.WebServerFiles + Url); + if (file.exists()) { + returnFile(file); + } + } + } + +// private void findChildFile(String Url) { +// int index = Url.lastIndexOf('/'); +// if (index != -1) { +// Log.d("index", Url.lastIndexOf('/') + ""); +// // 仍能逐层递减 +// if (index == 0) { +// exeResult("/"); +// urlName = "/" + urlName; +// return; +// } +// +// exeResult(Url.substring(0, index)); +// urlName = Url.substring(index - 1) + urlName; +// } +// Logger.e("Url:" + Url.substring(0, Url.lastIndexOf('/'))); +// Logger.e("UrlName:" + Url.substring(Url.lastIndexOf('/') + 1)); +// } + + private void returnString(String str) { + try { + OutputStream o = client.getOutputStream(); + o.write(setType(getHeaderBase(), str.length(), "200 OK").getBytes()); + for (int i = 0; + i < str.length(); + i++) { + o.write(str.charAt(i)); + } + o.close(); + client.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void returnFile(File file) { + if (file.exists()) { + try { + BufferedInputStream inputStream = + new BufferedInputStream( + new FileInputStream(file)); + BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); + ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int count; + while ((count = inputStream.read(buf)) != -1) { + tempOut.write(buf, 0, count); + } + tempOut.flush(); + out.write(setType(getHeaderBase(), tempOut.size(), "200 OK").getBytes()); + out.write(tempOut.toByteArray()); + out.flush(); + client.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void getParams(String url) { + int valueFirst; + for (String s : url.split("&")) { + valueFirst = s.indexOf("="); + params.put(s.substring(0, valueFirst), + s.substring(valueFirst + 1)); + } + } + + private String getHeaderBase() { + return "HTTP/1.1 %code%\n" + + "Server: JustWe_WebServer/0.1\n" + + "Content-Length: %length%\n" + + "Connection: close\n" + + "Content-Type: text/html; charset=iso-8859-1\n\n"; + } + + private String setType(String str, double length, String TYPE) { + str = str.replace("%code%", TYPE); + str = str.replace("%length%", "" + length); + return str; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/Servers.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Servers.java new file mode 100644 index 0000000..40a0b4e --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/Servers.java @@ -0,0 +1,73 @@ +package com.lfk.justweengine.utils.webServer; + +import android.content.Context; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Thread Controller + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public class Servers extends Thread { + // listen to connect + private ServerSocket serverSocket; + // log / error handler listener + private static WebServer.MessageHandler logResult; + private Context context; + private boolean IsRunning; + // solve threads + private static ExecutorService exe; + + public Servers(Context context, WebServer.MessageHandler logResult, int port) { + super(); + this.context = context; + Servers.logResult = logResult; + this.IsRunning = true; + exe = Executors.newCachedThreadPool(); + try { + serverSocket = new ServerSocket(port, 0, + InetAddress.getByName(WebServerDefault.WebServerIp)); + logResult.OnResult("listen to :" + WebServerDefault.WebServerIp + + ":" + port); + } catch (IOException e) { + e.printStackTrace(); + logResult.OnError("Server IO error"); + } + } + + @Override + public void run() { + super.run(); + while (IsRunning) { + try { + logResult.OnResult("<<<<<<< waiting >>>>>>>"); + Socket s = serverSocket.accept(); + logResult.OnResult("get from" + s.getInetAddress().toString()); + exe.execute(new RequestSolve(s)); + } catch (IOException e) { + logResult.OnError(e.getMessage()); + } + } + } + + public void stopServer() { + IsRunning = false; + try { + serverSocket.close(); + logResult.OnResult("Server close"); + } catch (IOException e) { + logResult.OnError(e.getMessage()); + } + } + + public static WebServer.MessageHandler getLogResult() { + return logResult; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServer.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServer.java new file mode 100644 index 0000000..1797115 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServer.java @@ -0,0 +1,154 @@ +package com.lfk.justweengine.utils.webServer; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; + +import com.lfk.justweengine.utils.logger.Logger; +import com.lfk.justweengine.utils.webServer.Interface.OnLogResult; +import com.lfk.justweengine.utils.webServer.Interface.OnPermissionFile; +import com.lfk.justweengine.utils.webServer.Interface.OnWebResult; + +import java.io.File; +import java.util.HashMap; + +/** + * WebServer + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public class WebServer { + private Activity engine; + private static HashMap webServerRule; + private OnLogResult logResult; + private WebServerService webServerService; + private Integer webPort = null; + private ServiceConnection serviceConnection; + private final int ERROR = -1; + private final int LOG = 1; + + public WebServer(Activity engine) { + this.engine = engine; + init(); + } + + public WebServer(Activity engine, OnLogResult logResult) { + this.engine = engine; + this.logResult = logResult; + init(); + } + + public WebServer(Activity engine, OnLogResult logResult, int webPort) { + this.engine = engine; + this.logResult = logResult; + this.webPort = webPort; + init(); + } + + private void init() { + webServerRule = new HashMap<>(); + + WebServerService.init(engine); + + serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + webServerService = ((WebServerService.LocalBinder) service).getService(); + if (logResult != null) + logResult.OnResult(WebServerDefault.WebServerServiceConnected); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + webServerService = null; + if (logResult != null) + logResult.OnResult(WebServerDefault.WebServerServiceDisconnected); + } + }; + + } + + + public void startWebService() { + if (webServerService != null) { + webServerService.startServer(new MessageHandler(), + (webPort == null) ? WebServerDefault.WebDefaultPort : webPort); + } + } + + public void stopWebService() { + if (webServerService != null) { + webServerService.stopServer(); + } + } + + public void initWebService() { + WebServerDefault.init(engine.getApplicationContext()); + // 绑定Service + engine.bindService(new Intent(engine, WebServerService.class), + serviceConnection, + Context.BIND_AUTO_CREATE + ); + } + + public void callOffWebService() { + engine.unbindService(serviceConnection); + } + + public void apply(String rule, OnWebResult result) { + webServerRule.put(rule, result); + } + + public void apply(final String rule) { + webServerRule.put(rule, new OnPermissionFile() { + @Override + public File OnPermissionFile(String name) { + Logger.e(WebServerDefault.WebServerFiles + rule + name); + return new File(WebServerDefault.WebServerFiles + rule + name); + } + }); + } + + public static OnWebResult getRule(String rule) { + return webServerRule.get(rule); + } + + public void setLogResult(OnLogResult logResult) { + this.logResult = logResult; + } + + public class MessageHandler extends Handler { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case LOG: + logResult.OnResult(msg.obj.toString()); + break; + case ERROR: + logResult.OnError(msg.obj.toString()); + break; + } + } + + public void OnError(String str) { + Message message = this.obtainMessage(); + message.what = ERROR; + message.obj = str; + sendMessage(message); + } + + public void OnResult(String str) { + Message message = this.obtainMessage(); + message.what = LOG; + message.obj = str; + sendMessage(message); + } + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerDefault.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerDefault.java new file mode 100644 index 0000000..dae3c79 --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerDefault.java @@ -0,0 +1,59 @@ +package com.lfk.justweengine.utils.webServer; + +import android.content.Context; +import android.os.Environment; + +import java.io.File; + +/** + * WebServerDefault Default message about Web + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public class WebServerDefault { + // default file local + public static final String WebServerFiles = Environment + .getExternalStorageDirectory() + "/JustWeWebServer"; + + public static final String WebServerServiceConnected = "Service connected"; + + public static final String WebServerServiceDisconnected = "Service disconnected"; + + // default port + public static final int WebDefaultPort = 8080; + + public static String getWebServerFiles() { + return WebServerFiles; + } + + // get local IP + public static String WebServerIp; + + public static Context context; + + public static void init(Context context) { + WebServerDefault.context = context; + File file = new File(WebServerFiles); + if (!file.exists()) { + file.mkdirs(); + } + } + + /** + * translate int to IP + * + * @param i Ip int + * @return IP + */ + public static String intToIp(int i) { + return ((i) & 0xFF) + "." + + ((i >> 8) & 0xFF) + "." + + ((i >> 16) & 0xFF) + "." + + (i >> 24 & 0xFF); + } + + public static void setWebServerIp(String webServerIp) { + WebServerIp = webServerIp; + } +} diff --git a/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerService.java b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerService.java new file mode 100644 index 0000000..9e292eb --- /dev/null +++ b/engine/src/main/java/com/lfk/justweengine/utils/webServer/WebServerService.java @@ -0,0 +1,137 @@ +package com.lfk.justweengine.utils.webServer; + +import android.app.Activity; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.net.wifi.SupplicantState; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.IBinder; + +import com.lfk.justweengine.R; + + +/** + * WebServerService for Android + * + * @author liufengkai + * Created by liufengkai on 16/1/6. + */ +public class WebServerService extends Service { + // threads translate through this handler + private WebServer.MessageHandler logResult; + // two follows about notification + private NotificationManager notificationManager; + private Notification notification; + private final IBinder mBinder = new LocalBinder(); + // socket thread object + private Servers webServers; + // engine context + private static Activity engine; + private PendingIntent contentIntent; + private boolean IsRunning; + + @Override + public void onCreate() { + super.onCreate(); + + notificationManager = (NotificationManager) + getSystemService(NOTIFICATION_SERVICE); + + updateNotification("Open Service"); + } + + public static void init(Activity engine) { + WebServerService.engine = engine; + } + + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** + * update notification + * + * @param text update message on notification + */ + private void updateNotification(String text) { + contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, engine.getClass()), 0); + Notification.Builder builder = new Notification.Builder(engine) + .setContentTitle("WebServer") + .setContentText(text) + .setContentIntent(contentIntent) + .setSmallIcon(R.mipmap.ic_launcher) + .setWhen(System.currentTimeMillis()); + notification = builder.getNotification(); + notificationManager.notify(0, notification); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + } + + public class LocalBinder extends Binder { + WebServerService getService() { + return WebServerService.this; + } + } + + /** + * start server + * + * @param logResult handler to translate message + * @param port port in socket + */ + public void startServer(WebServer.MessageHandler logResult, int port) { + this.logResult = logResult; + // running + setIsRunning(true); + + // get WifiManager + WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + + // set IP + WebServerDefault.setWebServerIp(WebServerDefault.intToIp(wifiInfo.getIpAddress())); + // if not in wifi + if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) { + this.logResult.OnError("Please connect to a WIFI-network."); + try { + throw new Exception("Please connect to a WIFI-network."); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Start socket thread + webServers = new Servers(engine.getApplicationContext(), logResult, port); + webServers.start(); + + updateNotification("running on " + + WebServerDefault.WebServerIp + ":" + port); + } + + public void stopServer() { + setIsRunning(false); + if (webServers != null) { + webServers.stopServer(); + webServers.interrupt(); + } + } + + public void setIsRunning(boolean isRunning) { + this.IsRunning = isRunning; + } + + public boolean isRunning() { + return IsRunning; + } +}