From 38b684bffe57d3025e93667575f0beef8e546065 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 1 Aug 2020 17:10:32 +0800 Subject: [PATCH 0001/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=20UI=20=E6=B5=8B=E8=AF=95=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9B=9E=E6=94=BE=E8=A7=A6=E5=B1=8F=E6=93=8D?= =?UTF-8?q?=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/demo/ui/UIAutoActivity.java | 115 ++++++++++++------ .../apijson/demo/ui/UIAutoListActivity.java | 1 + 2 files changed, 79 insertions(+), 37 deletions(-) diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java index 23805a966..d58da3aa9 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java @@ -23,6 +23,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; +import android.os.Message; import android.support.annotation.RequiresApi; import android.util.DisplayMetrics; import android.util.Log; @@ -76,6 +77,20 @@ public static Intent createIntent(Context context, String list) { return new Intent(context, UIAutoActivity.class).putExtra(INTENT_TOUCH_LIST, list); } + + private boolean isRecovering = false; + private Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + + if (isRecovering) { + MotionEvent event = (MotionEvent) msg.obj; + dispatchEventToCurrentActivity(event); + } + } + }; + private Activity context; int screenWidth; int screenHeight; @@ -108,11 +123,6 @@ protected void onCreate(Bundle savedInstanceState) { flowId = getIntent().getLongExtra(INTENT_FLOW_ID, flowId); touchList = JSON.parseArray(getIntent().getStringExtra(INTENT_TOUCH_LIST)); - if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 - - } else { //TODO 录制操作 - - } DisplayMetrics outMetrics = new DisplayMetrics(); Display display = getWindowManager().getDefaultDisplay(); @@ -126,6 +136,12 @@ protected void onCreate(Bundle savedInstanceState) { cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); dividerY = cache.getFloat(DIVIDER_Y, screenHeight - dip2px(30)); + if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 + recover(touchList); + return; + } + + ViewGroup root = (ViewGroup) getWindow().getDecorView(); cover = (ViewGroup) getLayoutInflater().inflate(R.layout.unit_auto_cover_layout, null); divider = (ViewGroup) getLayoutInflater().inflate(R.layout.unit_auto_divider_layout, null); @@ -166,6 +182,7 @@ protected void onCreate(Bundle savedInstanceState) { ivUnitAutoMenu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + isRecovering = false; // ((ViewGroup) v.getParent()).removeView(v); String cacheKey = UIAutoListActivity.CACHE_TOUCH; @@ -181,7 +198,7 @@ public void onClick(View v) { cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(allList)).commit(); // startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); - startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString())); + startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); FloatWindow.destroy("v"); FloatWindow.destroy("v_ball"); @@ -232,37 +249,7 @@ else if (event.getAction() == MotionEvent.ACTION_UP) { public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "onTouchEvent " + Calendar.getInstance().getTime().toLocaleString() + " action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY()); - Activity a = DemoApplication.getInstance().getCurrentActivity(); - if (a != null) { - View decorView = a.getWindow().getDecorView(); - float y = decorView.getY(); - float top = decorView.getTop(); - event.offsetLocation(0, decorView.getTop()); - View content = decorView.findViewById(android.R.id.content); - float cy = content.getY(); - float ctop = content.getTop(); - - Rect rectangle= new Rect(); - decorView.getWindowVisibleDisplayFrame(rectangle); - -// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); - - if (rectangle.top > 0) { - event = MotionEvent.obtain(event); - event.offsetLocation(0, rectangle.top); - } - a.dispatchTouchEvent(event); - - //放到 Application 中 have already added to window manager - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - showCover(true, a); - } - }, 1000); - } else { - //TODO 不是本 APP 的界面 - } + dispatchEventToCurrentActivity(event); if (touchList == null) { touchList = new JSONArray(); @@ -279,6 +266,9 @@ public void run() { obj.put("y", (int) relativeY); obj.put("dividerY", (int) dividerY); obj.put("time", System.currentTimeMillis()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); touchList.add(obj); if (isFinishing() || isDestroyed()) { @@ -476,6 +466,38 @@ private void showCover(boolean show, Activity activity) { } + public boolean dispatchEventToCurrentActivity(MotionEvent event) { + Activity a = DemoApplication.getInstance().getCurrentActivity(); + if (a != null) { + View decorView = a.getWindow().getDecorView(); + float y = decorView.getY(); + float top = decorView.getTop(); + event.offsetLocation(0, decorView.getTop()); + View content = decorView.findViewById(android.R.id.content); + float cy = content.getY(); + float ctop = content.getTop(); + + Rect rectangle= new Rect(); + decorView.getWindowVisibleDisplayFrame(rectangle); + +// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); + + if (rectangle.top > 0) { + event = MotionEvent.obtain(event); + event.offsetLocation(0, rectangle.top); + } + a.dispatchTouchEvent(event); + + return true; + } else { + //TODO 不是本 APP 的界面 + } + + return false; + } + + + /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ @@ -511,6 +533,24 @@ protected void onDestroy() { // } + public void recover(JSONArray touchList) { + isRecovering = true; + + JSONObject last = null; + for (int i = 0; i < touchList.size(); i++) { + JSONObject obj = touchList.getJSONObject(i); + + MotionEvent event = MotionEvent.obtain(obj.getIntValue("downTime"), obj.getIntValue("eventTime"), + obj.getIntValue("action"), obj.getIntValue("x"), obj.getIntValue("y"), obj.getIntValue("metaState")); + + Message msg = handler.obtainMessage(); + msg.obj = event; + handler.sendMessageDelayed(msg, last == null ? 0 : obj.getIntValue("eventTime") - last.getIntValue("eventTime")); + + last = obj; + } + } + public static final int REQUEST_UI_AUTO_LIST = 1; @Override @@ -523,6 +563,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_UI_AUTO_LIST) { JSONArray array = data == null ? null : JSON.parseArray(data.getStringExtra(UIAutoListActivity.RESULT_LIST)); + recover(array); Toast.makeText(context, "onActivityResult array = " + JSON.toJSONString(array), Toast.LENGTH_LONG).show(); //TODO 恢复 diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java index c8eb689cb..37ddb3b7d 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java @@ -265,6 +265,7 @@ public void send(View v) { } // Touch >>>>>>>>>>>>>>>>>>>>>>>>>>>>> request.setTag("Touch"); + pbUIAutoList.setVisibility(View.VISIBLE); HttpManager.getInstance().post(fullUrl, request.toString(), new HttpManager.OnHttpResponseListener() { @Override public void onHttpResponse(int requestCode, String resultJson, Exception e) { From 615414cbdf464ff1cc1fb12dfa77788be227969c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Aug 2020 16:17:51 +0800 Subject: [PATCH 0002/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=20UI=20=E6=B5=8B=E8=AF=95=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=B8=8D=E8=83=BD=E5=9B=9E=E6=94=BE=E6=BB=91?= =?UTF-8?q?=E5=8A=A8=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/apijson/demo/ui/TouchUtil.java | 25 ++ .../java/apijson/demo/ui/UIAutoActivity.java | 314 +++++++++++------- .../apijson/demo/ui/UIAutoListActivity.java | 14 +- ...er_layout.xml => ui_auto_cover_layout.xml} | 6 +- ..._layout.xml => ui_auto_divider_layout.xml} | 24 +- 5 files changed, 255 insertions(+), 128 deletions(-) create mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java rename APIJSON-Android/APIJSONTest/app/src/main/res/layout/{unit_auto_cover_layout.xml => ui_auto_cover_layout.xml} (89%) rename APIJSON-Android/APIJSONTest/app/src/main/res/layout/{unit_auto_divider_layout.xml => ui_auto_divider_layout.xml} (65%) diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java new file mode 100644 index 000000000..6a23d2b71 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java @@ -0,0 +1,25 @@ +package apijson.demo.ui; + +import android.view.MotionEvent; + +public class TouchUtil { + + public static String getActionName(int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + return "DOWN"; + case MotionEvent.ACTION_MOVE: + return "MOVE"; + case MotionEvent.ACTION_SCROLL: + return "SCROLL"; + case MotionEvent.ACTION_UP: + return "UP"; + case MotionEvent.ACTION_MASK: + return "MASK"; + case MotionEvent.ACTION_OUTSIDE: + return "OUTSIDE"; + default: + return "CANCEL"; + } + } +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java index d58da3aa9..75ca86080 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java @@ -18,7 +18,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; @@ -40,6 +39,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.yhao.floatwindow.FloatWindow; +import com.yhao.floatwindow.IFloatWindow; import com.yhao.floatwindow.MoveType; import java.util.Calendar; @@ -85,6 +85,11 @@ public void handleMessage(Message msg) { super.handleMessage(msg); if (isRecovering) { + if (lastCurTime >= System.currentTimeMillis()) { + isRecovering = false; + pbUIAutoDivider.setVisibility(View.GONE); + } + MotionEvent event = (MotionEvent) msg.obj; dispatchEventToCurrentActivity(event); } @@ -94,14 +99,18 @@ public void handleMessage(Message msg) { private Activity context; int screenWidth; int screenHeight; + int windowWidth; int windowHeight; + int windowY; ViewGroup cover; ViewGroup divider; - View rlUnitAutoDivider; - View vUnitAutoDivider; - View ivUnitAutoMenu; + View rlUIAutoDivider; + View vUIAutoDivider; + View ivUIAutoDivider; + View pbUIAutoDivider; + private float dividerY; private float dividerHeight; private boolean moved = false; @@ -129,12 +138,20 @@ protected void onCreate(Bundle savedInstanceState) { windowWidth = display.getWidth(); windowHeight = display.getHeight(); + windowY = getWindowY(this); display.getRealMetrics(outMetrics); screenWidth = outMetrics.widthPixels; screenHeight = outMetrics.heightPixels; + cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); - dividerY = cache.getFloat(DIVIDER_Y, screenHeight - dip2px(30)); + + dividerY = cache.getFloat(DIVIDER_Y, 0); + dividerHeight = cache.getFloat(DIVIDER_HEIGHT, dip2px(24)); + + if (dividerY <= dividerHeight || dividerY >= windowHeight - dividerHeight) { + dividerY = windowHeight - dividerHeight - dip2px(30); + } if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 recover(touchList); @@ -143,50 +160,51 @@ protected void onCreate(Bundle savedInstanceState) { ViewGroup root = (ViewGroup) getWindow().getDecorView(); - cover = (ViewGroup) getLayoutInflater().inflate(R.layout.unit_auto_cover_layout, null); - divider = (ViewGroup) getLayoutInflater().inflate(R.layout.unit_auto_divider_layout, null); + cover = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_cover_layout, null); + divider = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_divider_layout, null); - rlUnitAutoDivider = divider.findViewById(R.id.rlUnitAutoDivider); - vUnitAutoDivider = divider.findViewById(R.id.vUnitAutoDivider); - ivUnitAutoMenu = divider.findViewById(R.id.ivUnitAutoMenu); + rlUIAutoDivider = divider.findViewById(R.id.rlUIAutoDivider); + vUIAutoDivider = divider.findViewById(R.id.vUIAutoDivider); + ivUIAutoDivider = divider.findViewById(R.id.ivUIAutoDivider); + pbUIAutoDivider = divider.findViewById(R.id.pbUIAutoDivider); + pbUIAutoDivider.setVisibility(View.GONE); - dividerHeight = cache.getFloat(DIVIDER_HEIGHT, dip2px(24)); - ViewGroup.LayoutParams dividerLp = rlUnitAutoDivider.getLayoutParams(); + ViewGroup.LayoutParams dividerLp = rlUIAutoDivider.getLayoutParams(); if (dividerLp == null) { dividerLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) dividerHeight); } else { dividerLp.height = (int) dividerHeight; } - rlUnitAutoDivider.setLayoutParams(dividerLp); + rlUIAutoDivider.setLayoutParams(dividerLp); - cover.addView(divider); +// cover.addView(divider); -// rlUnitAutoDivider.post(new Runnable() { +// rlUIAutoDivider.post(new Runnable() { // @Override // public void run() { -// rlUnitAutoDivider.setY(dividerY - rlUnitAutoDivider.getHeight()/2); +// rlUIAutoDivider.setY(dividerY - rlUIAutoDivider.getHeight()/2); // cover.setVisibility(View.GONE); // } // }); - vUnitAutoDivider.setBackgroundColor(Color.parseColor(cache.getString(DIVIDER_COLOR, "#10000000"))); + vUIAutoDivider.setBackgroundColor(Color.parseColor(cache.getString(DIVIDER_COLOR, "#10000000"))); - ViewGroup.LayoutParams lineLp = ivUnitAutoMenu.getLayoutParams(); + ViewGroup.LayoutParams lineLp = ivUIAutoDivider.getLayoutParams(); if (lineLp == null) { lineLp = new RelativeLayout.LayoutParams((int) dividerHeight, (int) dividerHeight); } else { lineLp.width = lineLp.height = (int) dividerHeight; } - ivUnitAutoMenu.setLayoutParams(lineLp); + ivUIAutoDivider.setLayoutParams(lineLp); - ivUnitAutoMenu.setOnClickListener(new View.OnClickListener() { + ivUIAutoDivider.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { isRecovering = false; // ((ViewGroup) v.getParent()).removeView(v); String cacheKey = UIAutoListActivity.CACHE_TOUCH; - SharedPreferences cache = getSharedPreferences(UnitAutoActivity.TAG, Context.MODE_PRIVATE); + SharedPreferences cache = getSharedPreferences(UIAutoActivity.TAG, Context.MODE_PRIVATE); JSONArray allList = JSON.parseArray(cache.getString(cacheKey, null)); if (allList == null || allList.isEmpty()) { @@ -200,11 +218,13 @@ public void onClick(View v) { // startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); + floatCover = null; + floatDivider = null; FloatWindow.destroy("v"); FloatWindow.destroy("v_ball"); } }); - rlUnitAutoDivider.setOnTouchListener(new View.OnTouchListener() { + rlUIAutoDivider.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 都不动了 if (event.getY() - event.getRawY() >= 10) { @@ -218,7 +238,7 @@ public boolean onTouch(View v, MotionEvent event) { } else if (event.getAction() == MotionEvent.ACTION_UP) { if (! moved) { - ivUnitAutoMenu.performClick(); + ivUIAutoDivider.performClick(); } } } @@ -251,26 +271,6 @@ public boolean onTouch(View v, MotionEvent event) { dispatchEventToCurrentActivity(event); - if (touchList == null) { - touchList = new JSONArray(); - } - - float dividerY = rlUnitAutoDivider.getY() + rlUnitAutoDivider.getHeight()/2; - float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); - - JSONObject obj = new JSONObject(true); - obj.put("id", - System.currentTimeMillis()); - obj.put("flowId", flowId); - obj.put("action", event.getAction()); - obj.put("x", (int) event.getX()); - obj.put("y", (int) relativeY); - obj.put("dividerY", (int) dividerY); - obj.put("time", System.currentTimeMillis()); - obj.put("downTime", event.getDownTime()); - obj.put("eventTime", event.getEventTime()); - obj.put("metaState", event.getMetaState()); - touchList.add(obj); - if (isFinishing() || isDestroyed()) { // ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); // Activity runningActivity = activityManager.getRunningTasks(1).get(0); @@ -293,8 +293,10 @@ public boolean onTouch(View v, MotionEvent event) { s = ""; } + float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; + float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); - tvTouch.setText(Calendar.getInstance().getTime().toLocaleString() + " action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY() + "; relativeY: " + relativeY + "\n" + s); + tvTouch.setText(Calendar.getInstance().getTime().toLocaleString() + " " + TouchUtil.getActionName(event.getAction()) + "\nx:" + event.getX() + "; y:" + event.getY() + "; relativeY: " + relativeY + "; pointerCount: " + event.getPointerCount() + "\n" + s); // Toast.makeText(context, "vTouch.action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY(), Toast.LENGTH_SHORT).show(); //死循环 llTouch.dispatchTouchEvent(event); @@ -352,8 +354,8 @@ public void run() { public void onClick(View v) { Toast.makeText(context, "onClick BUTTON", Toast.LENGTH_SHORT).show(); - record(v); +// finish(); } public void toRemote(View v) { @@ -376,44 +378,55 @@ public void record(View v) { + private IFloatWindow floatCover; + private IFloatWindow floatDivider; + private void showCover(boolean show, Activity activity) { //TODO 为纵屏、横屏分别加两套,判断屏幕方向来显示对应的一套 - rlUnitAutoDivider.setVisibility(show ? View.VISIBLE : View.GONE); - rlUnitAutoDivider.setY(dividerY + dividerHeight/2); +// rlUIAutoDivider.setVisibility(show ? View.VISIBLE : View.GONE); +// rlUIAutoDivider.setY(dividerY + dividerHeight/2); - if (FloatWindow.get("v")== null) { + floatCover = FloatWindow.get("v"); + if (floatCover == null) { FloatWindow .with(getApplicationContext()) .setTag("v") .setView(cover) - .setWidth(screenWidth) //设置控件宽高 - .setHeight(screenHeight) + .setWidth(windowWidth) //设置控件宽高 + .setHeight(windowHeight) .setX(0) //设置控件初始位置 - .setY(0) + .setY(windowY) .setMoveType(MoveType.inactive) - .setDesktopShow(true) //桌面显示 + .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 // .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 // .setPermissionListener(mPermissionListener) //监听权限申请结果 .build(); + + floatCover = FloatWindow.get("v"); } -// -// -// if (FloatWindow.get("v_ball") == null) { -// FloatWindow -// .with(getApplicationContext()) -// .setTag("v_ball") -// .setView(divider) -// .setWidth(screenWidth) //设置控件宽高 -// .setHeight((int) dividerHeight) -// .setX(0) //设置控件初始位置 -// .setY((int) (dividerY + dividerHeight/2)) -//// .setY(screenHeight/2) -// .setMoveType(MoveType.slide) -// .setDesktopShow(true) //桌面显示 -//// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 -//// .setPermissionListener(mPermissionListener) //监听权限申请结果 -// .build(); -// } + floatCover.show(); + + + floatDivider = FloatWindow.get("v_ball"); + if (floatDivider == null) { + FloatWindow + .with(getApplicationContext()) + .setTag("v_ball") + .setView(divider) + .setWidth(windowWidth) //设置控件宽高 + .setHeight((int) dividerHeight) + .setX(0) //设置控件初始位置 + .setY((int) (windowY + dividerY - dividerHeight/2)) +// .setY(screenHeight/2) + .setMoveType(MoveType.slide) + .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 +// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +// .setPermissionListener(mPermissionListener) //监听权限申请结果 + .build(); + + floatDivider = FloatWindow.get("v_ball"); + } + floatDivider.show(); //TODO 新建一个 have already added to window manager @@ -450,50 +463,85 @@ private void showCover(boolean show, Activity activity) { // .build(); // } - FloatWindow.get("v").hide(); -// FloatWindow.get("v_ball").hide(); -// FloatWindow.get("h").hide(); -// FloatWindow.get("h_ball").hide(); - if (show) { - if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - FloatWindow.get("v").show(); +// FloatWindow.get("v").hide(); +//// FloatWindow.get("v_ball").hide(); +//// FloatWindow.get("h").hide(); +//// FloatWindow.get("h_ball").hide(); +// if (show) { +// if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { +// FloatWindow.get("v").show(); // FloatWindow.get("v_ball").show(); - } else { -// FloatWindow.get("h").show(); -// FloatWindow.get("h_ball").show(); - } - } +// } else { +//// FloatWindow.get("h").show(); +//// FloatWindow.get("h_ball").show(); +// } +// } } + public int getWindowY(Activity a) { + View decorView = a.getWindow().getDecorView(); + + Rect rectangle= new Rect(); + decorView.getWindowVisibleDisplayFrame(rectangle); + return rectangle.top; + } + public boolean dispatchEventToCurrentActivity(MotionEvent event) { Activity a = DemoApplication.getInstance().getCurrentActivity(); if (a != null) { - View decorView = a.getWindow().getDecorView(); - float y = decorView.getY(); - float top = decorView.getTop(); - event.offsetLocation(0, decorView.getTop()); - View content = decorView.findViewById(android.R.id.content); - float cy = content.getY(); - float ctop = content.getTop(); - - Rect rectangle= new Rect(); - decorView.getWindowVisibleDisplayFrame(rectangle); - // event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); +// +// float y = decorView.getY(); +// float top = decorView.getTop(); +// event.offsetLocation(0, decorView.getTop()); +// View content = decorView.findViewById(android.R.id.content); +// float cy = content.getY(); +// float ctop = content.getTop(); + + int windowY = getWindowY(a); - if (rectangle.top > 0) { + if (windowY > 0) { event = MotionEvent.obtain(event); - event.offsetLocation(0, rectangle.top); + event.offsetLocation(0, windowY); } a.dispatchTouchEvent(event); - return true; - } else { - //TODO 不是本 APP 的界面 } - return false; + +// float dividerY = rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2; + float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; + float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); + + JSONObject obj = new JSONObject(true); + obj.put("id", - System.currentTimeMillis()); + obj.put("flowId", flowId); + obj.put("action", event.getAction()); + obj.put("x", (int) event.getX()); + obj.put("y", (int) relativeY); + obj.put("dividerY", (int) dividerY); + obj.put("rawX", (int) event.getRawX()); + obj.put("rawY", (int) event.getRawY()); + obj.put("time", System.currentTimeMillis()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); + obj.put("size", event.getSize()); + obj.put("source", event.getSource()); + obj.put("pressure", event.getPressure()); + obj.put("deviceId", event.getDeviceId()); + obj.put("xPrecision", event.getXPrecision()); + obj.put("yPrecision", event.getYPrecision()); + obj.put("pointerCount", event.getPointerCount()); + obj.put("edgeFlags", event.getEdgeFlags()); + + if (touchList == null) { + touchList = new JSONArray(); + } + touchList.add(obj); + + return a != null; } @@ -516,7 +564,7 @@ public int px2dip(float pxValue) { @Override protected void onDestroy() { - cache.edit().remove(DIVIDER_Y).putFloat(DIVIDER_Y, rlUnitAutoDivider.getY() + rlUnitAutoDivider.getHeight()/2).apply(); + cache.edit().remove(DIVIDER_Y).putFloat(DIVIDER_Y, rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2).apply(); super.onDestroy(); } @@ -533,21 +581,54 @@ protected void onDestroy() { // } + private long firstTime = 0; + private long lastTime = 0; + private long firstCurTime = 0; + private long lastCurTime = 0; public void recover(JSONArray touchList) { isRecovering = true; - JSONObject last = null; - for (int i = 0; i < touchList.size(); i++) { - JSONObject obj = touchList.getJSONObject(i); - - MotionEvent event = MotionEvent.obtain(obj.getIntValue("downTime"), obj.getIntValue("eventTime"), - obj.getIntValue("action"), obj.getIntValue("x"), obj.getIntValue("y"), obj.getIntValue("metaState")); - - Message msg = handler.obtainMessage(); - msg.obj = event; - handler.sendMessageDelayed(msg, last == null ? 0 : obj.getIntValue("eventTime") - last.getIntValue("eventTime")); + showCover(true, DemoApplication.getInstance().getCurrentActivity()); + + JSONObject first = touchList == null || touchList.isEmpty() ? null : touchList.getJSONObject(0); + firstTime = first == null ? 0 : first.getLongValue("time"); + + firstCurTime = 0; + if (firstTime > 0) { + firstCurTime = System.currentTimeMillis(); + pbUIAutoDivider.setVisibility(View.VISIBLE); + + for (int i = 0; i < touchList.size(); i++) { + JSONObject obj = touchList.getJSONObject(i); + + MotionEvent event = MotionEvent.obtain( + obj.getLongValue("downTime"), + obj.getLongValue("eventTime"), + obj.getIntValue("action"), +// obj.getIntValue("pointerCount"), + obj.getFloatValue("x"), + obj.getFloatValue("y"), + obj.getFloatValue("pressure"), + obj.getFloatValue("size"), + obj.getIntValue("metaState"), + obj.getFloatValue("xPrecision"), + obj.getFloatValue("yPrecision"), + obj.getIntValue("deviceId"), + obj.getIntValue("edgeFlags") + ); + event.setSource(obj.getIntValue("source")); +// event.setEdgeFlags(obj.getIntValue("edgeFlags")); + + long time = obj.getIntValue("time"); + if (i >= touchList.size() - 1) { + lastTime = time; + lastCurTime = firstCurTime + lastTime - firstTime; + } - last = obj; + Message msg = handler.obtainMessage(); + msg.obj = event; + handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); + } } } @@ -563,10 +644,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_UI_AUTO_LIST) { JSONArray array = data == null ? null : JSON.parseArray(data.getStringExtra(UIAutoListActivity.RESULT_LIST)); - recover(array); + finish(); - Toast.makeText(context, "onActivityResult array = " + JSON.toJSONString(array), Toast.LENGTH_LONG).show(); - //TODO 恢复 + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + touchList = new JSONArray(); + recover(array); + } + }, 1000); } } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java index 37ddb3b7d..e9494b649 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java @@ -105,6 +105,7 @@ public static Intent createIntent(Context context, String touchList) { private Button btnUIAutoListGet; SharedPreferences cache; + String cacheKey; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -119,8 +120,8 @@ protected void onCreate(Bundle savedInstanceState) { isTouch = flowId > 0 || hasTempTouchList; cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); + cacheKey = isTouch ? CACHE_TOUCH : CACHE_FLOW; if (isLocal) { - String cacheKey = isTouch ? CACHE_TOUCH : CACHE_FLOW; JSONArray allList = JSON.parseArray(cache.getString(cacheKey, null)); if (hasTempTouchList) { @@ -227,8 +228,8 @@ public void run() { } if (isTouch) { - list.add("[" + state + "]" + " action: " + obj.getString("action") + ", time: " + new Date(obj.getLongValue("time")).toLocaleString() - + "\nx: " + obj.getString("x") + ", y: " + obj.getString("y") + ", dividerY: " + obj.getString("dividerY")); + list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) + + "\nx: " + obj.getString("x") + ", y: " + obj.getString("y") + ", dividerY: " + obj.getString("dividerY") + ", pointerCount: " + obj.getString("pointerCount")); } else { list.add("[" + state + "]" + " name: " + obj.getString("name") + ", time: " + new Date(obj.getLongValue("time")).toLocaleString()); } @@ -240,12 +241,19 @@ public void run() { }).start(); } + + private Map statueList = new HashMap(); public void send(View v) { final String fullUrl = StringUtil.getTrimedString(etUIAutoListUrl) + StringUtil.getString((TextView) v).toLowerCase(); pbUIAutoList.setVisibility(View.VISIBLE); + if (hasTempTouchList == false) { + hasTempTouchList = true; + cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(touchList)).apply(); + } + if (isLocal) { statueList = new HashMap<>(); diff --git a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_cover_layout.xml b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_cover_layout.xml similarity index 89% rename from APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_cover_layout.xml rename to APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_cover_layout.xml index 56c20aea3..ac237c759 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_cover_layout.xml +++ b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_cover_layout.xml @@ -8,7 +8,7 @@ > - + @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_divider_layout.xml b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_divider_layout.xml similarity index 65% rename from APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_divider_layout.xml rename to APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_divider_layout.xml index 21e42635a..6b6f4a6e1 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_divider_layout.xml +++ b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/ui_auto_divider_layout.xml @@ -1,7 +1,7 @@ + + \ No newline at end of file From d1d06822fc40bd40c857ad1893401943c1be4c93 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Aug 2020 16:56:52 +0800 Subject: [PATCH 0003/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=20UI=20=E6=B5=8B=E8=AF=95=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E5=9B=9E=E6=94=BE=E7=AC=AC=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E6=BB=91=E5=8A=A8=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/demo/ui/UIAutoActivity.java | 68 +++++++++++++++++-- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java index 75ca86080..30344b5b9 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java @@ -43,6 +43,8 @@ import com.yhao.floatwindow.MoveType; import java.util.Calendar; +import java.util.LinkedList; +import java.util.List; import apijson.demo.R; import apijson.demo.application.DemoApplication; @@ -85,13 +87,29 @@ public void handleMessage(Message msg) { super.handleMessage(msg); if (isRecovering) { - if (lastCurTime >= System.currentTimeMillis()) { + //通过遍历数组来实现 +// if (lastCurTime >= System.currentTimeMillis()) { +// isRecovering = false; +// pbUIAutoDivider.setVisibility(View.GONE); +// } +// +// MotionEvent event = (MotionEvent) msg.obj; +// dispatchEventToCurrentActivity(event); + + + //根据递归链表来实现,能精准地实现两个事件之间的间隔,不受处理时间不一致,甚至卡顿等影响。还能及时终止 + Node eventNode = ( Node) msg.obj; + dispatchEventToCurrentActivity(eventNode.item); + + if (eventNode.next == null) { isRecovering = false; pbUIAutoDivider.setVisibility(View.GONE); + return; } - MotionEvent event = (MotionEvent) msg.obj; - dispatchEventToCurrentActivity(event); + msg = Message.obtain(); + msg.obj = eventNode.next; + sendMessageDelayed(msg, eventNode.next.item.getEventTime() - eventNode.item.getEventTime()); } } }; @@ -581,6 +599,9 @@ protected void onDestroy() { // } + private Node firstEventNode; + private Node eventNode; + private long firstTime = 0; private long lastTime = 0; private long firstCurTime = 0; @@ -588,6 +609,8 @@ protected void onDestroy() { public void recover(JSONArray touchList) { isRecovering = true; + List list = new LinkedList<>(); + showCover(true, DemoApplication.getInstance().getCurrentActivity()); JSONObject first = touchList == null || touchList.isEmpty() ? null : touchList.getJSONObject(0); @@ -619,16 +642,32 @@ public void recover(JSONArray touchList) { event.setSource(obj.getIntValue("source")); // event.setEdgeFlags(obj.getIntValue("edgeFlags")); + list.add(event); + long time = obj.getIntValue("time"); - if (i >= touchList.size() - 1) { + if (i <= 0) { + firstEventNode = new Node<>(null, event, null); + eventNode = firstEventNode; + } + else if (i >= touchList.size() - 1) { lastTime = time; lastCurTime = firstCurTime + lastTime - firstTime; } - Message msg = handler.obtainMessage(); - msg.obj = event; - handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); + eventNode.next = new Node<>(eventNode, event, null); + eventNode = eventNode.next; + + //通过遍历数组来实现 +// Message msg = handler.obtainMessage(); +// msg.obj = event; +// handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); } + + //通过递归链表来实现 + Message msg = handler.obtainMessage(); + msg.obj = firstEventNode; + handler.sendMessage(msg); + } } @@ -656,5 +695,20 @@ public void run() { } } + + + + private static class Node { + E item; + Node next; + Node prev; + + Node(Node prev, E element, Node next) { + this.item = element; + this.next = next; + this.prev = prev; + } + } + } From 4acfd0bc208da0a91c97ac84e46017e02e1d6fed Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Aug 2020 19:17:03 +0800 Subject: [PATCH 0004/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=20UI=20=E6=B5=8B=E8=AF=95=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AE=B0=E5=BD=95=E5=92=8C=E5=9B=9E=E6=94=BE?= =?UTF-8?q?=E6=8C=89=E9=94=AE=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/demo/ui/TouchLayout.java | 30 ++ .../main/java/apijson/demo/ui/TouchUtil.java | 14 + .../java/apijson/demo/ui/UIAutoActivity.java | 288 +++++++++++++----- .../apijson/demo/ui/UIAutoListActivity.java | 14 +- 4 files changed, 275 insertions(+), 71 deletions(-) diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchLayout.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchLayout.java index 0447c63e2..a28022fef 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchLayout.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchLayout.java @@ -6,6 +6,7 @@ import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; +import android.view.KeyEvent; import android.view.MotionEvent; import android.widget.RelativeLayout; @@ -45,4 +46,33 @@ public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); return false; } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + super.onKeyDown(keyCode, event); + + return false; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + super.onKeyUp(keyCode, event); + + return false; + } + + + + private static class Node { + E item; + Node next; + Node prev; + + Node(Node prev, E element, Node next) { + this.item = element; + this.next = next; + this.prev = prev; + } + } + } \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java index 6a23d2b71..ad8d53ebc 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java @@ -1,5 +1,7 @@ package apijson.demo.ui; +import android.content.res.Configuration; +import android.view.KeyEvent; import android.view.MotionEvent; public class TouchUtil { @@ -22,4 +24,16 @@ public static String getActionName(int action) { return "CANCEL"; } } + + public static String getOrientationName(int orientation) { + return orientation == Configuration.ORIENTATION_LANDSCAPE ? "HORIZONTAL" : "VERTICAL"; + } + + public static String getKeyCodeName(int keyCode) { + return KeyEvent.keyCodeToString(keyCode); + } + + public static String getScanCodeName(int scanCode) { + return "" + scanCode; //它是 hardware key id KeyEvent.keyCodeToString(scanCode); + } } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java index 30344b5b9..eebaddfa4 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java @@ -18,6 +18,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; @@ -27,6 +28,8 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; +import android.view.InputEvent; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -43,8 +46,6 @@ import com.yhao.floatwindow.MoveType; import java.util.Calendar; -import java.util.LinkedList; -import java.util.List; import apijson.demo.R; import apijson.demo.application.DemoApplication; @@ -98,7 +99,7 @@ public void handleMessage(Message msg) { //根据递归链表来实现,能精准地实现两个事件之间的间隔,不受处理时间不一致,甚至卡顿等影响。还能及时终止 - Node eventNode = ( Node) msg.obj; + Node eventNode = ( Node) msg.obj; dispatchEventToCurrentActivity(eventNode.item); if (eventNode.next == null) { @@ -172,8 +173,9 @@ protected void onCreate(Bundle savedInstanceState) { } if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 - recover(touchList); - return; +// recover(touchList); + startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); +// return; } @@ -234,7 +236,8 @@ public void onClick(View v) { cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(allList)).commit(); // startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); - startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); +// startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); + startActivity(UIAutoActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString())); floatCover = null; floatDivider = null; @@ -505,10 +508,10 @@ public int getWindowY(Activity a) { return rectangle.top; } - public boolean dispatchEventToCurrentActivity(MotionEvent event) { - Activity a = DemoApplication.getInstance().getCurrentActivity(); - if (a != null) { -// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); + public boolean dispatchEventToCurrentActivity(InputEvent ie) { + Activity activity = DemoApplication.getInstance().getCurrentActivity(); + if (activity != null) { +// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); // // float y = decorView.getY(); // float top = decorView.getTop(); @@ -517,49 +520,53 @@ public boolean dispatchEventToCurrentActivity(MotionEvent event) { // float cy = content.getY(); // float ctop = content.getTop(); - int windowY = getWindowY(a); + if (ie instanceof MotionEvent) { + MotionEvent event = (MotionEvent) ie; + int windowY = getWindowY(activity); - if (windowY > 0) { - event = MotionEvent.obtain(event); - event.offsetLocation(0, windowY); + if (windowY > 0) { + event = MotionEvent.obtain(event); + event.offsetLocation(0, windowY); + } + activity.dispatchTouchEvent(event); + } + else if (ie instanceof KeyEvent) { + KeyEvent event = (KeyEvent) ie; + activity.dispatchKeyEvent(event); } - a.dispatchTouchEvent(event); } -// float dividerY = rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2; - float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; - float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); - - JSONObject obj = new JSONObject(true); - obj.put("id", - System.currentTimeMillis()); - obj.put("flowId", flowId); - obj.put("action", event.getAction()); - obj.put("x", (int) event.getX()); - obj.put("y", (int) relativeY); - obj.put("dividerY", (int) dividerY); - obj.put("rawX", (int) event.getRawX()); - obj.put("rawY", (int) event.getRawY()); - obj.put("time", System.currentTimeMillis()); - obj.put("downTime", event.getDownTime()); - obj.put("eventTime", event.getEventTime()); - obj.put("metaState", event.getMetaState()); - obj.put("size", event.getSize()); - obj.put("source", event.getSource()); - obj.put("pressure", event.getPressure()); - obj.put("deviceId", event.getDeviceId()); - obj.put("xPrecision", event.getXPrecision()); - obj.put("yPrecision", event.getYPrecision()); - obj.put("pointerCount", event.getPointerCount()); - obj.put("edgeFlags", event.getEdgeFlags()); - - if (touchList == null) { - touchList = new JSONArray(); - } - touchList.add(obj); - - return a != null; +// float dividerY = rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2; +// float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; +// float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); +// +// JSONObject obj = new JSONObject(true); +// obj.put("id", - System.currentTimeMillis()); +// obj.put("flowId", flowId); +// obj.put("action", event.getAction()); +// obj.put("x", (int) event.getX()); +// obj.put("y", (int) relativeY); +// obj.put("dividerY", (int) dividerY); +// obj.put("rawX", (int) event.getRawX()); +// obj.put("rawY", (int) event.getRawY()); +// obj.put("time", System.currentTimeMillis()); +// obj.put("downTime", event.getDownTime()); +// obj.put("eventTime", event.getEventTime()); +// obj.put("metaState", event.getMetaState()); +// obj.put("size", event.getSize()); +// obj.put("source", event.getSource()); +// obj.put("pressure", event.getPressure()); +// obj.put("deviceId", event.getDeviceId()); +// obj.put("xPrecision", event.getXPrecision()); +// obj.put("yPrecision", event.getYPrecision()); +// obj.put("pointerCount", event.getPointerCount()); +// obj.put("edgeFlags", event.getEdgeFlags()); + + addInputEvent(ie, activity); + + return activity != null; } @@ -599,8 +606,8 @@ protected void onDestroy() { // } - private Node firstEventNode; - private Node eventNode; + private Node firstEventNode; + private Node eventNode; private long firstTime = 0; private long lastTime = 0; @@ -609,7 +616,7 @@ protected void onDestroy() { public void recover(JSONArray touchList) { isRecovering = true; - List list = new LinkedList<>(); +// List list = new LinkedList<>(); showCover(true, DemoApplication.getInstance().getCurrentActivity()); @@ -624,25 +631,83 @@ public void recover(JSONArray touchList) { for (int i = 0; i < touchList.size(); i++) { JSONObject obj = touchList.getJSONObject(i); - MotionEvent event = MotionEvent.obtain( - obj.getLongValue("downTime"), - obj.getLongValue("eventTime"), - obj.getIntValue("action"), -// obj.getIntValue("pointerCount"), - obj.getFloatValue("x"), - obj.getFloatValue("y"), - obj.getFloatValue("pressure"), - obj.getFloatValue("size"), - obj.getIntValue("metaState"), - obj.getFloatValue("xPrecision"), - obj.getFloatValue("yPrecision"), - obj.getIntValue("deviceId"), - obj.getIntValue("edgeFlags") - ); - event.setSource(obj.getIntValue("source")); -// event.setEdgeFlags(obj.getIntValue("edgeFlags")); - - list.add(event); + InputEvent event; + if (obj.getIntValue("type") == 1) { + /** + public KeyEvent(long downTime, long eventTime, int action, + int code, int repeat, int metaState, + int deviceId, int scancode, int flags, int source) { + mDownTime = downTime; + mEventTime = eventTime; + mAction = action; + mKeyCode = code; + mRepeatCount = repeat; + mMetaState = metaState; + mDeviceId = deviceId; + mScanCode = scancode; + mFlags = flags; + mSource = source; + mDisplayId = INVALID_DISPLAY; + } + */ + event = new KeyEvent( + obj.getLongValue("downTime"), + obj.getLongValue("eventTime"), + obj.getIntValue("action"), + obj.getIntValue("keyCode"), + obj.getIntValue("repeatCount"), + obj.getIntValue("metaState"), + obj.getIntValue("deviceId"), + obj.getIntValue("scanCode"), + obj.getIntValue("flags"), + obj.getIntValue("source") + ); + } + else { + /** + public static MotionEvent obtain(long downTime, long eventTime, int action, + float x, float y, float pressure, float size, int metaState, + float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, + int displayId) + */ + + //居然编译报错,和 + // static public MotionEvent obtain(long downTime, long eventTime, + // int action, int pointerCount, PointerProperties[] pointerProperties, + // PointerCoords[] pointerCoords, int metaState, int buttonState, + // float xPrecision, float yPrecision, int deviceId, + // int edgeFlags, int source, int displayId, int flags) + //冲突,实际上类型没传错 + + // event = MotionEvent.obtain(obj.getLongValue("downTime"), obj.getLongValue("eventTime"), obj.getIntValue("action"), + // obj.getFloatValue("x"), obj.getFloatValue("y"), obj.getFloatValue("pressure"), obj.getFloatValue("size"), obj.getIntValue("metaState"), + // obj.getFloatValue("xPrecision"), obj.getFloatValue("yPrecision"), obj.getIntValue("deviceId"), obj.getIntValue("edgeFlags"), obj.getIntValue("source"), + // obj.getIntValue("displayId")); + + event = MotionEvent.obtain( + obj.getLongValue("downTime"), + obj.getLongValue("eventTime"), + obj.getIntValue("action"), +// obj.getIntValue("pointerCount"), + obj.getFloatValue("x"), + obj.getFloatValue("y"), + obj.getFloatValue("pressure"), + obj.getFloatValue("size"), + obj.getIntValue("metaState"), + obj.getFloatValue("xPrecision"), + obj.getFloatValue("yPrecision"), + obj.getIntValue("deviceId"), + obj.getIntValue("edgeFlags") +// obj.getIntValue("source"), +// obj.getIntValue("displayId") + ); + ((MotionEvent) event).setSource(obj.getIntValue("source")); +// ((MotionEvent) event).setEdgeFlags(obj.getIntValue("edgeFlags")); + + } + + +// list.add(event); long time = obj.getIntValue("time"); if (i <= 0) { @@ -671,6 +736,91 @@ else if (i >= touchList.size() - 1) { } } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + addInputEvent(event, this); + return super.onKeyDown(keyCode, event); + } + + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + addInputEvent(event, this); + return super.onKeyUp(keyCode, event); + } + + private JSONArray addInputEvent(InputEvent ie, Activity activity) { + int dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; + int orientation = activity == null ? Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; + + JSONObject obj = new JSONObject(true); + obj.put("id", - System.currentTimeMillis()); + obj.put("flowId", flowId); + obj.put("time", System.currentTimeMillis()); + obj.put("orientation", orientation); + obj.put("dividerY", dividerY); + + if (ie instanceof KeyEvent) { + KeyEvent event = (KeyEvent) ie; + obj.put("type", 1); + + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< + obj.put("action", event.getAction()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); + obj.put("source", event.getSource()); + obj.put("deviceId", event.getDeviceId()); + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> + + obj.put("keyCode", event.getKeyCode()); + obj.put("scanCode", event.getScanCode()); + obj.put("repeatCount", event.getRepeatCount()); + //通过 keyCode 获取的 obj.put("number", event.getNumber()); + obj.put("flags", event.getFlags()); + //通过 mMetaState 获取的 obj.put("modifiers", event.getModifiers()); + //通过 mKeyCode 获取的 obj.put("displayLabel", event.getDisplayLabel()); + //通过 mMetaState 获取的 obj.put("unicodeChar", event.getUnicodeChar()); + } + else if (ie instanceof MotionEvent) { + MotionEvent event = (MotionEvent) ie; + obj.put("type", 0); + + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< + obj.put("action", event.getAction()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); + obj.put("source", event.getSource()); + obj.put("deviceId", event.getDeviceId()); + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> + + float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); + + obj.put("x", (int) event.getX()); + obj.put("y", (int) relativeY); + obj.put("rawX", (int) event.getRawX()); + obj.put("rawY", (int) event.getRawY()); + obj.put("size", event.getSize()); + obj.put("pressure", event.getPressure()); + obj.put("xPrecision", event.getXPrecision()); + obj.put("yPrecision", event.getYPrecision()); + obj.put("pointerCount", event.getPointerCount()); + obj.put("edgeFlags", event.getEdgeFlags()); + } + + if (touchList == null) { + touchList = new JSONArray(); + } + touchList.add(obj); + + return touchList; + } + + + public static final int REQUEST_UI_AUTO_LIST = 1; @Override diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java index e9494b649..9113a2f0a 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java @@ -228,8 +228,18 @@ public void run() { } if (isTouch) { - list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) - + "\nx: " + obj.getString("x") + ", y: " + obj.getString("y") + ", dividerY: " + obj.getString("dividerY") + ", pointerCount: " + obj.getString("pointerCount")); + if (obj.getIntValue("type") == 1) { + list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) + + "\nkeyCode: " + TouchUtil.getKeyCodeName(obj.getIntValue("keyCode")) + ", scanCode: " + TouchUtil.getScanCodeName(obj.getIntValue("scanCode")) + ", dividerY: " + obj.getString("dividerY") + + "\nrepeatCount: " + obj.getString("repeatCount") + " " + TouchUtil.getOrientationName(obj.getIntValue("orientation")) + ); + } + else { + list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) + + "\nx: " + obj.getString("x") + ", y: " + obj.getString("y") + ", dividerY: " + obj.getString("dividerY") + + "\npointerCount: " + obj.getString("pointerCount") + " " + TouchUtil.getOrientationName(obj.getIntValue("orientation")) + ); + } } else { list.add("[" + state + "]" + " name: " + obj.getString("name") + ", time: " + new Date(obj.getLongValue("time")).toLocaleString()); } From a5d604e26ac666dcedbf759782f461c6f03d6b44 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Aug 2020 23:00:20 +0800 Subject: [PATCH 0005/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=20UI=20=E6=B5=8B=E8=AF=95=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=BF=81=E7=A7=BB=E5=85=AC=E5=85=B1=E7=9A=84?= =?UTF-8?q?=E5=BD=95=E5=88=B6=E4=B8=8E=E5=9B=9E=E6=94=BE=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=88=B0=E5=85=AC=E5=85=B1=E7=9A=84=20Applic?= =?UTF-8?q?ation=20=E7=B1=BB=EF=BC=9B=E5=AE=8C=E5=96=84=E5=92=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AD=97=E6=AE=B5=E7=9A=84=E5=AD=98=E5=8F=96=E4=B8=8E?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/demo/{ui => }/CodeUtil.java | 2 +- .../src/main/java/apijson/demo/InputUtil.java | 40 + .../demo/application/DemoApplication.java | 641 ++++++++- .../java/apijson/demo/ui/AutoActivity.java | 3 +- .../java/apijson/demo/ui/RequestActivity.java | 2 +- .../java/apijson/demo/ui/SelectActivity.java | 6 +- .../main/java/apijson/demo/ui/TouchUtil.java | 39 - .../java/apijson/demo/ui/UIAutoActivity.java | 1245 ++++++++--------- .../apijson/demo/ui/UIAutoBaseActivity.java | 47 + .../apijson/demo/ui/UIAutoListActivity.java | 11 +- .../apijson/demo/ui/UnitAutoActivity.java | 2 +- 11 files changed, 1359 insertions(+), 679 deletions(-) rename APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/{ui => }/CodeUtil.java (99%) create mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/InputUtil.java delete mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java create mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoBaseActivity.java diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/CodeUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/CodeUtil.java similarity index 99% rename from APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/CodeUtil.java rename to APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/CodeUtil.java index a8dff90f9..ffe791e98 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/CodeUtil.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/CodeUtil.java @@ -12,7 +12,7 @@ See the License for the specific language governing permissions and limitations under the License.*/ -package apijson.demo.ui; +package apijson.demo; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/InputUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/InputUtil.java new file mode 100644 index 000000000..6d31f54ca --- /dev/null +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/InputUtil.java @@ -0,0 +1,40 @@ +package apijson.demo; + +import android.content.res.Configuration; +import android.view.KeyEvent; +import android.view.MotionEvent; + +public class InputUtil { + + public static String getActionName(int action) { + return MotionEvent.actionToString(action); +// switch (action) { +// case MotionEvent.ACTION_DOWN: +// return "DOWN"; +// case MotionEvent.ACTION_MOVE: +// return "MOVE"; +// case MotionEvent.ACTION_SCROLL: +// return "SCROLL"; +// case MotionEvent.ACTION_UP: +// return "UP"; +// case MotionEvent.ACTION_MASK: +// return "MASK"; +// case MotionEvent.ACTION_OUTSIDE: +// return "OUTSIDE"; +// default: +// return "CANCEL"; +// } + } + + public static String getOrientationName(int orientation) { + return orientation == Configuration.ORIENTATION_LANDSCAPE ? "HORIZONTAL" : "VERTICAL"; + } + + public static String getKeyCodeName(int keyCode) { + return KeyEvent.keyCodeToString(keyCode); + } + + public static String getScanCodeName(int scanCode) { + return "" + scanCode; //它是 hardware key id KeyEvent.keyCodeToString(scanCode); + } +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/application/DemoApplication.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/application/DemoApplication.java index a84798036..562860e8e 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/application/DemoApplication.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/application/DemoApplication.java @@ -16,14 +16,41 @@ import android.app.Activity; import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.Rect; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.DisplayMetrics; import android.util.Log; +import android.view.Display; +import android.view.InputEvent; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.RelativeLayout; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.yhao.floatwindow.FloatWindow; +import com.yhao.floatwindow.IFloatWindow; +import com.yhao.floatwindow.MoveType; import java.lang.ref.WeakReference; +import java.util.Calendar; import java.util.LinkedList; import java.util.List; import apijson.demo.R; +import apijson.demo.ui.UIAutoActivity; +import apijson.demo.ui.UIAutoListActivity; +import zuo.biao.apijson.JSON; /**Application * @author Lemon @@ -31,12 +58,77 @@ public class DemoApplication extends Application { private static final String TAG = "DemoApplication"; + private static final String DIVIDER_Y = "DIVIDER_Y"; + private static final String DIVIDER_HEIGHT = "DIVIDER_HEIGHT"; + private static final String DIVIDER_COLOR = "DIVIDER_COLOR"; + private static DemoApplication instance; public static DemoApplication getInstance() { return instance; } + + private boolean isRecovering = false; + private Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + + if (isRecovering) { + //通过遍历数组来实现 +// if (lastCurTime >= System.currentTimeMillis()) { +// isRecovering = false; +// pbUIAutoDivider.setVisibility(View.GONE); +// } +// +// MotionEvent event = (MotionEvent) msg.obj; +// dispatchEventToCurrentActivity(event); + + + //根据递归链表来实现,能精准地实现两个事件之间的间隔,不受处理时间不一致,甚至卡顿等影响。还能及时终止 + Node eventNode = (Node) msg.obj; + dispatchEventToCurrentActivity(eventNode.item); + + if (eventNode.next == null || eventNode.next.item == null) { + isRecovering = false; + pbUIAutoDivider.setVisibility(View.GONE); + return; + } + + msg = Message.obtain(); + msg.obj = eventNode.next; + sendMessageDelayed(msg, eventNode.next.item.getEventTime() - eventNode.item.getEventTime()); + } + } + }; + + + + private Activity activity; + int screenWidth; + int screenHeight; + + int windowWidth; + int windowHeight; + int windowY; + + ViewGroup cover; + ViewGroup divider; + View rlUIAutoDivider; + View vUIAutoDivider; + View ivUIAutoDivider; + View pbUIAutoDivider; + + private float dividerY; + private float dividerHeight; + private boolean moved = false; + + private JSONArray touchList; + + SharedPreferences cache; + private long flowId = 0; + @Override public void onCreate() { super.onCreate(); @@ -87,9 +179,161 @@ public void onActivityDestroyed(Activity activity) { } }); + + } + + public void onUIAutoActivityCreate(Activity activity) { + setCurrentActivity(activity); + Window window = activity.getWindow(); + //反而让 cover 与底部差一个导航栏高度 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + + DisplayMetrics outMetrics = new DisplayMetrics(); + Display display = activity.getWindowManager().getDefaultDisplay(); + + windowWidth = display.getWidth(); + windowHeight = display.getHeight(); + windowY = getWindowY(activity); + + display.getRealMetrics(outMetrics); + screenWidth = outMetrics.widthPixels; + screenHeight = outMetrics.heightPixels; + + cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); + + dividerY = cache.getFloat(DIVIDER_Y, 0); + dividerHeight = cache.getFloat(DIVIDER_HEIGHT, dip2px(24)); + + if (dividerY <= dividerHeight || dividerY >= windowHeight - dividerHeight) { + dividerY = windowHeight - dividerHeight - dip2px(30); + } + + if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 + activity.startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), UIAutoActivity.REQUEST_UI_AUTO_LIST); + } + + cover = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_cover_layout, null); + divider = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_divider_layout, null); + + rlUIAutoDivider = divider.findViewById(R.id.rlUIAutoDivider); + vUIAutoDivider = divider.findViewById(R.id.vUIAutoDivider); + ivUIAutoDivider = divider.findViewById(R.id.ivUIAutoDivider); + pbUIAutoDivider = divider.findViewById(R.id.pbUIAutoDivider); + pbUIAutoDivider.setVisibility(View.GONE); + + ViewGroup.LayoutParams dividerLp = rlUIAutoDivider.getLayoutParams(); + if (dividerLp == null) { + dividerLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) dividerHeight); + } else { + dividerLp.height = (int) dividerHeight; + } + rlUIAutoDivider.setLayoutParams(dividerLp); + +// cover.addView(divider); + +// rlUIAutoDivider.post(new Runnable() { +// @Override +// public void run() { +// rlUIAutoDivider.setY(dividerY - rlUIAutoDivider.getHeight()/2); +// cover.setVisibility(View.GONE); +// } +// }); + + vUIAutoDivider.setBackgroundColor(Color.parseColor(cache.getString(DIVIDER_COLOR, "#10000000"))); + + ViewGroup.LayoutParams lineLp = ivUIAutoDivider.getLayoutParams(); + if (lineLp == null) { + lineLp = new RelativeLayout.LayoutParams((int) dividerHeight, (int) dividerHeight); + } else { + lineLp.width = lineLp.height = (int) dividerHeight; + } + ivUIAutoDivider.setLayoutParams(lineLp); + + + + cover.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + Log.d(TAG, "onTouchEvent " + Calendar.getInstance().getTime().toLocaleString() + " action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY()); + dispatchEventToCurrentActivity(event); +//死循环 llTouch.dispatchTouchEvent(event); +// vDispatchTouch.dispatchTouchEvent(event); +// vDispatchTouch.dispatchTouchEvent(event); + //onTouchEvent 不能处理事件 vDispatchTouch.onTouchEvent(event); +// vTouch.setOnTouchListener(this); + return true; //连续记录只能 return true + } + }); + + ivUIAutoDivider.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + isRecovering = false; +// ((ViewGroup) v.getParent()).removeView(v); + + String cacheKey = UIAutoListActivity.CACHE_TOUCH; + SharedPreferences cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); + JSONArray allList = JSON.parseArray(cache.getString(cacheKey, null)); + + if (allList == null || allList.isEmpty()) { + allList = touchList; + } + else { + allList.addAll(touchList); + } + cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(allList)).commit(); + +// startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); +// startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); + startActivity(UIAutoActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString())); + + floatCover = null; + floatDivider = null; + FloatWindow.destroy("v"); + FloatWindow.destroy("v_ball"); + } + }); + rlUIAutoDivider.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { +// 都不动了 if (event.getY() - event.getRawY() >= 10) { + if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) { + moved = true; + divider.setY(event.getY()); +// divider.invalidate(); + } else { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + moved = false; + } + else if (event.getAction() == MotionEvent.ACTION_UP) { + if (! moved) { + ivUIAutoDivider.performClick(); + } + } + } +// } + return true; + } + }); + +// ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// root.addView(cover, lp); + + } + + + public void onUIAutoActivityDestroy(Activity activity) { + cache.edit().remove(DIVIDER_Y).putFloat(DIVIDER_Y, rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2).apply(); } + public LayoutInflater getLayoutInflater() { + try { + return LayoutInflater.from(this); + } catch (Exception e) { + return LayoutInflater.from(activity); + } + } + /**获取应用名 * @return */ @@ -115,8 +359,403 @@ public Activity getCurrentActivity() { } public void setCurrentActivity(Activity activity) { - if (sCurrentActivityWeakRef == null || !activity.equals(sCurrentActivityWeakRef.get())) { + this.activity = activity; + if (sCurrentActivityWeakRef == null || ! activity.equals(sCurrentActivityWeakRef.get())) { sCurrentActivityWeakRef = new WeakReference<>(activity); } } + + + + + + public boolean onTouchEvent(MotionEvent event, Activity activity) { + addInputEvent(event, activity); + return true; + } + public boolean onKeyDown(int keyCode, KeyEvent event, Activity activity) { + addInputEvent(event, activity); + return true; + } + public boolean onKeyUp(int keyCode, KeyEvent event, Activity activity) { + addInputEvent(event, activity); + return true; + } + + public void record() { + flowId = - System.currentTimeMillis(); + + cover.setVisibility(View.VISIBLE); + showCover(true, activity); + } + + + + + private IFloatWindow floatCover; + private IFloatWindow floatDivider; + + private void showCover(boolean show, Activity activity) { + //TODO 为纵屏、横屏分别加两套,判断屏幕方向来显示对应的一套 +// rlUIAutoDivider.setVisibility(show ? View.VISIBLE : View.GONE); +// rlUIAutoDivider.setY(dividerY + dividerHeight/2); + + floatCover = FloatWindow.get("v"); + if (floatCover == null) { + FloatWindow + .with(getApplicationContext()) + .setTag("v") + .setView(cover) + .setWidth(windowWidth) //设置控件宽高 + .setHeight(windowHeight) + .setX(0) //设置控件初始位置 + .setY(windowY) + .setMoveType(MoveType.inactive) + .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 +// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +// .setPermissionListener(mPermissionListener) //监听权限申请结果 + .build(); + + floatCover = FloatWindow.get("v"); + } + floatCover.show(); + + + floatDivider = FloatWindow.get("v_ball"); + if (floatDivider == null) { + FloatWindow + .with(getApplicationContext()) + .setTag("v_ball") + .setView(divider) + .setWidth(windowWidth) //设置控件宽高 + .setHeight((int) dividerHeight) + .setX(0) //设置控件初始位置 + .setY((int) (windowY + dividerY - dividerHeight/2)) +// .setY(screenHeight/2) + .setMoveType(MoveType.slide) + .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 +// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +// .setPermissionListener(mPermissionListener) //监听权限申请结果 + .build(); + + floatDivider = FloatWindow.get("v_ball"); + } + floatDivider.show(); + + //TODO 新建一个 have already added to window manager + +// if (FloatWindow.get("h")== null) { +// FloatWindow +// .with(getApplicationContext()) +// .setTag("h") +// .setView(cover) +// .setWidth(screenWidth) //设置控件宽高 +// .setHeight(screenHeight) +// .setX(0) //设置控件初始位置 +// .setY(0) +// .setMoveType(MoveType.inactive) +// .setDesktopShow(true) //桌面显示 +//// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +//// .setPermissionListener(mPermissionListener) //监听权限申请结果 +// .build(); +// } +// +// if (FloatWindow.get("h_ball") == null) { +// FloatWindow +// .with(getApplicationContext()) +// .setTag("h_ball") +// .setView(divider) +// .setWidth(screenWidth) //设置控件宽高 +// .setHeight((int) dividerHeight) +// .setX(0) //设置控件初始位置 +// .setY((int) (dividerY + dividerHeight/2)) +//// .setY(screenHeight/2) +// .setMoveType(MoveType.slide) +// .setDesktopShow(true) //桌面显示 +//// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +//// .setPermissionListener(mPermissionListener) //监听权限申请结果 +// .build(); +// } + +// FloatWindow.get("v").hide(); +//// FloatWindow.get("v_ball").hide(); +//// FloatWindow.get("h").hide(); +//// FloatWindow.get("h_ball").hide(); +// if (show) { +// if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { +// FloatWindow.get("v").show(); +// FloatWindow.get("v_ball").show(); +// } else { +//// FloatWindow.get("h").show(); +//// FloatWindow.get("h_ball").show(); +// } +// } + } + + + public int getWindowY(Activity activity) { + View decorView = activity.getWindow().getDecorView(); + + Rect rectangle= new Rect(); + decorView.getWindowVisibleDisplayFrame(rectangle); + return rectangle.top; + } + + public boolean dispatchEventToCurrentActivity(InputEvent ie) { + if (activity != null) { + if (ie instanceof MotionEvent) { + MotionEvent event = (MotionEvent) ie; + int windowY = getWindowY(activity); + + if (windowY > 0) { + event = MotionEvent.obtain(event); + event.offsetLocation(0, windowY); + } + activity.dispatchTouchEvent(event); + } + else if (ie instanceof KeyEvent) { + KeyEvent event = (KeyEvent) ie; + activity.dispatchKeyEvent(event); + } + + } + + addInputEvent(ie, activity); + + return activity != null; + } + + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public int dip2px(float dpValue) { + final float scale = getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public int px2dip(float pxValue) { + final float scale = getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + + private Node firstEventNode; + private Node eventNode; + + private long firstTime = 0; + private long lastTime = 0; + private long firstCurTime = 0; + private long lastCurTime = 0; + public void recover(JSONArray touchList) { + isRecovering = true; + +// List list = new LinkedList<>(); + + showCover(true, DemoApplication.getInstance().getCurrentActivity()); + + JSONObject first = touchList == null || touchList.isEmpty() ? null : touchList.getJSONObject(0); + firstTime = first == null ? 0 : first.getLongValue("time"); + + firstCurTime = 0; + if (firstTime > 0) { + firstCurTime = System.currentTimeMillis(); + pbUIAutoDivider.setVisibility(View.VISIBLE); + + for (int i = 0; i < touchList.size(); i++) { + JSONObject obj = touchList.getJSONObject(i); + + InputEvent event; + if (obj.getIntValue("type") == 1) { + /** + public KeyEvent(long downTime, long eventTime, int action, + int code, int repeat, int metaState, + int deviceId, int scancode, int flags, int source) { + mDownTime = downTime; + mEventTime = eventTime; + mAction = action; + mKeyCode = code; + mRepeatCount = repeat; + mMetaState = metaState; + mDeviceId = deviceId; + mScanCode = scancode; + mFlags = flags; + mSource = source; + mDisplayId = INVALID_DISPLAY; + } + */ + event = new KeyEvent( + obj.getLongValue("downTime"), + obj.getLongValue("eventTime"), + obj.getIntValue("action"), + obj.getIntValue("keyCode"), + obj.getIntValue("repeatCount"), + obj.getIntValue("metaState"), + obj.getIntValue("deviceId"), + obj.getIntValue("scanCode"), + obj.getIntValue("flags"), + obj.getIntValue("source") + ); + } + else { + /** + public static MotionEvent obtain(long downTime, long eventTime, int action, + float x, float y, float pressure, float size, int metaState, + float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, + int displayId) + */ + + //居然编译报错,和 + // static public MotionEvent obtain(long downTime, long eventTime, + // int action, int pointerCount, PointerProperties[] pointerProperties, + // PointerCoords[] pointerCoords, int metaState, int buttonState, + // float xPrecision, float yPrecision, int deviceId, + // int edgeFlags, int source, int displayId, int flags) + //冲突,实际上类型没传错 + + // event = MotionEvent.obtain(obj.getLongValue("downTime"), obj.getLongValue("eventTime"), obj.getIntValue("action"), + // obj.getFloatValue("x"), obj.getFloatValue("y"), obj.getFloatValue("pressure"), obj.getFloatValue("size"), obj.getIntValue("metaState"), + // obj.getFloatValue("xPrecision"), obj.getFloatValue("yPrecision"), obj.getIntValue("deviceId"), obj.getIntValue("edgeFlags"), obj.getIntValue("source"), + // obj.getIntValue("displayId")); + + event = MotionEvent.obtain( + obj.getLongValue("downTime"), + obj.getLongValue("eventTime"), + obj.getIntValue("action"), +// obj.getIntValue("pointerCount"), + obj.getFloatValue("x"), + obj.getFloatValue("y"), + obj.getFloatValue("pressure"), + obj.getFloatValue("size"), + obj.getIntValue("metaState"), + obj.getFloatValue("xPrecision"), + obj.getFloatValue("yPrecision"), + obj.getIntValue("deviceId"), + obj.getIntValue("edgeFlags") +// obj.getIntValue("source"), +// obj.getIntValue("displayId") + ); + ((MotionEvent) event).setSource(obj.getIntValue("source")); +// ((MotionEvent) event).setEdgeFlags(obj.getIntValue("edgeFlags")); + + } + + +// list.add(event); + + long time = obj.getIntValue("time"); + if (i <= 0) { + firstEventNode = new Node<>(null, event, null); + eventNode = firstEventNode; + } + else if (i >= touchList.size() - 1) { + lastTime = time; + lastCurTime = firstCurTime + lastTime - firstTime; + } + + eventNode.next = new Node<>(eventNode, event, null); + eventNode = eventNode.next; + + //通过遍历数组来实现 +// Message msg = handler.obtainMessage(); +// msg.obj = event; +// handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); + } + + //通过递归链表来实现 + Message msg = handler.obtainMessage(); + msg.obj = firstEventNode; + handler.sendMessage(msg); + + } + } + + + private JSONArray addInputEvent(InputEvent ie, Activity activity) { + int dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; + int orientation = activity == null ? Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; + + JSONObject obj = new JSONObject(true); + obj.put("id", - System.currentTimeMillis()); + obj.put("flowId", flowId); + obj.put("time", System.currentTimeMillis()); + obj.put("orientation", orientation); + obj.put("dividerY", dividerY); + + if (ie instanceof KeyEvent) { + KeyEvent event = (KeyEvent) ie; + obj.put("type", 1); + + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< + obj.put("action", event.getAction()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); + obj.put("source", event.getSource()); + obj.put("deviceId", event.getDeviceId()); + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> + + obj.put("keyCode", event.getKeyCode()); + obj.put("scanCode", event.getScanCode()); + obj.put("repeatCount", event.getRepeatCount()); + //通过 keyCode 获取的 obj.put("number", event.getNumber()); + obj.put("flags", event.getFlags()); + //通过 mMetaState 获取的 obj.put("modifiers", event.getModifiers()); + //通过 mKeyCode 获取的 obj.put("displayLabel", event.getDisplayLabel()); + //通过 mMetaState 获取的 obj.put("unicodeChar", event.getUnicodeChar()); + } + else if (ie instanceof MotionEvent) { + MotionEvent event = (MotionEvent) ie; + obj.put("type", 0); + + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< + obj.put("action", event.getAction()); + obj.put("downTime", event.getDownTime()); + obj.put("eventTime", event.getEventTime()); + obj.put("metaState", event.getMetaState()); + obj.put("source", event.getSource()); + obj.put("deviceId", event.getDeviceId()); + //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> + + float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); + + obj.put("x", (int) event.getX()); + obj.put("y", (int) relativeY); + obj.put("rawX", (int) event.getRawX()); + obj.put("rawY", (int) event.getRawY()); + obj.put("size", event.getSize()); + obj.put("pressure", event.getPressure()); + obj.put("xPrecision", event.getXPrecision()); + obj.put("yPrecision", event.getYPrecision()); + obj.put("pointerCount", event.getPointerCount()); + obj.put("edgeFlags", event.getEdgeFlags()); + } + + if (touchList == null) { + touchList = new JSONArray(); + } + touchList.add(obj); + + return touchList; + } + + + + + private static class Node { + E item; + Node next; + Node prev; + + Node(Node prev, E element, Node next) { + this.item = element; + this.next = next; + this.prev = prev; + } + } + } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/AutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/AutoActivity.java index ca1680043..f90aa21c8 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/AutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/AutoActivity.java @@ -28,6 +28,7 @@ import android.widget.TextView; import android.widget.Toast; +import apijson.demo.CodeUtil; import apijson.demo.R; import apijson.demo.RequestUtil; import apijson.demo.StringUtil; @@ -36,7 +37,7 @@ /**自动生成代码 * @author Lemon */ -public class AutoActivity extends Activity { +public class AutoActivity extends UIAutoBaseActivity { private static final String TAG = "AutoActivity"; public static final String KEY_REQUEST = "KEY_REQUEST"; diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/RequestActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/RequestActivity.java index 09f2ded8e..b0e422271 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/RequestActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/RequestActivity.java @@ -52,7 +52,7 @@ * 向服务器发起请求查询或操作相应数据 * @author Lemon */ -public class RequestActivity extends Activity implements OnHttpResponseListener { +public class RequestActivity extends UIAutoBaseActivity implements OnHttpResponseListener { private static final String TAG = "RequestActivity"; diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java index 4ace20fb6..12de06e94 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java @@ -32,13 +32,14 @@ import apijson.demo.R; import apijson.demo.RequestUtil; import apijson.demo.StringUtil; +import apijson.demo.application.DemoApplication; import zuo.biao.apijson.JSON; /**选择Activity * 选择向服务器发起的请求 * @author Lemon */ -public class SelectActivity extends Activity implements OnClickListener { +public class SelectActivity extends UIAutoBaseActivity implements OnClickListener { public static final String CONFIG_PATH = "CONFIG_PATH"; @@ -115,6 +116,9 @@ public boolean onLongClick(View v) { }); } + DemoApplication.getInstance().onUIAutoActivityCreate(this); + DemoApplication.getInstance().record(); + } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java deleted file mode 100644 index ad8d53ebc..000000000 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/TouchUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -package apijson.demo.ui; - -import android.content.res.Configuration; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class TouchUtil { - - public static String getActionName(int action) { - switch (action) { - case MotionEvent.ACTION_DOWN: - return "DOWN"; - case MotionEvent.ACTION_MOVE: - return "MOVE"; - case MotionEvent.ACTION_SCROLL: - return "SCROLL"; - case MotionEvent.ACTION_UP: - return "UP"; - case MotionEvent.ACTION_MASK: - return "MASK"; - case MotionEvent.ACTION_OUTSIDE: - return "OUTSIDE"; - default: - return "CANCEL"; - } - } - - public static String getOrientationName(int orientation) { - return orientation == Configuration.ORIENTATION_LANDSCAPE ? "HORIZONTAL" : "VERTICAL"; - } - - public static String getKeyCodeName(int keyCode) { - return KeyEvent.keyCodeToString(keyCode); - } - - public static String getScanCodeName(int scanCode) { - return "" + scanCode; //它是 hardware key id KeyEvent.keyCodeToString(scanCode); - } -} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java index eebaddfa4..0281ed089 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoActivity.java @@ -18,34 +18,16 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; -import android.os.Message; -import android.support.annotation.RequiresApi; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.Display; -import android.view.InputEvent; -import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.view.Window; -import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.yhao.floatwindow.FloatWindow; -import com.yhao.floatwindow.IFloatWindow; -import com.yhao.floatwindow.MoveType; - -import java.util.Calendar; import apijson.demo.R; import apijson.demo.application.DemoApplication; @@ -81,58 +63,58 @@ public static Intent createIntent(Context context, String list) { } - private boolean isRecovering = false; - private Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - - if (isRecovering) { - //通过遍历数组来实现 -// if (lastCurTime >= System.currentTimeMillis()) { +// private boolean isRecovering = false; +// private Handler handler = new Handler() { +// @Override +// public void handleMessage(Message msg) { +// super.handleMessage(msg); +// +// if (isRecovering) { +// //通过遍历数组来实现 +//// if (lastCurTime >= System.currentTimeMillis()) { +//// isRecovering = false; +//// pbUIAutoDivider.setVisibility(View.GONE); +//// } +//// +//// MotionEvent event = (MotionEvent) msg.obj; +//// dispatchEventToCurrentActivity(event); +// +// +// //根据递归链表来实现,能精准地实现两个事件之间的间隔,不受处理时间不一致,甚至卡顿等影响。还能及时终止 +// Node eventNode = ( Node) msg.obj; +// dispatchEventToCurrentActivity(eventNode.item); +// +// if (eventNode.next == null) { // isRecovering = false; // pbUIAutoDivider.setVisibility(View.GONE); +// return; // } // -// MotionEvent event = (MotionEvent) msg.obj; -// dispatchEventToCurrentActivity(event); - - - //根据递归链表来实现,能精准地实现两个事件之间的间隔,不受处理时间不一致,甚至卡顿等影响。还能及时终止 - Node eventNode = ( Node) msg.obj; - dispatchEventToCurrentActivity(eventNode.item); - - if (eventNode.next == null) { - isRecovering = false; - pbUIAutoDivider.setVisibility(View.GONE); - return; - } - - msg = Message.obtain(); - msg.obj = eventNode.next; - sendMessageDelayed(msg, eventNode.next.item.getEventTime() - eventNode.item.getEventTime()); - } - } - }; +// msg = Message.obtain(); +// msg.obj = eventNode.next; +// sendMessageDelayed(msg, eventNode.next.item.getEventTime() - eventNode.item.getEventTime()); +// } +// } +// }; private Activity context; - int screenWidth; - int screenHeight; - - int windowWidth; - int windowHeight; - int windowY; - - ViewGroup cover; - ViewGroup divider; - View rlUIAutoDivider; - View vUIAutoDivider; - View ivUIAutoDivider; - View pbUIAutoDivider; - - private float dividerY; - private float dividerHeight; - private boolean moved = false; +// int screenWidth; +// int screenHeight; +// +// int windowWidth; +// int windowHeight; +// int windowY; +// +// ViewGroup cover; +// ViewGroup divider; +// View rlUIAutoDivider; +// View vUIAutoDivider; +// View ivUIAutoDivider; +// View pbUIAutoDivider; +// +// private float dividerY; +// private float dividerHeight; +// private boolean moved = false; private JSONArray touchList; @@ -147,30 +129,32 @@ protected void onCreate(Bundle savedInstanceState) { //反而让 cover 与底部差一个导航栏高度 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); context = this; + DemoApplication.getInstance().setCurrentActivity(this); + flowId = getIntent().getLongExtra(INTENT_FLOW_ID, flowId); touchList = JSON.parseArray(getIntent().getStringExtra(INTENT_TOUCH_LIST)); - - DisplayMetrics outMetrics = new DisplayMetrics(); - Display display = getWindowManager().getDefaultDisplay(); - - windowWidth = display.getWidth(); - windowHeight = display.getHeight(); - windowY = getWindowY(this); - - display.getRealMetrics(outMetrics); - screenWidth = outMetrics.widthPixels; - screenHeight = outMetrics.heightPixels; - - cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); - - dividerY = cache.getFloat(DIVIDER_Y, 0); - dividerHeight = cache.getFloat(DIVIDER_HEIGHT, dip2px(24)); - - if (dividerY <= dividerHeight || dividerY >= windowHeight - dividerHeight) { - dividerY = windowHeight - dividerHeight - dip2px(30); - } +// +// DisplayMetrics outMetrics = new DisplayMetrics(); +// Display display = getWindowManager().getDefaultDisplay(); +// +// windowWidth = display.getWidth(); +// windowHeight = display.getHeight(); +// windowY = getWindowY(this); +// +// display.getRealMetrics(outMetrics); +// screenWidth = outMetrics.widthPixels; +// screenHeight = outMetrics.heightPixels; +// +// cache = getSharedPreferences(TAG, Context.MODE_PRIVATE); +// +// dividerY = cache.getFloat(DIVIDER_Y, 0); +// dividerHeight = cache.getFloat(DIVIDER_HEIGHT, dip2px(24)); +// +// if (dividerY <= dividerHeight || dividerY >= windowHeight - dividerHeight) { +// dividerY = windowHeight - dividerHeight - dip2px(30); +// } if (touchList != null && touchList.isEmpty() == false) { //TODO 回放操作 // recover(touchList); @@ -179,94 +163,94 @@ protected void onCreate(Bundle savedInstanceState) { } - ViewGroup root = (ViewGroup) getWindow().getDecorView(); - cover = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_cover_layout, null); - divider = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_divider_layout, null); - - rlUIAutoDivider = divider.findViewById(R.id.rlUIAutoDivider); - vUIAutoDivider = divider.findViewById(R.id.vUIAutoDivider); - ivUIAutoDivider = divider.findViewById(R.id.ivUIAutoDivider); - pbUIAutoDivider = divider.findViewById(R.id.pbUIAutoDivider); - pbUIAutoDivider.setVisibility(View.GONE); - - ViewGroup.LayoutParams dividerLp = rlUIAutoDivider.getLayoutParams(); - if (dividerLp == null) { - dividerLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) dividerHeight); - } else { - dividerLp.height = (int) dividerHeight; - } - rlUIAutoDivider.setLayoutParams(dividerLp); - -// cover.addView(divider); - -// rlUIAutoDivider.post(new Runnable() { +// ViewGroup root = (ViewGroup) getWindow().getDecorView(); +// cover = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_cover_layout, null); +// divider = (ViewGroup) getLayoutInflater().inflate(R.layout.ui_auto_divider_layout, null); +// +// rlUIAutoDivider = divider.findViewById(R.id.rlUIAutoDivider); +// vUIAutoDivider = divider.findViewById(R.id.vUIAutoDivider); +// ivUIAutoDivider = divider.findViewById(R.id.ivUIAutoDivider); +// pbUIAutoDivider = divider.findViewById(R.id.pbUIAutoDivider); +// pbUIAutoDivider.setVisibility(View.GONE); +// +// ViewGroup.LayoutParams dividerLp = rlUIAutoDivider.getLayoutParams(); +// if (dividerLp == null) { +// dividerLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) dividerHeight); +// } else { +// dividerLp.height = (int) dividerHeight; +// } +// rlUIAutoDivider.setLayoutParams(dividerLp); +// +//// cover.addView(divider); +// +//// rlUIAutoDivider.post(new Runnable() { +//// @Override +//// public void run() { +//// rlUIAutoDivider.setY(dividerY - rlUIAutoDivider.getHeight()/2); +//// cover.setVisibility(View.GONE); +//// } +//// }); +// +// vUIAutoDivider.setBackgroundColor(Color.parseColor(cache.getString(DIVIDER_COLOR, "#10000000"))); +// +// ViewGroup.LayoutParams lineLp = ivUIAutoDivider.getLayoutParams(); +// if (lineLp == null) { +// lineLp = new RelativeLayout.LayoutParams((int) dividerHeight, (int) dividerHeight); +// } else { +// lineLp.width = lineLp.height = (int) dividerHeight; +// } +// ivUIAutoDivider.setLayoutParams(lineLp); +// +// ivUIAutoDivider.setOnClickListener(new View.OnClickListener() { // @Override -// public void run() { -// rlUIAutoDivider.setY(dividerY - rlUIAutoDivider.getHeight()/2); -// cover.setVisibility(View.GONE); +// public void onClick(View v) { +// isRecovering = false; +//// ((ViewGroup) v.getParent()).removeView(v); +// +// String cacheKey = UIAutoListActivity.CACHE_TOUCH; +// SharedPreferences cache = getSharedPreferences(UIAutoActivity.TAG, Context.MODE_PRIVATE); +// JSONArray allList = JSON.parseArray(cache.getString(cacheKey, null)); +// +// if (allList == null || allList.isEmpty()) { +// allList = touchList; +// } +// else { +// allList.addAll(touchList); +// } +// cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(allList)).commit(); +// +//// startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); +//// startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); +// startActivity(UIAutoActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString())); +// +// floatCover = null; +// floatDivider = null; +// FloatWindow.destroy("v"); +// FloatWindow.destroy("v_ball"); // } // }); - - vUIAutoDivider.setBackgroundColor(Color.parseColor(cache.getString(DIVIDER_COLOR, "#10000000"))); - - ViewGroup.LayoutParams lineLp = ivUIAutoDivider.getLayoutParams(); - if (lineLp == null) { - lineLp = new RelativeLayout.LayoutParams((int) dividerHeight, (int) dividerHeight); - } else { - lineLp.width = lineLp.height = (int) dividerHeight; - } - ivUIAutoDivider.setLayoutParams(lineLp); - - ivUIAutoDivider.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - isRecovering = false; -// ((ViewGroup) v.getParent()).removeView(v); - - String cacheKey = UIAutoListActivity.CACHE_TOUCH; - SharedPreferences cache = getSharedPreferences(UIAutoActivity.TAG, Context.MODE_PRIVATE); - JSONArray allList = JSON.parseArray(cache.getString(cacheKey, null)); - - if (allList == null || allList.isEmpty()) { - allList = touchList; - } - else { - allList.addAll(touchList); - } - cache.edit().remove(cacheKey).putString(cacheKey, JSON.toJSONString(allList)).commit(); - -// startActivity(UIAutoListActivity.createIntent(DemoApplication.getInstance(), flowId)); // touchList == null ? null : touchList.toJSONString())); -// startActivityForResult(UIAutoListActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString()), REQUEST_UI_AUTO_LIST); - startActivity(UIAutoActivity.createIntent(DemoApplication.getInstance(), touchList == null ? null : touchList.toJSONString())); - - floatCover = null; - floatDivider = null; - FloatWindow.destroy("v"); - FloatWindow.destroy("v_ball"); - } - }); - rlUIAutoDivider.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { -// 都不动了 if (event.getY() - event.getRawY() >= 10) { - if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) { - moved = true; - divider.setY(event.getY()); -// divider.invalidate(); - } else { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - moved = false; - } - else if (event.getAction() == MotionEvent.ACTION_UP) { - if (! moved) { - ivUIAutoDivider.performClick(); - } - } - } +// rlUIAutoDivider.setOnTouchListener(new View.OnTouchListener() { +// @Override +// public boolean onTouch(View v, MotionEvent event) { +//// 都不动了 if (event.getY() - event.getRawY() >= 10) { +// if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) { +// moved = true; +// divider.setY(event.getY()); +//// divider.invalidate(); +// } else { +// if (event.getAction() == MotionEvent.ACTION_DOWN) { +// moved = false; +// } +// else if (event.getAction() == MotionEvent.ACTION_UP) { +// if (! moved) { +// ivUIAutoDivider.performClick(); +// } +// } // } - return true; - } - }); +//// } +// return true; +// } +// }); // ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); // root.addView(cover, lp); @@ -284,50 +268,50 @@ else if (event.getAction() == MotionEvent.ACTION_UP) { final View vDispatchTouch = findViewById(R.id.vDispatchTouch); - View.OnTouchListener listener = new View.OnTouchListener() { - @RequiresApi(api = 29) - @Override - public boolean onTouch(View v, MotionEvent event) { - Log.d(TAG, "onTouchEvent " + Calendar.getInstance().getTime().toLocaleString() + " action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY()); - - dispatchEventToCurrentActivity(event); - - if (isFinishing() || isDestroyed()) { -// ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); -// Activity runningActivity = activityManager.getRunningTasks(1).get(0); -// getWindow().getDecorView().dispatchTouchEvent(event); - - return true; - } - - vDispatchTouch.dispatchTouchEvent(event); - -// vTouch.setOnTouchListener(new View.OnTouchListener() { -// @Override -// public boolean onTouch(View v, MotionEvent event) { -// return false; -// } -// }); +// View.OnTouchListener listener = new View.OnTouchListener() { +// @RequiresApi(api = 29) +// @Override +// public boolean onTouch(View v, MotionEvent event) { +// Log.d(TAG, "onTouchEvent " + Calendar.getInstance().getTime().toLocaleString() + " action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY()); +// +// dispatchEventToCurrentActivity(event); +// +// if (isFinishing() || isDestroyed()) { +//// ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); +//// Activity runningActivity = activityManager.getRunningTasks(1).get(0); +//// getWindow().getDecorView().dispatchTouchEvent(event); +// +// return true; +// } // - CharSequence s = tvTouch.getText(); - if (s == null) { - s = ""; - } - - float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; - float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); - - tvTouch.setText(Calendar.getInstance().getTime().toLocaleString() + " " + TouchUtil.getActionName(event.getAction()) + "\nx:" + event.getX() + "; y:" + event.getY() + "; relativeY: " + relativeY + "; pointerCount: " + event.getPointerCount() + "\n" + s); -// Toast.makeText(context, "vTouch.action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY(), Toast.LENGTH_SHORT).show(); - -//死循环 llTouch.dispatchTouchEvent(event); -// vDispatchTouch.dispatchTouchEvent(event); // vDispatchTouch.dispatchTouchEvent(event); - //onTouchEvent 不能处理事件 vDispatchTouch.onTouchEvent(event); -// vTouch.setOnTouchListener(this); - return true; //连续记录只能 return true - } - }; +// +//// vTouch.setOnTouchListener(new View.OnTouchListener() { +//// @Override +//// public boolean onTouch(View v, MotionEvent event) { +//// return false; +//// } +//// }); +//// +// CharSequence s = tvTouch.getText(); +// if (s == null) { +// s = ""; +// } +// +// float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; +// float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); +// +// tvTouch.setText(Calendar.getInstance().getTime().toLocaleString() + " " + InputUtil.getActionName(event.getAction()) + "\nx:" + event.getX() + "; y:" + event.getY() + "; relativeY: " + relativeY + "; pointerCount: " + event.getPointerCount() + "\n" + s); +//// Toast.makeText(context, "vTouch.action:" + (event.getAction()) + "; x:" + event.getX() + "; y:" + event.getY(), Toast.LENGTH_SHORT).show(); +// +////死循环 llTouch.dispatchTouchEvent(event); +//// vDispatchTouch.dispatchTouchEvent(event); +//// vDispatchTouch.dispatchTouchEvent(event); +// //onTouchEvent 不能处理事件 vDispatchTouch.onTouchEvent(event); +//// vTouch.setOnTouchListener(this); +// return true; //连续记录只能 return true +// } +// }; // vTouch.setOnTouchListener(listener); tvButton.setOnClickListener(new View.OnClickListener() { @@ -353,22 +337,23 @@ public boolean onLongClick(View v) { } }); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - - MotionEvent e = MotionEvent.obtain(1000, 1000, - MotionEvent.ACTION_DOWN, screenWidth/2, screenHeight/2, 0); - - //TODO onTouchEvent ? - vTouch.dispatchTouchEvent(e); - e.setAction(MotionEvent.ACTION_UP); - vTouch.dispatchTouchEvent(e); +// new Handler().postDelayed(new Runnable() { +// @Override +// public void run() { +// +// MotionEvent e = MotionEvent.obtain(1000, 1000, +// MotionEvent.ACTION_DOWN, screenWidth/2, screenHeight/2, 0); +// +// //TODO onTouchEvent ? +// vTouch.dispatchTouchEvent(e); +// e.setAction(MotionEvent.ACTION_UP); +// vTouch.dispatchTouchEvent(e); +// +// } +// }, 1000); - } - }, 1000); +// cover.setOnTouchListener(listener); - cover.setOnTouchListener(listener); } @@ -390,436 +375,438 @@ public void toLocal(View v) { public void record(View v) { flowId = - System.currentTimeMillis(); - cover.setVisibility(View.VISIBLE); - showCover(true, context); - +// cover.setVisibility(View.VISIBLE); +// showCover(true, context); // finish(); - } - - - - private IFloatWindow floatCover; - private IFloatWindow floatDivider; + DemoApplication.getInstance().record(); + finish(); + } - private void showCover(boolean show, Activity activity) { - //TODO 为纵屏、横屏分别加两套,判断屏幕方向来显示对应的一套 -// rlUIAutoDivider.setVisibility(show ? View.VISIBLE : View.GONE); -// rlUIAutoDivider.setY(dividerY + dividerHeight/2); - floatCover = FloatWindow.get("v"); - if (floatCover == null) { - FloatWindow - .with(getApplicationContext()) - .setTag("v") - .setView(cover) - .setWidth(windowWidth) //设置控件宽高 - .setHeight(windowHeight) - .setX(0) //设置控件初始位置 - .setY(windowY) - .setMoveType(MoveType.inactive) - .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 -// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 -// .setPermissionListener(mPermissionListener) //监听权限申请结果 - .build(); - floatCover = FloatWindow.get("v"); - } - floatCover.show(); - - - floatDivider = FloatWindow.get("v_ball"); - if (floatDivider == null) { - FloatWindow - .with(getApplicationContext()) - .setTag("v_ball") - .setView(divider) - .setWidth(windowWidth) //设置控件宽高 - .setHeight((int) dividerHeight) - .setX(0) //设置控件初始位置 - .setY((int) (windowY + dividerY - dividerHeight/2)) -// .setY(screenHeight/2) - .setMoveType(MoveType.slide) - .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 -// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 -// .setPermissionListener(mPermissionListener) //监听权限申请结果 - .build(); - - floatDivider = FloatWindow.get("v_ball"); - } - floatDivider.show(); - //TODO 新建一个 have already added to window manager - -// if (FloatWindow.get("h")== null) { +// private IFloatWindow floatCover; +// private IFloatWindow floatDivider; +// +// private void showCover(boolean show, Activity activity) { +// //TODO 为纵屏、横屏分别加两套,判断屏幕方向来显示对应的一套 +//// rlUIAutoDivider.setVisibility(show ? View.VISIBLE : View.GONE); +//// rlUIAutoDivider.setY(dividerY + dividerHeight/2); +// +// floatCover = FloatWindow.get("v"); +// if (floatCover == null) { // FloatWindow // .with(getApplicationContext()) -// .setTag("h") +// .setTag("v") // .setView(cover) -// .setWidth(screenWidth) //设置控件宽高 -// .setHeight(screenHeight) +// .setWidth(windowWidth) //设置控件宽高 +// .setHeight(windowHeight) // .setX(0) //设置控件初始位置 -// .setY(0) +// .setY(windowY) // .setMoveType(MoveType.inactive) -// .setDesktopShow(true) //桌面显示 +// .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 //// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 //// .setPermissionListener(mPermissionListener) //监听权限申请结果 // .build(); +// +// floatCover = FloatWindow.get("v"); // } +// floatCover.show(); // -// if (FloatWindow.get("h_ball") == null) { +// +// floatDivider = FloatWindow.get("v_ball"); +// if (floatDivider == null) { // FloatWindow // .with(getApplicationContext()) -// .setTag("h_ball") +// .setTag("v_ball") // .setView(divider) -// .setWidth(screenWidth) //设置控件宽高 +// .setWidth(windowWidth) //设置控件宽高 // .setHeight((int) dividerHeight) // .setX(0) //设置控件初始位置 -// .setY((int) (dividerY + dividerHeight/2)) +// .setY((int) (windowY + dividerY - dividerHeight/2)) //// .setY(screenHeight/2) // .setMoveType(MoveType.slide) -// .setDesktopShow(true) //桌面显示 +// .setDesktopShow(true) //必须为 true,否则切换 Activity 就会自动隐藏 //桌面显示 //// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 //// .setPermissionListener(mPermissionListener) //监听权限申请结果 // .build(); +// +// floatDivider = FloatWindow.get("v_ball"); // } - -// FloatWindow.get("v").hide(); -//// FloatWindow.get("v_ball").hide(); -//// FloatWindow.get("h").hide(); -//// FloatWindow.get("h_ball").hide(); -// if (show) { -// if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { -// FloatWindow.get("v").show(); -// FloatWindow.get("v_ball").show(); -// } else { -//// FloatWindow.get("h").show(); -//// FloatWindow.get("h_ball").show(); +// floatDivider.show(); +// +// //TODO 新建一个 have already added to window manager +// +//// if (FloatWindow.get("h")== null) { +//// FloatWindow +//// .with(getApplicationContext()) +//// .setTag("h") +//// .setView(cover) +//// .setWidth(screenWidth) //设置控件宽高 +//// .setHeight(screenHeight) +//// .setX(0) //设置控件初始位置 +//// .setY(0) +//// .setMoveType(MoveType.inactive) +//// .setDesktopShow(true) //桌面显示 +////// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +////// .setPermissionListener(mPermissionListener) //监听权限申请结果 +//// .build(); +//// } +//// +//// if (FloatWindow.get("h_ball") == null) { +//// FloatWindow +//// .with(getApplicationContext()) +//// .setTag("h_ball") +//// .setView(divider) +//// .setWidth(screenWidth) //设置控件宽高 +//// .setHeight((int) dividerHeight) +//// .setX(0) //设置控件初始位置 +//// .setY((int) (dividerY + dividerHeight/2)) +////// .setY(screenHeight/2) +//// .setMoveType(MoveType.slide) +//// .setDesktopShow(true) //桌面显示 +////// .setViewStateListener(mViewStateListener) //监听悬浮控件状态改变 +////// .setPermissionListener(mPermissionListener) //监听权限申请结果 +//// .build(); +//// } +// +//// FloatWindow.get("v").hide(); +////// FloatWindow.get("v_ball").hide(); +////// FloatWindow.get("h").hide(); +////// FloatWindow.get("h_ball").hide(); +//// if (show) { +//// if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { +//// FloatWindow.get("v").show(); +//// FloatWindow.get("v_ball").show(); +//// } else { +////// FloatWindow.get("h").show(); +////// FloatWindow.get("h_ball").show(); +//// } +//// } +// } +// +// +// public int getWindowY(Activity a) { +// View decorView = a.getWindow().getDecorView(); +// +// Rect rectangle= new Rect(); +// decorView.getWindowVisibleDisplayFrame(rectangle); +// return rectangle.top; +// } +// +// public boolean dispatchEventToCurrentActivity(InputEvent ie) { +// Activity activity = DemoApplication.getInstance().getCurrentActivity(); +// if (activity != null) { +//// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); +//// +//// float y = decorView.getY(); +//// float top = decorView.getTop(); +//// event.offsetLocation(0, decorView.getTop()); +//// View content = decorView.findViewById(android.R.id.content); +//// float cy = content.getY(); +//// float ctop = content.getTop(); +// +// if (ie instanceof MotionEvent) { +// MotionEvent event = (MotionEvent) ie; +// int windowY = getWindowY(activity); +// +// if (windowY > 0) { +// event = MotionEvent.obtain(event); +// event.offsetLocation(0, windowY); +// } +// activity.dispatchTouchEvent(event); // } +// else if (ie instanceof KeyEvent) { +// KeyEvent event = (KeyEvent) ie; +// activity.dispatchKeyEvent(event); +// } +// // } - } - - - public int getWindowY(Activity a) { - View decorView = a.getWindow().getDecorView(); - - Rect rectangle= new Rect(); - decorView.getWindowVisibleDisplayFrame(rectangle); - return rectangle.top; - } - - public boolean dispatchEventToCurrentActivity(InputEvent ie) { - Activity activity = DemoApplication.getInstance().getCurrentActivity(); - if (activity != null) { -// event.offsetLocation(0, a.getWindow().getDecorView().findViewById(android.R.id.content).getTop()); -// -// float y = decorView.getY(); -// float top = decorView.getTop(); -// event.offsetLocation(0, decorView.getTop()); -// View content = decorView.findViewById(android.R.id.content); -// float cy = content.getY(); -// float ctop = content.getTop(); - - if (ie instanceof MotionEvent) { - MotionEvent event = (MotionEvent) ie; - int windowY = getWindowY(activity); - - if (windowY > 0) { - event = MotionEvent.obtain(event); - event.offsetLocation(0, windowY); - } - activity.dispatchTouchEvent(event); - } - else if (ie instanceof KeyEvent) { - KeyEvent event = (KeyEvent) ie; - activity.dispatchKeyEvent(event); - } - - } - - -// float dividerY = rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2; -// float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; -// float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); +// +// +//// float dividerY = rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2; +//// float dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; +//// float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); +//// +//// JSONObject obj = new JSONObject(true); +//// obj.put("id", - System.currentTimeMillis()); +//// obj.put("flowId", flowId); +//// obj.put("action", event.getAction()); +//// obj.put("x", (int) event.getX()); +//// obj.put("y", (int) relativeY); +//// obj.put("dividerY", (int) dividerY); +//// obj.put("rawX", (int) event.getRawX()); +//// obj.put("rawY", (int) event.getRawY()); +//// obj.put("time", System.currentTimeMillis()); +//// obj.put("downTime", event.getDownTime()); +//// obj.put("eventTime", event.getEventTime()); +//// obj.put("metaState", event.getMetaState()); +//// obj.put("size", event.getSize()); +//// obj.put("source", event.getSource()); +//// obj.put("pressure", event.getPressure()); +//// obj.put("deviceId", event.getDeviceId()); +//// obj.put("xPrecision", event.getXPrecision()); +//// obj.put("yPrecision", event.getYPrecision()); +//// obj.put("pointerCount", event.getPointerCount()); +//// obj.put("edgeFlags", event.getEdgeFlags()); +// +// addInputEvent(ie, activity); +// +// return activity != null; +// } +// +// +// +// /** +// * 根据手机的分辨率从 dp 的单位 转成为 px(像素) +// */ +// public int dip2px(float dpValue) { +// final float scale = getResources().getDisplayMetrics().density; +// return (int) (dpValue * scale + 0.5f); +// } +// +// /** +// * 根据手机的分辨率从 px(像素) 的单位 转成为 dp +// */ +// public int px2dip(float pxValue) { +// final float scale = getResources().getDisplayMetrics().density; +// return (int) (pxValue / scale + 0.5f); +// } +// +// @Override +// protected void onDestroy() { +// cache.edit().remove(DIVIDER_Y).putFloat(DIVIDER_Y, rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2).apply(); +// super.onDestroy(); +// } +// +//// @Override +//// public boolean dispatchTouchEvent(MotionEvent ev) { +//// super.dispatchTouchEvent(ev); +//// return false; +//// } +//// +//// @Override +//// public boolean onTouchEvent(MotionEvent event) { +//// super.onTouchEvent(event); +//// return false; +//// } +// +// +// private Node firstEventNode; +// private Node eventNode; +// +// private long firstTime = 0; +// private long lastTime = 0; +// private long firstCurTime = 0; +// private long lastCurTime = 0; +// public void recover(JSONArray touchList) { +// isRecovering = true; +// +//// List list = new LinkedList<>(); +// +// showCover(true, DemoApplication.getInstance().getCurrentActivity()); +// +// JSONObject first = touchList == null || touchList.isEmpty() ? null : touchList.getJSONObject(0); +// firstTime = first == null ? 0 : first.getLongValue("time"); +// +// firstCurTime = 0; +// if (firstTime > 0) { +// firstCurTime = System.currentTimeMillis(); +// pbUIAutoDivider.setVisibility(View.VISIBLE); +// +// for (int i = 0; i < touchList.size(); i++) { +// JSONObject obj = touchList.getJSONObject(i); +// +// InputEvent event; +// if (obj.getIntValue("type") == 1) { +// /** +// public KeyEvent(long downTime, long eventTime, int action, +// int code, int repeat, int metaState, +// int deviceId, int scancode, int flags, int source) { +// mDownTime = downTime; +// mEventTime = eventTime; +// mAction = action; +// mKeyCode = code; +// mRepeatCount = repeat; +// mMetaState = metaState; +// mDeviceId = deviceId; +// mScanCode = scancode; +// mFlags = flags; +// mSource = source; +// mDisplayId = INVALID_DISPLAY; +// } +// */ +// event = new KeyEvent( +// obj.getLongValue("downTime"), +// obj.getLongValue("eventTime"), +// obj.getIntValue("action"), +// obj.getIntValue("keyCode"), +// obj.getIntValue("repeatCount"), +// obj.getIntValue("metaState"), +// obj.getIntValue("deviceId"), +// obj.getIntValue("scanCode"), +// obj.getIntValue("flags"), +// obj.getIntValue("source") +// ); +// } +// else { +// /** +// public static MotionEvent obtain(long downTime, long eventTime, int action, +// float x, float y, float pressure, float size, int metaState, +// float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, +// int displayId) +// */ +// +// //居然编译报错,和 +// // static public MotionEvent obtain(long downTime, long eventTime, +// // int action, int pointerCount, PointerProperties[] pointerProperties, +// // PointerCoords[] pointerCoords, int metaState, int buttonState, +// // float xPrecision, float yPrecision, int deviceId, +// // int edgeFlags, int source, int displayId, int flags) +// //冲突,实际上类型没传错 +// +// // event = MotionEvent.obtain(obj.getLongValue("downTime"), obj.getLongValue("eventTime"), obj.getIntValue("action"), +// // obj.getFloatValue("x"), obj.getFloatValue("y"), obj.getFloatValue("pressure"), obj.getFloatValue("size"), obj.getIntValue("metaState"), +// // obj.getFloatValue("xPrecision"), obj.getFloatValue("yPrecision"), obj.getIntValue("deviceId"), obj.getIntValue("edgeFlags"), obj.getIntValue("source"), +// // obj.getIntValue("displayId")); +// +// event = MotionEvent.obtain( +// obj.getLongValue("downTime"), +// obj.getLongValue("eventTime"), +// obj.getIntValue("action"), +//// obj.getIntValue("pointerCount"), +// obj.getFloatValue("x"), +// obj.getFloatValue("y"), +// obj.getFloatValue("pressure"), +// obj.getFloatValue("size"), +// obj.getIntValue("metaState"), +// obj.getFloatValue("xPrecision"), +// obj.getFloatValue("yPrecision"), +// obj.getIntValue("deviceId"), +// obj.getIntValue("edgeFlags") +//// obj.getIntValue("source"), +//// obj.getIntValue("displayId") +// ); +// ((MotionEvent) event).setSource(obj.getIntValue("source")); +//// ((MotionEvent) event).setEdgeFlags(obj.getIntValue("edgeFlags")); +// +// } +// +// +//// list.add(event); +// +// long time = obj.getIntValue("time"); +// if (i <= 0) { +// firstEventNode = new Node<>(null, event, null); +// eventNode = firstEventNode; +// } +// else if (i >= touchList.size() - 1) { +// lastTime = time; +// lastCurTime = firstCurTime + lastTime - firstTime; +// } +// +// eventNode.next = new Node<>(eventNode, event, null); +// eventNode = eventNode.next; +// +// //通过遍历数组来实现 +//// Message msg = handler.obtainMessage(); +//// msg.obj = event; +//// handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); +// } +// +// //通过递归链表来实现 +// Message msg = handler.obtainMessage(); +// msg.obj = firstEventNode; +// handler.sendMessage(msg); +// +// } +// } +// +// +// +// @Override +// public boolean onKeyDown(int keyCode, KeyEvent event) { +// addInputEvent(event, this); +// return super.onKeyDown(keyCode, event); +// } +// +// +// @Override +// public boolean onKeyUp(int keyCode, KeyEvent event) { +// addInputEvent(event, this); +// return super.onKeyUp(keyCode, event); +// } +// +// private JSONArray addInputEvent(InputEvent ie, Activity activity) { +// int dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; +// int orientation = activity == null ? Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; // // JSONObject obj = new JSONObject(true); // obj.put("id", - System.currentTimeMillis()); // obj.put("flowId", flowId); -// obj.put("action", event.getAction()); -// obj.put("x", (int) event.getX()); -// obj.put("y", (int) relativeY); -// obj.put("dividerY", (int) dividerY); -// obj.put("rawX", (int) event.getRawX()); -// obj.put("rawY", (int) event.getRawY()); // obj.put("time", System.currentTimeMillis()); -// obj.put("downTime", event.getDownTime()); -// obj.put("eventTime", event.getEventTime()); -// obj.put("metaState", event.getMetaState()); -// obj.put("size", event.getSize()); -// obj.put("source", event.getSource()); -// obj.put("pressure", event.getPressure()); -// obj.put("deviceId", event.getDeviceId()); -// obj.put("xPrecision", event.getXPrecision()); -// obj.put("yPrecision", event.getYPrecision()); -// obj.put("pointerCount", event.getPointerCount()); -// obj.put("edgeFlags", event.getEdgeFlags()); - - addInputEvent(ie, activity); - - return activity != null; - } - - - - /** - * 根据手机的分辨率从 dp 的单位 转成为 px(像素) - */ - public int dip2px(float dpValue) { - final float scale = getResources().getDisplayMetrics().density; - return (int) (dpValue * scale + 0.5f); - } - - /** - * 根据手机的分辨率从 px(像素) 的单位 转成为 dp - */ - public int px2dip(float pxValue) { - final float scale = getResources().getDisplayMetrics().density; - return (int) (pxValue / scale + 0.5f); - } - - @Override - protected void onDestroy() { - cache.edit().remove(DIVIDER_Y).putFloat(DIVIDER_Y, rlUIAutoDivider.getY() + rlUIAutoDivider.getHeight()/2).apply(); - super.onDestroy(); - } - -// @Override -// public boolean dispatchTouchEvent(MotionEvent ev) { -// super.dispatchTouchEvent(ev); -// return false; -// } +// obj.put("orientation", orientation); +// obj.put("dividerY", dividerY); // -// @Override -// public boolean onTouchEvent(MotionEvent event) { -// super.onTouchEvent(event); -// return false; +// if (ie instanceof KeyEvent) { +// KeyEvent event = (KeyEvent) ie; +// obj.put("type", 1); +// +// //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< +// obj.put("action", event.getAction()); +// obj.put("downTime", event.getDownTime()); +// obj.put("eventTime", event.getEventTime()); +// obj.put("metaState", event.getMetaState()); +// obj.put("source", event.getSource()); +// obj.put("deviceId", event.getDeviceId()); +// //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> +// +// obj.put("keyCode", event.getKeyCode()); +// obj.put("scanCode", event.getScanCode()); +// obj.put("repeatCount", event.getRepeatCount()); +// //通过 keyCode 获取的 obj.put("number", event.getNumber()); +// obj.put("flags", event.getFlags()); +// //通过 mMetaState 获取的 obj.put("modifiers", event.getModifiers()); +// //通过 mKeyCode 获取的 obj.put("displayLabel", event.getDisplayLabel()); +// //通过 mMetaState 获取的 obj.put("unicodeChar", event.getUnicodeChar()); +// } +// else if (ie instanceof MotionEvent) { +// MotionEvent event = (MotionEvent) ie; +// obj.put("type", 0); +// +// //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< +// obj.put("action", event.getAction()); +// obj.put("downTime", event.getDownTime()); +// obj.put("eventTime", event.getEventTime()); +// obj.put("metaState", event.getMetaState()); +// obj.put("source", event.getSource()); +// obj.put("deviceId", event.getDeviceId()); +// //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> +// +// float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); +// +// obj.put("x", (int) event.getX()); +// obj.put("y", (int) relativeY); +// obj.put("rawX", (int) event.getRawX()); +// obj.put("rawY", (int) event.getRawY()); +// obj.put("size", event.getSize()); +// obj.put("pressure", event.getPressure()); +// obj.put("xPrecision", event.getXPrecision()); +// obj.put("yPrecision", event.getYPrecision()); +// obj.put("pointerCount", event.getPointerCount()); +// obj.put("edgeFlags", event.getEdgeFlags()); +// } +// +// if (touchList == null) { +// touchList = new JSONArray(); +// } +// touchList.add(obj); +// +// return touchList; // } - private Node firstEventNode; - private Node eventNode; - - private long firstTime = 0; - private long lastTime = 0; - private long firstCurTime = 0; - private long lastCurTime = 0; - public void recover(JSONArray touchList) { - isRecovering = true; - -// List list = new LinkedList<>(); - - showCover(true, DemoApplication.getInstance().getCurrentActivity()); - - JSONObject first = touchList == null || touchList.isEmpty() ? null : touchList.getJSONObject(0); - firstTime = first == null ? 0 : first.getLongValue("time"); - - firstCurTime = 0; - if (firstTime > 0) { - firstCurTime = System.currentTimeMillis(); - pbUIAutoDivider.setVisibility(View.VISIBLE); - - for (int i = 0; i < touchList.size(); i++) { - JSONObject obj = touchList.getJSONObject(i); - - InputEvent event; - if (obj.getIntValue("type") == 1) { - /** - public KeyEvent(long downTime, long eventTime, int action, - int code, int repeat, int metaState, - int deviceId, int scancode, int flags, int source) { - mDownTime = downTime; - mEventTime = eventTime; - mAction = action; - mKeyCode = code; - mRepeatCount = repeat; - mMetaState = metaState; - mDeviceId = deviceId; - mScanCode = scancode; - mFlags = flags; - mSource = source; - mDisplayId = INVALID_DISPLAY; - } - */ - event = new KeyEvent( - obj.getLongValue("downTime"), - obj.getLongValue("eventTime"), - obj.getIntValue("action"), - obj.getIntValue("keyCode"), - obj.getIntValue("repeatCount"), - obj.getIntValue("metaState"), - obj.getIntValue("deviceId"), - obj.getIntValue("scanCode"), - obj.getIntValue("flags"), - obj.getIntValue("source") - ); - } - else { - /** - public static MotionEvent obtain(long downTime, long eventTime, int action, - float x, float y, float pressure, float size, int metaState, - float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, - int displayId) - */ - - //居然编译报错,和 - // static public MotionEvent obtain(long downTime, long eventTime, - // int action, int pointerCount, PointerProperties[] pointerProperties, - // PointerCoords[] pointerCoords, int metaState, int buttonState, - // float xPrecision, float yPrecision, int deviceId, - // int edgeFlags, int source, int displayId, int flags) - //冲突,实际上类型没传错 - - // event = MotionEvent.obtain(obj.getLongValue("downTime"), obj.getLongValue("eventTime"), obj.getIntValue("action"), - // obj.getFloatValue("x"), obj.getFloatValue("y"), obj.getFloatValue("pressure"), obj.getFloatValue("size"), obj.getIntValue("metaState"), - // obj.getFloatValue("xPrecision"), obj.getFloatValue("yPrecision"), obj.getIntValue("deviceId"), obj.getIntValue("edgeFlags"), obj.getIntValue("source"), - // obj.getIntValue("displayId")); - - event = MotionEvent.obtain( - obj.getLongValue("downTime"), - obj.getLongValue("eventTime"), - obj.getIntValue("action"), -// obj.getIntValue("pointerCount"), - obj.getFloatValue("x"), - obj.getFloatValue("y"), - obj.getFloatValue("pressure"), - obj.getFloatValue("size"), - obj.getIntValue("metaState"), - obj.getFloatValue("xPrecision"), - obj.getFloatValue("yPrecision"), - obj.getIntValue("deviceId"), - obj.getIntValue("edgeFlags") -// obj.getIntValue("source"), -// obj.getIntValue("displayId") - ); - ((MotionEvent) event).setSource(obj.getIntValue("source")); -// ((MotionEvent) event).setEdgeFlags(obj.getIntValue("edgeFlags")); - - } - - -// list.add(event); - - long time = obj.getIntValue("time"); - if (i <= 0) { - firstEventNode = new Node<>(null, event, null); - eventNode = firstEventNode; - } - else if (i >= touchList.size() - 1) { - lastTime = time; - lastCurTime = firstCurTime + lastTime - firstTime; - } - - eventNode.next = new Node<>(eventNode, event, null); - eventNode = eventNode.next; - - //通过遍历数组来实现 -// Message msg = handler.obtainMessage(); -// msg.obj = event; -// handler.sendMessageDelayed(msg, i <= 0 ? 0 : time - firstTime); - } - - //通过递归链表来实现 - Message msg = handler.obtainMessage(); - msg.obj = firstEventNode; - handler.sendMessage(msg); - - } - } - - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - addInputEvent(event, this); - return super.onKeyDown(keyCode, event); - } - - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - addInputEvent(event, this); - return super.onKeyUp(keyCode, event); - } - - private JSONArray addInputEvent(InputEvent ie, Activity activity) { - int dividerY = floatDivider.getY() + rlUIAutoDivider.getHeight()/2; - int orientation = activity == null ? Configuration.ORIENTATION_PORTRAIT : activity.getResources().getConfiguration().orientation; - - JSONObject obj = new JSONObject(true); - obj.put("id", - System.currentTimeMillis()); - obj.put("flowId", flowId); - obj.put("time", System.currentTimeMillis()); - obj.put("orientation", orientation); - obj.put("dividerY", dividerY); - - if (ie instanceof KeyEvent) { - KeyEvent event = (KeyEvent) ie; - obj.put("type", 1); - - //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< - obj.put("action", event.getAction()); - obj.put("downTime", event.getDownTime()); - obj.put("eventTime", event.getEventTime()); - obj.put("metaState", event.getMetaState()); - obj.put("source", event.getSource()); - obj.put("deviceId", event.getDeviceId()); - //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> - - obj.put("keyCode", event.getKeyCode()); - obj.put("scanCode", event.getScanCode()); - obj.put("repeatCount", event.getRepeatCount()); - //通过 keyCode 获取的 obj.put("number", event.getNumber()); - obj.put("flags", event.getFlags()); - //通过 mMetaState 获取的 obj.put("modifiers", event.getModifiers()); - //通过 mKeyCode 获取的 obj.put("displayLabel", event.getDisplayLabel()); - //通过 mMetaState 获取的 obj.put("unicodeChar", event.getUnicodeChar()); - } - else if (ie instanceof MotionEvent) { - MotionEvent event = (MotionEvent) ie; - obj.put("type", 0); - - //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 <<<<<<<<<<<<<<<<<< - obj.put("action", event.getAction()); - obj.put("downTime", event.getDownTime()); - obj.put("eventTime", event.getEventTime()); - obj.put("metaState", event.getMetaState()); - obj.put("source", event.getSource()); - obj.put("deviceId", event.getDeviceId()); - //虽然 KeyEvent 和 MotionEvent 都有,但都不在父类 InputEvent 中 >>>>>>>>>>>>>>>>>> - - float relativeY = event.getY() <= dividerY ? event.getY() : (event.getY() - screenHeight); - - obj.put("x", (int) event.getX()); - obj.put("y", (int) relativeY); - obj.put("rawX", (int) event.getRawX()); - obj.put("rawY", (int) event.getRawY()); - obj.put("size", event.getSize()); - obj.put("pressure", event.getPressure()); - obj.put("xPrecision", event.getXPrecision()); - obj.put("yPrecision", event.getYPrecision()); - obj.put("pointerCount", event.getPointerCount()); - obj.put("edgeFlags", event.getEdgeFlags()); - } - - if (touchList == null) { - touchList = new JSONArray(); - } - touchList.add(obj); - - return touchList; - } - - public static final int REQUEST_UI_AUTO_LIST = 1; @@ -839,7 +826,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { @Override public void run() { touchList = new JSONArray(); - recover(array); + DemoApplication.getInstance().recover(array); } }, 1000); } @@ -847,18 +834,18 @@ public void run() { } - - private static class Node { - E item; - Node next; - Node prev; - - Node(Node prev, E element, Node next) { - this.item = element; - this.next = next; - this.prev = prev; - } - } +// +// private static class Node { +// E item; +// Node next; +// Node prev; +// +// Node(Node prev, E element, Node next) { +// this.item = element; +// this.next = next; +// this.prev = prev; +// } +// } } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoBaseActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoBaseActivity.java new file mode 100644 index 000000000..5f9c3cfd1 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoBaseActivity.java @@ -0,0 +1,47 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon) + +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 apijson.demo.ui; + +import android.app.Activity; +import android.view.KeyEvent; + +import apijson.demo.application.DemoApplication; + +/**Activity 基类 + * @author Lemon + */ +public abstract class UIAutoBaseActivity extends Activity { + private static final String TAG = "UIAutoBaseActivity"; + + //只在 TouchLayout 中记录 +// @Override +// public boolean onTouchEvent(MotionEvent event) { +// DemoApplication.getInstance().onTouchEvent(event, this); +// return super.onTouchEvent(event); +// } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + DemoApplication.getInstance().onKeyDown(keyCode, event, this); + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + DemoApplication.getInstance().onKeyUp(keyCode, event, this); + return super.onKeyUp(keyCode, event); + } + +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java index 9113a2f0a..923e79e61 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UIAutoListActivity.java @@ -41,6 +41,7 @@ import apijson.demo.HttpManager; import apijson.demo.R; import apijson.demo.StringUtil; +import apijson.demo.InputUtil; import zuo.biao.apijson.JSON; import zuo.biao.apijson.JSONRequest; import zuo.biao.apijson.JSONResponse; @@ -229,15 +230,15 @@ public void run() { if (isTouch) { if (obj.getIntValue("type") == 1) { - list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) - + "\nkeyCode: " + TouchUtil.getKeyCodeName(obj.getIntValue("keyCode")) + ", scanCode: " + TouchUtil.getScanCodeName(obj.getIntValue("scanCode")) + ", dividerY: " + obj.getString("dividerY") - + "\nrepeatCount: " + obj.getString("repeatCount") + " " + TouchUtil.getOrientationName(obj.getIntValue("orientation")) + list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + InputUtil.getActionName(obj.getIntValue("action")) + + "\nkeyCode: " + InputUtil.getKeyCodeName(obj.getIntValue("keyCode")) + ", scanCode: " + InputUtil.getScanCodeName(obj.getIntValue("scanCode")) + ", dividerY: " + obj.getString("dividerY") + + "\nrepeatCount: " + obj.getString("repeatCount") + " " + InputUtil.getOrientationName(obj.getIntValue("orientation")) ); } else { - list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + TouchUtil.getActionName(obj.getIntValue("action")) + list.add("[" + state + "] " + new Date(obj.getLongValue("time")).toLocaleString() + " " + InputUtil.getActionName(obj.getIntValue("action")) + "\nx: " + obj.getString("x") + ", y: " + obj.getString("y") + ", dividerY: " + obj.getString("dividerY") - + "\npointerCount: " + obj.getString("pointerCount") + " " + TouchUtil.getOrientationName(obj.getIntValue("orientation")) + + "\npointerCount: " + obj.getString("pointerCount") + " " + InputUtil.getOrientationName(obj.getIntValue("orientation")) ); } } else { diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java index b5d46e6d0..aacdcdb00 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java @@ -50,7 +50,7 @@ * https://github.com/TommyLemon/UnitAuto * @author Lemon */ -public class UnitAutoActivity extends Activity implements HttpServerRequestCallback { +public class UnitAutoActivity extends UIAutoBaseActivity implements HttpServerRequestCallback { public static final String TAG = "UnitAutoActivity"; private static final String KEY_PORT = "KEY_PORT"; From 53882da1de00e911011d93400c023e74485eb57f Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 15 Aug 2020 20:21:10 +0800 Subject: [PATCH 0006/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=89=AB=E6=8F=8F=E4=B8=8D=E5=88=B0=E7=B1=BB?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=98=BE=E7=A4=BA=E5=92=8C=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=20IPV4=20=E5=9C=B0=E5=9D=80=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=A4=8D=E5=88=B6=E5=8F=8A=E5=85=B6=E5=AE=83=E4=BD=93?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/AndroidManifest.xml | 1 + .../src/main/java/apijson/demo/IPUtil.java | 77 ++++++++++++ .../main/java/apijson/demo/MethodUtil.java | 111 ++++++++++++++++++ .../java/apijson/demo/server/MethodUtil.java | 100 ++++++++++------ .../java/apijson/demo/ui/SelectActivity.java | 5 +- .../apijson/demo/ui/UnitAutoActivity.java | 76 +++++++++--- .../main/res/layout/unit_auto_activity.xml | 23 ++-- 7 files changed, 327 insertions(+), 66 deletions(-) create mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java create mode 100644 APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java diff --git a/APIJSON-Android/APIJSONTest/app/src/main/AndroidManifest.xml b/APIJSON-Android/APIJSONTest/app/src/main/AndroidManifest.xml index 2198b3bb9..707b98a5b 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/AndroidManifest.xml +++ b/APIJSON-Android/APIJSONTest/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ android:minSdkVersion="15" android:targetSdkVersion="21" /> + diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java new file mode 100644 index 000000000..0e363e1d7 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java @@ -0,0 +1,77 @@ +package apijson.demo; + +import android.content.Context; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +/** + * ======================================================= + * 版权:Copyright LiYing 2015-2016. All rights reserved. + * 作者:liying - liruoer2008@yeah.net + * 日期:2016/12/19 19:43 + * 版本:1.0 + * 描述:IP地址工具类 + * 备注: + * ======================================================= + */ +public class IPUtil { + + /** + * 获取本机IPv4地址 + * + * @param context + * @return 本机IPv4地址;null:无网络连接 + */ + public static String getIpAddress(Context context) { + // 获取WiFi服务 + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + // 判断WiFi是否开启 + if (wifiManager.isWifiEnabled()) { + // 已经开启了WiFi + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + int ipAddress = wifiInfo.getIpAddress(); + String ip = intToIp(ipAddress); + return ip; + } else { + // 未开启WiFi + return getIpAddress(); + } + } + + private static String intToIp(int ipAddress) { + return (ipAddress & 0xFF) + "." + + ((ipAddress >> 8) & 0xFF) + "." + + ((ipAddress >> 16) & 0xFF) + "." + + (ipAddress >> 24 & 0xFF); + } + + /** + * 获取本机IPv4地址 + * + * @return 本机IPv4地址;null:无网络连接 + */ + private static String getIpAddress() { + try { + NetworkInterface networkInterface; + InetAddress inetAddress; + for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { + networkInterface = en.nextElement(); + for (Enumeration enumIpAddr = networkInterface.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { + inetAddress = enumIpAddr.nextElement(); + if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) { + return inetAddress.getHostAddress(); + } + } + } + return null; + } catch (SocketException ex) { + ex.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java new file mode 100644 index 000000000..0d4493b59 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java @@ -0,0 +1,111 @@ +package apijson.demo; + +import com.alibaba.fastjson.JSONObject; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import apijson.demo.application.DemoApplication; +import dalvik.system.DexFile; + +public class MethodUtil extends apijson.demo.server.MethodUtil { + + static { + CLASS_LOADER_CALLBACK = new ClassLoaderCallback() { + + @Override + public Class loadClass(String className) { + return null; + } + + @Override + public List> loadClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException, IOException { + List> list = new ArrayList>(); + int index = className.indexOf("<"); + if (index >= 0) { + className = className.substring(0, index); + } + + boolean allPackage = isEmpty(packageOrFileName, true); + boolean allName = isEmpty(className, true); + + //将包名替换成目录 TODO 应该一层层查找进去,实时判断是 package 还是 class,如果已经是 class 还有下一级,应该用 $ 隔开内部类。简单点也可以认为大驼峰是类 + String fileName = allPackage ? "" : separator2dot(packageOrFileName); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + DexFile dex = new DexFile(DemoApplication.getInstance().getPackageResourcePath()); + Enumeration entries = dex.entries(); + while (entries.hasMoreElements()) { + String entryName = entries.nextElement(); + if (allPackage || entryName.startsWith(fileName)) { + Class entryClass = Class.forName(entryName, true, classLoader); + + if (allName || className.equals(entryClass.getSimpleName())) { + list.add(entryClass); + } + } + } + + return list; + } + }; + } + + public static JSONObject listMethod(String request) { + if (CLASS_LOADER_CALLBACK == null) { + CLASS_LOADER_CALLBACK = new ClassLoaderCallback() { + + @Override + public Class loadClass(String className) { + return null; + } + + @Override + public List> loadClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException, IOException { + List> list = new ArrayList>(); + int index = className.indexOf("<"); + if (index >= 0) { + className = className.substring(0, index); + } + + boolean allPackage = isEmpty(packageOrFileName, true); + boolean allName = isEmpty(className, true); + + //将包名替换成目录 TODO 应该一层层查找进去,实时判断是 package 还是 class,如果已经是 class 还有下一级,应该用 $ 隔开内部类。简单点也可以认为大驼峰是类 + String fileName = allPackage ? File.separator : dot2Separator(packageOrFileName); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + DexFile dex = new DexFile(DemoApplication.getInstance().getPackageResourcePath()); + Enumeration entries = dex.entries(); + while (entries.hasMoreElements()) { + String entryName = entries.nextElement(); + if (allPackage || entryName.startsWith(fileName)) { + Class entryClass = Class.forName(entryName, true, classLoader); + + if (allName || className.equals(entryClass.getSimpleName())) { + list.add(entryClass); + } + } + } + + return list; + } + }; + } + return apijson.demo.server.MethodUtil.listMethod(request); + } + + public static void invokeMethod(String request, Object instance, Listener listener) throws Exception { + apijson.demo.server.MethodUtil.invokeMethod(request, instance, listener); + } + + public static void invokeMethod(JSONObject request, Object instance, Listener listener) throws Exception { + apijson.demo.server.MethodUtil.invokeMethod(request, instance, listener); + } + +} \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java index 3d9ab48ea..517f93efb 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java @@ -1,13 +1,17 @@ package apijson.demo.server; -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import android.content.Context; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.util.TypeUtils; import java.io.File; +import java.io.IOException; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -20,6 +24,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -28,18 +33,20 @@ import java.util.Objects; import java.util.Set; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.alibaba.fastjson.annotation.JSONField; -import com.alibaba.fastjson.parser.Feature; -import com.alibaba.fastjson.parser.ParserConfig; -import com.alibaba.fastjson.util.TypeUtils; - +import dalvik.system.DexFile; +import dalvik.system.PathClassLoader; import zuo.biao.apijson.StringUtil; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + public class MethodUtil { + /**非null注解 * javax.validation.constraints.NotNull不在JDK里面,为了减少第三方库引用就在这里实现了一个替代品 * @author Lemon @@ -63,6 +70,12 @@ public interface Callback { JSONObject newErrorResult(Exception e); } + + public interface ClassLoaderCallback { + List> loadClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException, IOException; + Class loadClass(String className) throws ClassNotFoundException; + } + public static String KEY_CODE = "code"; public static String KEY_MSG = "msg"; @@ -88,24 +101,8 @@ public interface Callback { public static String KEY_CALL_MAP = "call(){}"; - public static Callback CALLBACK = new Callback() { - - @Override - public JSONObject newSuccessResult() { - JSONObject result = new JSONObject(true); - result.put(KEY_CODE, CODE_SUCCESS); - result.put(KEY_MSG, MSG_SUCCESS); - return result; - } - - @Override - public JSONObject newErrorResult(Exception e) { - JSONObject result = new JSONObject(true); - result.put(KEY_CODE, CODE_SERVER_ERROR); - result.put(KEY_MSG, e.getMessage()); - return result; - } - }; + public static ClassLoaderCallback CLASS_LOADER_CALLBACK; + public static Callback CALLBACK; // Map> public static final Map, Map> INSTANCE_MAP; @@ -113,6 +110,27 @@ public JSONObject newErrorResult(Exception e) { public static final Map> BASE_CLASS_MAP; public static final Map> CLASS_MAP; static { + CLASS_LOADER_CALLBACK = null; + CALLBACK = new Callback() { + + @Override + public JSONObject newSuccessResult() { + JSONObject result = new JSONObject(true); + result.put(KEY_CODE, CODE_SUCCESS); + result.put(KEY_MSG, MSG_SUCCESS); + return result; + } + + @Override + public JSONObject newErrorResult(Exception e) { + JSONObject result = new JSONObject(true); + result.put(KEY_CODE, CODE_SERVER_ERROR); + result.put(KEY_MSG, e.getMessage()); + return result; + } + }; + + INSTANCE_MAP = new HashMap<>(); PRIMITIVE_CLASS_MAP = new HashMap>(); @@ -582,12 +600,12 @@ public static JSONArray getMethodListGroupByClass(String pkgName, String clsName boolean allMethod = isEmpty(methodName, true); - List> classlist = findClassList(pkgName, clsName, true); + List> classList = findClassList(pkgName, clsName, true); JSONArray list = null; - if (classlist != null) { - list = new JSONArray(classlist.size()); + if (classList != null) { + list = new JSONArray(classList.size()); - for (Class cls : classlist) { + for (Class cls : classList) { if (cls == null) { continue; } @@ -637,6 +655,10 @@ public static String dot2Separator(String name) { return name == null ? null : name.replaceAll("\\.", File.separator); } + public static String separator2dot(String name) { + return name == null ? null : name.replaceAll(File.separator, "."); + } + // private void initTypesAndValues(JSONArray methodArgs, Class[] types, Object[] args) // throws IllegalArgumentException, ClassNotFoundException, IOException { // initTypesAndValues(methodArgs, types, args, false); @@ -876,7 +898,11 @@ public static Class findClass(String packageOrFileName, String className, boo * @return * @throws ClassNotFoundException */ - public static List> findClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException { + public static List> findClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException, IOException { + if (CLASS_LOADER_CALLBACK != null) { + return CLASS_LOADER_CALLBACK.loadClassList(packageOrFileName, className, ignoreError); + } + List> list = new ArrayList<>(); int index = className.indexOf("<"); diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java index 12de06e94..774376245 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/SelectActivity.java @@ -32,7 +32,6 @@ import apijson.demo.R; import apijson.demo.RequestUtil; import apijson.demo.StringUtil; -import apijson.demo.application.DemoApplication; import zuo.biao.apijson.JSON; /**选择Activity @@ -116,8 +115,8 @@ public boolean onLongClick(View v) { }); } - DemoApplication.getInstance().onUIAutoActivityCreate(this); - DemoApplication.getInstance().record(); +// DemoApplication.getInstance().onUIAutoActivityCreate(this); +// DemoApplication.getInstance().record(); } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java index aacdcdb00..8cc5e8189 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java @@ -41,10 +41,11 @@ import java.lang.reflect.Method; +import apijson.demo.IPUtil; +import apijson.demo.MethodUtil; import apijson.demo.R; import apijson.demo.StringUtil; import apijson.demo.application.DemoApplication; -import apijson.demo.server.MethodUtil; /**自动单元测试,需要用 UnitAuto 发请求到这个设备 * https://github.com/TommyLemon/UnitAuto @@ -73,6 +74,7 @@ public static Intent createIntent(Context context) { private TextView tvUnitResponse; private TextView tvUnitOrient; + private TextView tvUnitIP; private TextView etUnitPort; private View pbUnit; @Override @@ -88,6 +90,7 @@ protected void onCreate(Bundle savedInstanceState) { tvUnitResponse = findViewById(R.id.tvUnitResponse); tvUnitOrient = findViewById(R.id.tvUnitOrient); + tvUnitIP = findViewById(R.id.tvUnitIP); etUnitPort = findViewById(R.id.etUnitPort); pbUnit = findViewById(R.id.pbUnit); @@ -95,6 +98,7 @@ protected void onCreate(Bundle savedInstanceState) { SharedPreferences sp = getSharedPreferences(TAG, Context.MODE_PRIVATE); port = sp.getString(KEY_PORT, ""); + tvUnitIP.setText(IPUtil.getIpAddress(context) + ":"); etUnitPort.setText(port); pbUnit.setVisibility(View.GONE); @@ -114,33 +118,50 @@ protected void onResume() { onConfigurationChanged(getResources().getConfiguration()); } + @Override public void onConfigurationChanged(Configuration newConfig) { - tvUnitOrient.setText( - getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE - ? (getString(R.string.screen) + getString(R.string.horizontal)) - : getString(R.string.vertical) - ); + tvUnitOrient.setText(isLandscape() ? (getString(R.string.screen) + getString(R.string.horizontal)) : getString(R.string.vertical)); super.onConfigurationChanged(newConfig); } + + public void copy(View v) { StringUtil.copyText(context, StringUtil.getString((TextView) v)); } public void orient(View v) { - setRequestedOrientation(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE - ? ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); + setRequestedOrientation(isLandscape() ? ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); + } + + public void ip(View v) { + String ip = IPUtil.getIpAddress(context); + tvUnitIP.setText(ip + ":"); + + StringUtil.copyText(context, "http://" + ip + ":" + getPort()); } + private boolean isLandscape() { + return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } + private String port = "8080"; + private String getPort() { + String p = StringUtil.getTrimedString(etUnitPort); + if (StringUtil.isEmpty(p, true)) { + p = StringUtil.getTrimedString(etUnitPort.getHint()); + } + return StringUtil.isEmpty(p, true) ? "8080" : p; + } + + public void start(View v) { v.setEnabled(false); - port = StringUtil.getTrimedString(etUnitPort); try { - startServer(StringUtil.isEmpty(port, true) ? 8080 : Integer.valueOf(port)); + startServer(Integer.valueOf(getPort())); etUnitPort.setEnabled(false); pbUnit.setVisibility(View.VISIBLE); @@ -208,7 +229,12 @@ public void onRequest(final AsyncHttpServerRequest asyncHttpServerRequest, final @Override public void run() { if (isAlive) { //TODO 改为 ListView 展示,保证每次请求都能对齐 Request 和 Response 的显示 - tvUnitRequest.setText(StringUtil.getString(asyncHttpServerRequest) + "Content:\n" + zuo.biao.apijson.JSON.format(request) + "\n\n\n\n\n" + StringUtil.getString(tvUnitRequest)); + try { + tvUnitRequest.setText(StringUtil.getString(asyncHttpServerRequest) + "Content:\n" + zuo.biao.apijson.JSON.format(request)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitRequest)); + } + catch (Exception e) { + e.printStackTrace(); + } } } }); @@ -225,7 +251,12 @@ public void run() { send(asyncHttpServerResponse, "ok"); break; case "/method/list": - asyncHttpServerResponse.send("application/json; charset=utf-8", MethodUtil.listMethod(request).toJSONString()); + new Thread(new Runnable() { + @Override + public void run() { + send(asyncHttpServerResponse, MethodUtil.listMethod(request).toJSONString()); + } + }).start(); break; case "/method/invoke": MethodUtil.Listener listener = new MethodUtil.Listener() { @@ -249,12 +280,14 @@ public void complete(JSONObject data, Method method, MethodUtil.InterfaceProxy p String pkgName = req.getString("package"); String clsName = req.getString("class"); Class clazz = Class.forName(pkgName.replaceAll("/", ".") + "." + clsName); - if (clazz.isAssignableFrom(Activity.class)) { - instance = UnitAutoActivity.this; - } else if (clazz.isAssignableFrom(Application.class)) { - instance = DemoApplication.getInstance(); - } else { - instance = null; + + if (req.getBooleanValue("static") == false) { + if (Activity.class.isAssignableFrom(clazz) || Context.class.isAssignableFrom(clazz)) { + instance = DemoApplication.getInstance().getCurrentActivity(); + } + else if (Application.class.isAssignableFrom(clazz)) { + instance = DemoApplication.getInstance(); + } } } catch (Exception e) { @@ -294,7 +327,12 @@ private void send(AsyncHttpServerResponse asyncHttpServerResponse, String json) @Override public void run() { if (isAlive) { - tvUnitResponse.setText(StringUtil.getString(asyncHttpServerResponse) + "Content:\n" + zuo.biao.apijson.JSON.format(json) + "\n\n\n\n\n" + StringUtil.getString(tvUnitResponse)); + try { + tvUnitResponse.setText(StringUtil.getString(asyncHttpServerResponse) + "Content:\n" + zuo.biao.apijson.JSON.format(json)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitResponse)); + } + catch (Exception e) { + e.printStackTrace(); + } } } }); diff --git a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml index cb5b28233..dd43c9407 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml +++ b/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml @@ -24,7 +24,9 @@ android:background="@null" android:gravity="top|left" android:hint="request" - android:textSize="14sp" /> + android:textSize="14sp" + android:textIsSelectable="true" + /> @@ -72,23 +74,30 @@ /> Date: Sat, 15 Aug 2020 20:25:27 +0800 Subject: [PATCH 0007/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20MethodUtil=20=E6=89=AB=E6=8F=8F=20class=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/apijson/demo/MethodUtil.java | 42 ----------------- .../java/apijson/demo/server/MethodUtil.java | 47 ++++++++----------- 2 files changed, 19 insertions(+), 70 deletions(-) diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java index 0d4493b59..db66fcb4b 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java @@ -2,7 +2,6 @@ import com.alibaba.fastjson.JSONObject; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; @@ -56,47 +55,6 @@ public List> loadClassList(String packageOrFileName, String className, } public static JSONObject listMethod(String request) { - if (CLASS_LOADER_CALLBACK == null) { - CLASS_LOADER_CALLBACK = new ClassLoaderCallback() { - - @Override - public Class loadClass(String className) { - return null; - } - - @Override - public List> loadClassList(String packageOrFileName, String className, boolean ignoreError) throws ClassNotFoundException, IOException { - List> list = new ArrayList>(); - int index = className.indexOf("<"); - if (index >= 0) { - className = className.substring(0, index); - } - - boolean allPackage = isEmpty(packageOrFileName, true); - boolean allName = isEmpty(className, true); - - //将包名替换成目录 TODO 应该一层层查找进去,实时判断是 package 还是 class,如果已经是 class 还有下一级,应该用 $ 隔开内部类。简单点也可以认为大驼峰是类 - String fileName = allPackage ? File.separator : dot2Separator(packageOrFileName); - - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - DexFile dex = new DexFile(DemoApplication.getInstance().getPackageResourcePath()); - Enumeration entries = dex.entries(); - while (entries.hasMoreElements()) { - String entryName = entries.nextElement(); - if (allPackage || entryName.startsWith(fileName)) { - Class entryClass = Class.forName(entryName, true, classLoader); - - if (allName || className.equals(entryClass.getSimpleName())) { - list.add(entryClass); - } - } - } - - return list; - } - }; - } return apijson.demo.server.MethodUtil.listMethod(request); } diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java index 517f93efb..88194d5fb 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java +++ b/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java @@ -1,7 +1,5 @@ package apijson.demo.server; -import android.content.Context; - import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -24,7 +22,6 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -33,8 +30,6 @@ import java.util.Objects; import java.util.Set; -import dalvik.system.DexFile; -import dalvik.system.PathClassLoader; import zuo.biao.apijson.StringUtil; import static java.lang.annotation.ElementType.ANNOTATION_TYPE; @@ -101,8 +96,25 @@ public interface ClassLoaderCallback { public static String KEY_CALL_MAP = "call(){}"; - public static ClassLoaderCallback CLASS_LOADER_CALLBACK; - public static Callback CALLBACK; + public static ClassLoaderCallback CLASS_LOADER_CALLBACK = null; //不能在 static 代码块赋值,否则 MethodUtil 子类中 static 代码块对它赋值的代码不会执行! + public static Callback CALLBACK = new Callback() { //不能在 static 代码块赋值,否则 MethodUtil 子类中 static 代码块对它赋值的代码不会执行! + + @Override + public JSONObject newSuccessResult() { + JSONObject result = new JSONObject(true); + result.put(KEY_CODE, CODE_SUCCESS); + result.put(KEY_MSG, MSG_SUCCESS); + return result; + } + + @Override + public JSONObject newErrorResult(Exception e) { + JSONObject result = new JSONObject(true); + result.put(KEY_CODE, CODE_SERVER_ERROR); + result.put(KEY_MSG, e.getMessage()); + return result; + } + }; // Map> public static final Map, Map> INSTANCE_MAP; @@ -110,27 +122,6 @@ public interface ClassLoaderCallback { public static final Map> BASE_CLASS_MAP; public static final Map> CLASS_MAP; static { - CLASS_LOADER_CALLBACK = null; - CALLBACK = new Callback() { - - @Override - public JSONObject newSuccessResult() { - JSONObject result = new JSONObject(true); - result.put(KEY_CODE, CODE_SUCCESS); - result.put(KEY_MSG, MSG_SUCCESS); - return result; - } - - @Override - public JSONObject newErrorResult(Exception e) { - JSONObject result = new JSONObject(true); - result.put(KEY_CODE, CODE_SERVER_ERROR); - result.put(KEY_MSG, e.getMessage()); - return result; - } - }; - - INSTANCE_MAP = new HashMap<>(); PRIMITIVE_CLASS_MAP = new HashMap>(); From 23936a00e8c9f655e208ef2d7881bd8b59f6b002 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 16 Aug 2020 17:47:32 +0800 Subject: [PATCH 0008/1308] =?UTF-8?q?Android=EF=BC=9AAPIJSONTest=20?= =?UTF-8?q?=E4=B8=AD=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=8A=BD=E5=8F=96=E4=B8=BA=20UnitAuto-Apk=EF=BC=9B?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96UI=E6=B5=8B=E8=AF=95=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=9B=9E=E6=94=BE=E5=B4=A9=E6=BA=83=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../APIJSONTest/UnitAuto-Apk/.gitignore | 1 + .../APIJSONTest/UnitAuto-Apk/build.gradle | 28 + .../UnitAuto-Apk/proguard-rules.pro | 23 + .../UnitAuto-Apk/src/main/AndroidManifest.xml | 11 + .../src/main/java/unitauto/JSON.java | 299 ++++++ .../src/main/java/unitauto/Log.java | 74 ++ .../src/main/java/unitauto}/MethodUtil.java | 22 +- .../src/main/java/unitauto/StringUtil.java | 865 ++++++++++++++++++ .../src/main/java/unitauto/apk}/IPUtil.java | 2 +- .../main/java/unitauto/apk}/MethodUtil.java | 37 +- .../java/unitauto/apk}/UnitAutoActivity.java | 46 +- .../main/java/unitauto/apk/UnitAutoApp.java | 113 +++ .../main/res/layout/unit_auto_activity.xml | 10 +- .../src/main/res/values-en/strings.xml | 11 + .../src/main/res/values/dimens.xml | 7 + .../src/main/res/values/strings.xml | 13 + APIJSON-Android/APIJSONTest/app/build.gradle | 3 +- .../java/apijson/demo/ApplicationTest.java | 13 - .../app/src/main/AndroidManifest.xml | 27 +- .../main/java/apijson/demo/StringUtil.java | 19 +- .../demo/application/DemoApplication.java | 29 +- .../java/apijson/demo/ui/SelectActivity.java | 1 + .../apijson/demo/ui/UIAutoListActivity.java | 38 +- .../app/src/main/res/values-en/strings.xml | 8 - .../app/src/main/res/values/strings.xml | 8 - .../java/apijson/demo/ExampleUnitTest.java | 15 - APIJSON-Android/APIJSONTest/settings.gradle | 2 +- 27 files changed, 1596 insertions(+), 129 deletions(-) create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/.gitignore create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/build.gradle create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/proguard-rules.pro create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/AndroidManifest.xml create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/JSON.java create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/Log.java rename APIJSON-Android/APIJSONTest/{app/src/main/java/apijson/demo/server => UnitAuto-Apk/src/main/java/unitauto}/MethodUtil.java (98%) create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/StringUtil.java rename APIJSON-Android/APIJSONTest/{app/src/main/java/apijson/demo => UnitAuto-Apk/src/main/java/unitauto/apk}/IPUtil.java (99%) rename APIJSON-Android/APIJSONTest/{app/src/main/java/apijson/demo => UnitAuto-Apk/src/main/java/unitauto/apk}/MethodUtil.java (65%) rename APIJSON-Android/APIJSONTest/{app/src/main/java/apijson/demo/ui => UnitAuto-Apk/src/main/java/unitauto/apk}/UnitAutoActivity.java (87%) create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoApp.java rename APIJSON-Android/APIJSONTest/{app => UnitAuto-Apk}/src/main/res/layout/unit_auto_activity.xml (92%) create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/values-en/strings.xml create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/values/dimens.xml create mode 100644 APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/values/strings.xml delete mode 100644 APIJSON-Android/APIJSONTest/app/src/androidTest/java/apijson/demo/ApplicationTest.java delete mode 100644 APIJSON-Android/APIJSONTest/app/src/test/java/apijson/demo/ExampleUnitTest.java diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/.gitignore b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/.gitignore @@ -0,0 +1 @@ +/build diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/build.gradle b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/build.gradle new file mode 100644 index 000000000..a2b4dc169 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + defaultConfig { + minSdkVersion 21 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_1_8 + } + buildToolsVersion '29.0.0' +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.alibaba:fastjson:1.2.61' + compile 'com.koushikdutta.async:androidasync:2.+' +} diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/proguard-rules.pro b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/proguard-rules.pro new file mode 100644 index 000000000..1d9b5ede3 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/proguard-rules.pro @@ -0,0 +1,23 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-keep public class unitauto.** \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/AndroidManifest.xml b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/AndroidManifest.xml new file mode 100644 index 000000000..54a3c6a2c --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/JSON.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/JSON.java new file mode 100644 index 000000000..353014062 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/JSON.java @@ -0,0 +1,299 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +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 unitauto; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.serializer.SerializerFeature; + +import java.util.List; + + +/**阿里FastJSON封装类 防止解析时异常 + * @author Lemon + */ +public class JSON { + private static final String TAG = "JSON"; + + /**判断json格式是否正确 + * @param s + * @return + */ + public static boolean isJsonCorrect(String s) { + //太长 Log.i(TAG, "isJsonCorrect <<<< " + s + " >>>>>>>"); + if (s == null + // || s.equals("[]") + // || s.equals("{}") + || s.equals("") + || s.equals("[null]") + || s.equals("{null}") + || s.equals("null")) { + return false; + } + return true; + } + + /**获取有效的json + * @param s + * @return + */ + public static String getCorrectJson(String s) { + return getCorrectJson(s, false); + } + /**获取有效的json + * @param s + * @param isArray + * @return + */ + public static String getCorrectJson(String s, boolean isArray) { + s = StringUtil.getTrimedString(s); + // if (isArray) { + // while (s.startsWith("\"")) { + // s = s.substring(1); + // } + // while (s.endsWith("\"")) { + // s = s.substring(0, s.length() - 1); + // } + // } + return s;//isJsonCorrect(s) ? s : null; + } + + /** + * @param obj + * @return + */ + public static Object parse(Object obj) { + int features = com.alibaba.fastjson.JSON.DEFAULT_PARSER_FEATURE; + features |= Feature.OrderedField.getMask(); + try { + return com.alibaba.fastjson.JSON.parse(obj instanceof String ? (String) obj : toJSONString(obj), features); + } catch (Exception e) { + Log.i(TAG, "parse catch \n" + e.getMessage()); + } + return null; + } + /**obj转JSONObject + * @param obj + * @return + */ + public static JSONObject parseObject(Object obj) { + if (obj instanceof JSONObject) { + return (JSONObject) obj; + } + return parseObject(toJSONString(obj)); + } + /**json转JSONObject + * @param json + * @return + */ + public static JSONObject parseObject(String json) { + int features = com.alibaba.fastjson.JSON.DEFAULT_PARSER_FEATURE; + features |= Feature.OrderedField.getMask(); + return parseObject(json, features); + } + /**json转JSONObject + * @param json + * @param features + * @return + */ + public static JSONObject parseObject(String json, int features) { + try { + return com.alibaba.fastjson.JSON.parseObject(getCorrectJson(json), JSONObject.class, features); + } catch (Exception e) { + Log.i(TAG, "parseObject catch \n" + e.getMessage()); + } + return null; + } + + /**JSONObject转实体类 + * @param object + * @param clazz + * @return + */ + public static T parseObject(JSONObject object, Class clazz) { + return parseObject(toJSONString(object), clazz); + } + /**json转实体类 + * @param json + * @param clazz + * @return + */ + public static T parseObject(String json, Class clazz) { + if (clazz == null) { + Log.e(TAG, "parseObject clazz == null >> return null;"); + } else { + try { + int features = com.alibaba.fastjson.JSON.DEFAULT_PARSER_FEATURE; + features |= Feature.OrderedField.getMask(); + return com.alibaba.fastjson.JSON.parseObject(getCorrectJson(json), clazz, features); + } catch (Exception e) { + Log.i(TAG, "parseObject catch \n" + e.getMessage()); + } + } + return null; + } + + /**list转JSONArray + * @param list + * @return + */ + public static JSONArray parseArray(List list) { + return new JSONArray(list); + } + /**obj转JSONArray + * @param obj + * @return + */ + public static JSONArray parseArray(Object obj) { + if (obj instanceof JSONArray) { + return (JSONArray) obj; + } + return parseArray(toJSONString(obj)); + } + /**json转JSONArray + * @param json + * @return + */ + public static JSONArray parseArray(String json) { + try { + return com.alibaba.fastjson.JSON.parseArray(getCorrectJson(json, true)); + } catch (Exception e) { + Log.i(TAG, "parseArray catch \n" + e.getMessage()); + } + return null; + } + /**JSONArray转实体类列表 + * @param array + * @param clazz + * @return + */ + public static List parseArray(JSONArray array, Class clazz) { + return parseArray(toJSONString(array), clazz); + } + /**json转实体类列表 + * @param json + * @param clazz + * @return + */ + public static List parseArray(String json, Class clazz) { + if (clazz == null) { + Log.e(TAG, "parseArray clazz == null >> return null;"); + } else { + try { + return com.alibaba.fastjson.JSON.parseArray(getCorrectJson(json, true), clazz); + } catch (Exception e) { + Log.i(TAG, "parseArray catch \n" + e.getMessage()); + } + } + return null; + } + + /**实体类转json + * @param obj + * @return + */ + public static String toJSONString(Object obj) { + if (obj instanceof String) { + return (String) obj; + } + try { + return com.alibaba.fastjson.JSON.toJSONString(obj); + } catch (Exception e) { + Log.e(TAG, "toJSONString catch \n" + e.getMessage()); + } + return null; + } + + /**实体类转json + * @param obj + * @param features + * @return + */ + public static String toJSONString(Object obj, SerializerFeature... features) { + if (obj instanceof String) { + return (String) obj; + } + try { + return com.alibaba.fastjson.JSON.toJSONString(obj, features); + } catch (Exception e) { + Log.e(TAG, "parseArray catch \n" + e.getMessage()); + } + return null; + } + + /**格式化,显示更好看 + * @param json + * @return + */ + public static String format(String json) { + return format(parse(json)); + } + /**格式化,显示更好看 + * @param object + * @return + */ + public static String format(Object object) { + return toJSONString(object, SerializerFeature.PrettyFormat); + } + + /**判断是否为JSONObject + * @param obj instanceof String ? parseObject + * @return + */ + public static boolean isJSONObject(Object obj) { + if (obj instanceof JSONObject) { + return true; + } + if (obj instanceof String) { + try { + JSONObject json = parseObject((String) obj); + return json != null && json.isEmpty() == false; + } catch (Exception e) { + Log.e(TAG, "isJSONObject catch \n" + e.getMessage()); + } + } + + return false; + } + /**判断是否为JSONArray + * @param obj instanceof String ? parseArray + * @return + */ + public static boolean isJSONArray(Object obj) { + if (obj instanceof JSONArray) { + return true; + } + if (obj instanceof String) { + try { + JSONArray json = parseArray((String) obj); + return json != null && json.isEmpty() == false; + } catch (Exception e) { + Log.e(TAG, "isJSONArray catch \n" + e.getMessage()); + } + } + + return false; + } + + /**判断是否为 Boolean,Number,String 中的一种 + * @param obj + * @return + */ + public static boolean isBooleanOrNumberOrString(Object obj) { + return obj instanceof Boolean || obj instanceof Number || obj instanceof String; + } + +} diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/Log.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/Log.java new file mode 100644 index 000000000..96cf7bc22 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/Log.java @@ -0,0 +1,74 @@ +/*Copyright ©2015 TommyLemon(https://github.com/TommyLemon) + +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 unitauto; + +/**测试用Log + * @modifier Lemon + */ +public class Log { + + public static boolean DEBUG = true; + + /** + * @param TAG + * @param msg + */ + public static void d(String TAG, String msg) { + if (DEBUG) { + System.err.println(TAG + ".DEBUG: " + msg); + } + } + + /** + * @param TAG + * @param msg + */ + public static void v(String TAG, String msg) { + if (DEBUG) { + System.out.println(TAG + ".VERBOSE: " + msg); + } + } + + /** + * @param TAG + * @param msg + */ + public static void i(String TAG, String msg) { + if (DEBUG) { + System.out.println(TAG + ".INFO: " + msg); + } + } + + /** + * @param TAG + * @param msg + */ + public static void e(String TAG, String msg) { + if (DEBUG) { + System.err.println(TAG + ".ERROR: " + msg); + } + } + + /** + * @param TAG + * @param msg + */ + public static void w(String TAG, String msg) { + if (DEBUG) { + System.err.println(TAG + ".WARN: " + msg); + } + } + +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/MethodUtil.java similarity index 98% rename from APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java rename to APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/MethodUtil.java index 88194d5fb..33a039c51 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/server/MethodUtil.java +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/MethodUtil.java @@ -1,4 +1,18 @@ -package apijson.demo.server; +/*Copyright ©2020 TommyLemon(https://github.com/TommyLemon) + +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 unitauto; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; @@ -30,8 +44,6 @@ import java.util.Objects; import java.util.Set; -import zuo.biao.apijson.StringUtil; - import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; @@ -39,6 +51,10 @@ import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/**方法/函数的工具类 + * @author Lemon + */ public class MethodUtil { diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/StringUtil.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/StringUtil.java new file mode 100644 index 000000000..607c171af --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/StringUtil.java @@ -0,0 +1,865 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +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 unitauto; + +import java.io.File; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.regex.Pattern; + +/**通用字符串(String)相关类,为null时返回"" + * @author Lemon + * @use StringUtil. + */ +public class StringUtil { + private static final String TAG = "StringUtil"; + + public StringUtil() { + } + + public static final String UTF_8 = "utf-8"; + + public static final String EMPTY = "无"; + public static final String UNKNOWN = "未知"; + public static final String UNLIMITED = "不限"; + + public static final String I = "我"; + public static final String YOU = "你"; + public static final String HE = "他"; + public static final String SHE = "她"; + public static final String IT = "它"; + + public static final String MALE = "男"; + public static final String FEMALE = "女"; + + public static final String TODO = "未完成"; + public static final String DONE = "已完成"; + + public static final String FAIL = "失败"; + public static final String SUCCESS = "成功"; + + public static final String SUNDAY = "日"; + public static final String MONDAY = "一"; + public static final String TUESDAY = "二"; + public static final String WEDNESDAY = "三"; + public static final String THURSDAY = "四"; + public static final String FRIDAY = "五"; + public static final String SATURDAY = "六"; + + public static final String YUAN = "元"; + + + private static String currentString = ""; + /**获取刚传入处理后的string + * @must 上个影响currentString的方法 和 这个方法都应该在同一线程中,否则返回值可能不对 + * @return + */ + public static String getCurrentString() { + return currentString == null ? "" : currentString; + } + + //获取string,为null时返回"" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**获取string,为null则返回"" + * @param object + * @return + */ + public static String getString(Object object) { + return object == null ? "" : object.toString(); + } + /**获取string,为null则返回"" + * @param cs + * @return + */ + public static String getString(CharSequence cs) { + return cs == null ? "" : cs.toString(); + } + /**获取string,为null则返回"" + * @param s + * @return + */ + public static String getString(String s) { + return s == null ? "" : s; + } + /**获取string,为null则返回"" + * ignoreEmptyItem = false; + * split = "," + * @param array + * @return {@link #getString(Object[], boolean)} + */ + public static String getString(Object[] array) { + return getString(array, false); + } + /**获取string,为null则返回"" + * split = "," + * @param array + * @param ignoreEmptyItem + * @return {@link #getString(Object[], boolean)} + */ + public static String getString(Object[] array, boolean ignoreEmptyItem) { + return getString(array, null, ignoreEmptyItem); + } + /**获取string,为null则返回"" + * ignoreEmptyItem = false; + * @param array + * @param split + * @return {@link #getString(Object[], String, boolean)} + */ + public static String getString(Object[] array, String split) { + return getString(array, split, false); + } + /**获取string,为null则返回"" + * @param array + * @param split + * @param ignoreEmptyItem + * @return + */ + public static String getString(Object[] array, String split, boolean ignoreEmptyItem) { + String s = ""; + if (array != null) { + if (split == null) { + split = ","; + } + for (int i = 0; i < array.length; i++) { + if (ignoreEmptyItem && isEmpty(array[i], true)) { + continue; + } + s += ((i > 0 ? split : "") + array[i]); + } + } + return getString(s); + } + + //获取string,为null时返回"" >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + //获取去掉前后空格后的string<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**获取去掉前后空格后的string,为null则返回"" + * @param object + * @return + */ + public static String getTrimedString(Object object) { + return getTrimedString(getString(object)); + } + /**获取去掉前后空格后的string,为null则返回"" + * @param cs + * @return + */ + public static String getTrimedString(CharSequence cs) { + return getTrimedString(getString(cs)); + } + /**获取去掉前后空格后的string,为null则返回"" + * @param s + * @return + */ + public static String getTrimedString(String s) { + return getString(s).trim(); + } + + //获取去掉前后空格后的string>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //获取去掉所有空格后的string <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**获取去掉所有空格后的string,为null则返回"" + * @param object + * @return + */ + public static String getNoBlankString(Object object) { + return getNoBlankString(getString(object)); + } + /**获取去掉所有空格后的string,为null则返回"" + * @param cs + * @return + */ + public static String getNoBlankString(CharSequence cs) { + return getNoBlankString(getString(cs)); + } + /**获取去掉所有空格后的string,为null则返回"" + * @param s + * @return + */ + public static String getNoBlankString(String s) { + return getString(s).replaceAll("\\s", ""); + } + + //获取去掉所有空格后的string >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //获取string的长度<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**获取string的长度,为null则返回0 + * @param object + * @param trim + * @return + */ + public static int getLength(Object object, boolean trim) { + return getLength(getString(object), trim); + } + /**获取string的长度,为null则返回0 + * @param cs + * @param trim + * @return + */ + public static int getLength(CharSequence cs, boolean trim) { + return getLength(getString(cs), trim); + } + /**获取string的长度,为null则返回0 + * @param s + * @param trim + * @return + */ + public static int getLength(String s, boolean trim) { + s = trim ? getTrimedString(s) : s; + return getString(s).length(); + } + + //获取string的长度>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //判断字符是否为空 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**判断字符是否为空 + * @param object + * @param trim + * @return + */ + public static boolean isEmpty(Object object, boolean trim) { + return isEmpty(getString(object), trim); + } + /**判断字符是否为空 + * @param cs + * @param trim + * @return + */ + public static boolean isEmpty(CharSequence cs, boolean trim) { + return isEmpty(getString(cs), trim); + } + /**判断字符是否为空 + * @param s + * @param trim + * @return + */ + public static boolean isEmpty(String s, boolean trim) { + // Log.i(TAG, "getTrimedString s = " + s); + if (s == null) { + return true; + } + if (trim) { + s = s.trim(); + } + if (s.isEmpty()) { + return true; + } + + currentString = s; + + return false; + } + + //判断字符是否为空 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + //判断字符是否非空 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**判断字符是否非空 + * @param object + * @param trim + * @return + */ + public static boolean isNotEmpty(Object object, boolean trim) { + return isNotEmpty(getString(object), trim); + } + /**判断字符是否非空 + * @param cs + * @param trim + * @return + */ + public static boolean isNotEmpty(CharSequence cs, boolean trim) { + return isNotEmpty(getString(cs), trim); + } + /**判断字符是否非空 + * @param s + * @param trim + * @return + */ + public static boolean isNotEmpty(String s, boolean trim) { + return ! isEmpty(s, trim); + } + + //判断字符是否非空 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //判断字符类型 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + public static final Pattern PATTERN_NUMBER; + public static final Pattern PATTERN_PHONE; + public static final Pattern PATTERN_EMAIL; + public static final Pattern PATTERN_ID_CARD; + public static final Pattern PATTERN_ALPHA; + public static final Pattern PATTERN_PASSWORD; //TODO + public static final Pattern PATTERN_NAME; + public static final Pattern PATTERN_ALPHA_BIG; + public static final Pattern PATTERN_ALPHA_SMALL; + static { + PATTERN_NUMBER = Pattern.compile("^[0-9]+$"); + PATTERN_ALPHA = Pattern.compile("^[a-zA-Z]+$"); + PATTERN_ALPHA_BIG = Pattern.compile("^[A-Z]+$"); + PATTERN_ALPHA_SMALL = Pattern.compile("^[a-z]+$"); + PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_]+$");//已用55个中英字符测试通过 + PATTERN_PHONE = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0-2,5-9])|(17[0-9]))\\d{8}$"); + PATTERN_EMAIL = Pattern.compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"); + PATTERN_ID_CARD = Pattern.compile("(^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{2}$)"); + PATTERN_PASSWORD = Pattern.compile("^[0-9a-zA-Z]+$"); + } + + /**判断手机格式是否正确 + * @param phone + * @return + */ + public static boolean isPhone(String phone) { + if (isNotEmpty(phone, true) == false) { + return false; + } + + currentString = phone; + return PATTERN_PHONE.matcher(phone).matches(); + } + /**判断手机格式是否正确 + * @param s + * @return + */ + public static boolean isPassword(String s) { + return getLength(s, false) >= 6 && PATTERN_PASSWORD.matcher(s).matches(); + } + /**判断是否全是数字密码 + * @param s + * @return + */ + public static boolean isNumberPassword(String s) { + return getLength(s, false) == 6 && isNumer(s); + } + /**判断email格式是否正确 + * @param email + * @return + */ + public static boolean isEmail(String email) { + if (isNotEmpty(email, true) == false) { + return false; + } + + currentString = email; + return PATTERN_EMAIL.matcher(email).matches(); + } + + + /**判断是否全是验证码 + * @param s + * @return + */ + public static boolean isVerify(String s) { + return getLength(s, false) >= 4 && isNumer(s); + } + /**判断是否全是数字 + * @param s + * @return + */ + public static boolean isNumer(String s) { + if (isNotEmpty(s, true) == false) { + return false; + } + + currentString = s; + return PATTERN_NUMBER.matcher(s).matches(); + } + /**判断是否全是字母 + * @param s + * @return + */ + public static boolean isAlpha(String s) { + if (isEmpty(s, true)) { + return false; + } + + currentString = s; + return PATTERN_ALPHA.matcher(s).matches(); + } + /**判断是否全是数字或字母 + * @param s + * @return + */ + public static boolean isNumberOrAlpha(String s) { + return isNumer(s) || isAlpha(s); + } + + /**判断是否为代码名称,只能包含字母,数字或下划线 + * @param s + * @return + */ + public static boolean isName(String s) { + return s != null && PATTERN_NAME.matcher(s).matches(); + } + /**判断是否为首字母大写的代码名称 + * @param s + * @return + */ + public static boolean isBigName(String s) { + s = getString(s); + if (s.isEmpty() || PATTERN_ALPHA_BIG.matcher(s.substring(0, 1)).matches() == false) { + return false; + } + return s.length() <= 1 ? true : isName(s.substring(1)); + } + /**判断是否为首字母小写的代码名称 + * @param s + * @return + */ + public static boolean isSmallName(String s) { + s = getString(s); + if (s.isEmpty() || PATTERN_ALPHA_SMALL.matcher(s.substring(0, 1)).matches() == false) { + return false; + } + return s.length() <= 1 ? true : isName(s.substring(1)); + } + + + /**判断字符类型是否是身份证号 + * @param number + * @return + */ + public static boolean isIDCard(String number) { + if (isNumberOrAlpha(number) == false) { + return false; + } + number = getString(number); + if (number.length() == 15) { + Log.i(TAG, "isIDCard number.length() == 15 old IDCard"); + currentString = number; + return true; + } + if (number.length() == 18) { + currentString = number; + return true; + } + + return false; + } + + public static final String HTTP = "http"; + public static final String URL_PREFIX = "http://"; + public static final String URL_PREFIXs = "https://"; + public static final String URL_STAFFIX = URL_PREFIX; + public static final String URL_STAFFIXs = URL_PREFIXs; + /**判断字符类型是否是网址 + * @param url + * @return + */ + public static boolean isUrl(String url) { + if (isNotEmpty(url, true) == false) { + return false; + } else if (! url.startsWith(URL_PREFIX) && ! url.startsWith(URL_PREFIXs)) { + return false; + } + + currentString = url; + return true; + } + + public static final String FILE_PATH_PREFIX = "file://"; + /**判断文件路径是否存在 + * @param path + * @return + */ + public static boolean isFilePathExist(String path) { + return StringUtil.isFilePath(path) && new File(path).exists(); + } + + public static final String SEPARATOR = "/"; + /**判断是否为路径 + * @param path + * @return + */ + public static boolean isPath(String path) { + return StringUtil.isNotEmpty(path, true) && path.contains(SEPARATOR) + && path.contains(SEPARATOR + SEPARATOR) == false && path.endsWith(SEPARATOR) == false; + } + + /**判断字符类型是否是路径 + * @param path + * @return + */ + public static boolean isFilePath(String path) { + if (isNotEmpty(path, true) == false) { + return false; + } + + if (! path.contains(".") || path.endsWith(".")) { + return false; + } + + currentString = path; + + return true; + } + + //判断字符类型 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //提取特殊字符<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**去掉string内所有非数字类型字符 + * @param object + * @return + */ + public static String getNumber(Object object) { + return getNumber(getString(object)); + } + /**去掉string内所有非数字类型字符 + * @param cs + * @return + */ + public static String getNumber(CharSequence cs) { + return getNumber(getString(cs)); + } + /**去掉string内所有非数字类型字符 + * @param s + * @return + */ + public static String getNumber(String s) { + return getNumber(s, false); + } + /**去掉string内所有非数字类型字符 + * @param s + * @param onlyStart 中间有非数字时只获取前面的数字 + * @return + */ + public static String getNumber(String s, boolean onlyStart) { + if (isNotEmpty(s, true) == false) { + return ""; + } + + String numberString = ""; + String single; + for (int i = 0; i < s.length(); i++) { + single = s.substring(i, i + 1); + if (isNumer(single)) { + numberString += single; + } else { + if (onlyStart) { + return numberString; + } + } + } + + return numberString; + } + + //提取特殊字符>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + //校正(自动补全等)字符串<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + /**获取网址,自动补全 + * @param url + * @return + */ + public static String getCorrectUrl(String url) { + Log.i(TAG, "getCorrectUrl : \n" + url); + if (isNotEmpty(url, true) == false) { + return ""; + } + + // if (! url.endsWith("/") && ! url.endsWith(".html")) { + // url = url + "/"; + // } + + if (isUrl(url) == false) { + return URL_PREFIX + url; + } + return url; + } + + /**获取去掉所有 空格 、"-" 、"+86" 后的phone + * @param phone + * @return + */ + public static String getCorrectPhone(String phone) { + if (isNotEmpty(phone, true) == false) { + return ""; + } + + phone = getNoBlankString(phone); + phone = phone.replaceAll("-", ""); + if (phone.startsWith("+86")) { + phone = phone.substring(3); + } + return phone; + } + + + /**获取邮箱,自动补全 + * @param email + * @return + */ + public static String getCorrectEmail(String email) { + if (isNotEmpty(email, true) == false) { + return ""; + } + + email = getNoBlankString(email); + if (isEmail(email) == false && ! email.endsWith(".com")) { + email += ".com"; + } + + return email; + } + + + public static final int PRICE_FORMAT_DEFAULT = 0; + public static final int PRICE_FORMAT_PREFIX = 1; + public static final int PRICE_FORMAT_SUFFIX = 2; + public static final int PRICE_FORMAT_PREFIX_WITH_BLANK = 3; + public static final int PRICE_FORMAT_SUFFIX_WITH_BLANK = 4; + public static final String[] PRICE_FORMATS = { + "", "¥", "元", "¥ ", " 元" + }; + + /**获取价格,保留两位小数 + * @param price + * @return + */ + public static String getPrice(String price) { + return getPrice(price, PRICE_FORMAT_DEFAULT); + } + /**获取价格,保留两位小数 + * @param price + * @param formatType 添加单位(元) + * @return + */ + public static String getPrice(String price, int formatType) { + if (isNotEmpty(price, true) == false) { + return getPrice(0, formatType); + } + + //单独写到getCorrectPrice? <<<<<<<<<<<<<<<<<<<<<< + String correctPrice = ""; + String s; + for (int i = 0; i < price.length(); i++) { + s = price.substring(i, i + 1); + if (".".equals(s) || isNumer(s)) { + correctPrice += s; + } + } + //单独写到getCorrectPrice? >>>>>>>>>>>>>>>>>>>>>> + + Log.i(TAG, "getPrice <<<<<<<<<<<<<<<<<< correctPrice = " + correctPrice); + if (correctPrice.contains(".")) { + // if (correctPrice.startsWith(".")) { + // correctPrice = 0 + correctPrice; + // } + if (correctPrice.endsWith(".")) { + correctPrice = correctPrice.replaceAll(".", ""); + } + } + + Log.i(TAG, "getPrice correctPrice = " + correctPrice + " >>>>>>>>>>>>>>>>"); + return isNotEmpty(correctPrice, true) ? getPrice(new BigDecimal(0 + correctPrice), formatType) : getPrice(0, formatType); + } + /**获取价格,保留两位小数 + * @param price + * @return + */ + public static String getPrice(BigDecimal price) { + return getPrice(price, PRICE_FORMAT_DEFAULT); + } + /**获取价格,保留两位小数 + * @param price + * @return + */ + public static String getPrice(double price) { + return getPrice(price, PRICE_FORMAT_DEFAULT); + } + /**获取价格,保留两位小数 + * @param price + * @param formatType 添加单位(元) + * @return + */ + public static String getPrice(BigDecimal price, int formatType) { + return getPrice(price == null ? 0 : price.doubleValue(), formatType); + } + /**获取价格,保留两位小数 + * @param price + * @param formatType 添加单位(元) + * @return + */ + public static String getPrice(double price, int formatType) { + String s = new DecimalFormat("#########0.00").format(price); + switch (formatType) { + case PRICE_FORMAT_PREFIX: + return PRICE_FORMATS[PRICE_FORMAT_PREFIX] + s; + case PRICE_FORMAT_SUFFIX: + return s + PRICE_FORMATS[PRICE_FORMAT_SUFFIX]; + case PRICE_FORMAT_PREFIX_WITH_BLANK: + return PRICE_FORMATS[PRICE_FORMAT_PREFIX_WITH_BLANK] + s; + case PRICE_FORMAT_SUFFIX_WITH_BLANK: + return s + PRICE_FORMATS[PRICE_FORMAT_SUFFIX_WITH_BLANK]; + default: + return s; + } + } + + + /**分割路径 + * @param path + * @return + */ + public static String[] splitPath(String path) { + if (StringUtil.isNotEmpty(path, true) == false) { + return null; + } + return isPath(path) ? split(path, SEPARATOR) : new String[] {path}; + } + /**将s分割成String[] + * @param s + * @return + */ + public static String[] split(String s) { + return split(s, null); + } + /**将s用split分割成String[] + * trim = true; + * @param s + * @param split + * @return + */ + public static String[] split(String s, String split) { + return split(s, split, true); + } + /**将s用split分割成String[] + * @param s + * @param split + * @param trim 去掉前后两端的split + * @return + */ + public static String[] split(String s, String split, boolean trim) { + s = getString(s); + if (s.isEmpty()) { + return null; + } + if (isNotEmpty(split, false) == false) { + split = ","; + } + if (trim) { + while (s.startsWith(split)) { + s = s.substring(split.length()); + } + while (s.endsWith(split)) { + s = s.substring(0, s.length() - split.length()); + } + } + return s.contains(split) ? s.split(split) : new String[]{s}; + } + + /** + * @param key + * @param suffix + * @return key + suffix,第一个字母小写 + */ + public static String addSuffix(String key, String suffix) { + key = getNoBlankString(key); + if (key.isEmpty()) { + return firstCase(suffix); + } + return firstCase(key) + firstCase(suffix, true); + } + /** + * @param key + */ + public static String firstCase(String key) { + return firstCase(key, false); + } + /** + * @param key + * @param upper + * @return + */ + public static String firstCase(String key, boolean upper) { + key = getString(key); + if (key.isEmpty()) { + return ""; + } + + String first = key.substring(0, 1); + key = (upper ? first.toUpperCase() : first.toLowerCase()) + key.substring(1, key.length()); + + return key; + } + + /**全部大写 + * @param s + * @return + */ + public static String toUpperCase(String s) { + return toUpperCase(s, false); + } + /**全部大写 + * @param s + * @param trim + * @return + */ + public static String toUpperCase(String s, boolean trim) { + s = trim ? getTrimedString(s) : getString(s); + return s.toUpperCase(); + } + /**全部小写 + * @param s + * @return + */ + public static String toLowerCase(String s) { + return toLowerCase(s, false); + } + /**全部小写 + * @param s + * @return + */ + public static String toLowerCase(String s, boolean trim) { + s = trim ? getTrimedString(s) : getString(s); + return s.toLowerCase(); + } + + public static String concat(String left, String right) { + return concat(left, right, null); + } + public static String concat(String left, String right, String split) { + return concat(left, right, split, true); + } + public static String concat(String left, String right, boolean trim) { + return concat(left, right, null, trim); + } + public static String concat(String left, String right, String split, boolean trim) { + if (isEmpty(left, trim)) { + return right; + } + if (isEmpty(right, trim)) { + return left; + } + + if (split == null) { + split = ","; + } + return left + split + right; + } + + //校正(自动补全等)字符串>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/IPUtil.java similarity index 99% rename from APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java rename to APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/IPUtil.java index 0e363e1d7..c3d3442f4 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/IPUtil.java +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/IPUtil.java @@ -1,4 +1,4 @@ -package apijson.demo; +package unitauto.apk; import android.content.Context; import android.net.wifi.WifiInfo; diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/MethodUtil.java similarity index 65% rename from APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java rename to APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/MethodUtil.java index db66fcb4b..785e88ae2 100644 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/MethodUtil.java +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/MethodUtil.java @@ -1,16 +1,31 @@ -package apijson.demo; +/*Copyright ©2020 TommyLemon(https://github.com/TommyLemon) -import com.alibaba.fastjson.JSONObject; +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 unitauto.apk; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import apijson.demo.application.DemoApplication; import dalvik.system.DexFile; -public class MethodUtil extends apijson.demo.server.MethodUtil { + +/**针对 Apk 文件的方法/函数的工具类 + * @author Lemon + */ +public class MethodUtil extends unitauto.MethodUtil { static { CLASS_LOADER_CALLBACK = new ClassLoaderCallback() { @@ -36,7 +51,7 @@ public List> loadClassList(String packageOrFileName, String className, ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - DexFile dex = new DexFile(DemoApplication.getInstance().getPackageResourcePath()); + DexFile dex = new DexFile(UnitAutoApp.getApp().getPackageResourcePath()); Enumeration entries = dex.entries(); while (entries.hasMoreElements()) { String entryName = entries.nextElement(); @@ -54,16 +69,4 @@ public List> loadClassList(String packageOrFileName, String className, }; } - public static JSONObject listMethod(String request) { - return apijson.demo.server.MethodUtil.listMethod(request); - } - - public static void invokeMethod(String request, Object instance, Listener listener) throws Exception { - apijson.demo.server.MethodUtil.invokeMethod(request, instance, listener); - } - - public static void invokeMethod(JSONObject request, Object instance, Listener listener) throws Exception { - apijson.demo.server.MethodUtil.invokeMethod(request, instance, listener); - } - } \ No newline at end of file diff --git a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoActivity.java similarity index 87% rename from APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java rename to APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoActivity.java index 8cc5e8189..0f42ba30d 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitAutoActivity.java +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoActivity.java @@ -1,4 +1,4 @@ -/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon) +/*Copyright ©2020 TommyLemon(https://github.com/TommyLemon) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ See the License for the specific language governing permissions and limitations under the License.*/ -package apijson.demo.ui; +package unitauto.apk; import android.app.Activity; import android.app.Application; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -29,7 +31,6 @@ import android.widget.TextView; import android.widget.Toast; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.http.Headers; @@ -41,17 +42,15 @@ import java.lang.reflect.Method; -import apijson.demo.IPUtil; -import apijson.demo.MethodUtil; -import apijson.demo.R; -import apijson.demo.StringUtil; -import apijson.demo.application.DemoApplication; +import unitauto.JSON; +import unitauto.StringUtil; + /**自动单元测试,需要用 UnitAuto 发请求到这个设备 * https://github.com/TommyLemon/UnitAuto * @author Lemon */ -public class UnitAutoActivity extends UIAutoBaseActivity implements HttpServerRequestCallback { +public class UnitAutoActivity extends Activity implements HttpServerRequestCallback { public static final String TAG = "UnitAutoActivity"; private static final String KEY_PORT = "KEY_PORT"; @@ -128,7 +127,7 @@ public void onConfigurationChanged(Configuration newConfig) { public void copy(View v) { - StringUtil.copyText(context, StringUtil.getString((TextView) v)); + copyText(context, StringUtil.getString(((TextView) v).getText())); } public void orient(View v) { @@ -139,7 +138,22 @@ public void ip(View v) { String ip = IPUtil.getIpAddress(context); tvUnitIP.setText(ip + ":"); - StringUtil.copyText(context, "http://" + ip + ":" + getPort()); + copyText(context, "http://" + ip + ":" + getPort()); + } + + + /** + * @param value + */ + public static void copyText(Context context, String value) { + if (context == null || StringUtil.isEmpty(value, true)) { + Log.e("StringUtil", "copyText context == null || StringUtil.isNotEmpty(value, true) == false >> return;"); + return; + } + ClipData cd = ClipData.newPlainText("simple text", value); + ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager.setPrimaryClip(cd); + Toast.makeText(context, "已复制\n" + value, Toast.LENGTH_SHORT).show(); } @@ -149,7 +163,7 @@ private boolean isLandscape() { private String port = "8080"; private String getPort() { - String p = StringUtil.getTrimedString(etUnitPort); + String p = StringUtil.getTrimedString(etUnitPort.getText()); if (StringUtil.isEmpty(p, true)) { p = StringUtil.getTrimedString(etUnitPort.getHint()); } @@ -230,7 +244,7 @@ public void onRequest(final AsyncHttpServerRequest asyncHttpServerRequest, final public void run() { if (isAlive) { //TODO 改为 ListView 展示,保证每次请求都能对齐 Request 和 Response 的显示 try { - tvUnitRequest.setText(StringUtil.getString(asyncHttpServerRequest) + "Content:\n" + zuo.biao.apijson.JSON.format(request)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitRequest)); + tvUnitRequest.setText(StringUtil.getString(asyncHttpServerRequest) + "Content:\n" + JSON.format(request)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitRequest)); } catch (Exception e) { e.printStackTrace(); @@ -283,10 +297,10 @@ public void complete(JSONObject data, Method method, MethodUtil.InterfaceProxy p if (req.getBooleanValue("static") == false) { if (Activity.class.isAssignableFrom(clazz) || Context.class.isAssignableFrom(clazz)) { - instance = DemoApplication.getInstance().getCurrentActivity(); + instance = UnitAutoApp.getInstance().getCurrentActivity(); } else if (Application.class.isAssignableFrom(clazz)) { - instance = DemoApplication.getInstance(); + instance = UnitAutoApp.getApp(); } } } @@ -328,7 +342,7 @@ private void send(AsyncHttpServerResponse asyncHttpServerResponse, String json) public void run() { if (isAlive) { try { - tvUnitResponse.setText(StringUtil.getString(asyncHttpServerResponse) + "Content:\n" + zuo.biao.apijson.JSON.format(json)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitResponse)); + tvUnitResponse.setText(StringUtil.getString(asyncHttpServerResponse) + "Content:\n" + JSON.format(json)); //批量跑测试容易卡死,也没必要显示所有的,专注更好 + "\n\n\n\n\n" + StringUtil.getString(tvUnitResponse)); } catch (Exception e) { e.printStackTrace(); diff --git a/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoApp.java b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoApp.java new file mode 100644 index 000000000..c7ddc1f45 --- /dev/null +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/java/unitauto/apk/UnitAutoApp.java @@ -0,0 +1,113 @@ +/*Copyright ©2020 TommyLemon(https://github.com/TommyLemon) + +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 unitauto.apk; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import android.util.Log; + +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.List; + +/**Application + * @author Lemon + */ +public class UnitAutoApp extends Application { + private static final String TAG = "UnitAutoApp"; + + private static UnitAutoApp INSTANCE; + public static UnitAutoApp getInstance() { + return INSTANCE; + } + + private static Application APP; + public static Application getApp() { + return APP; + } + public static void init(Application app) { + APP = app; + + app.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { + + @Override + public void onActivityStarted(Activity activity) { + Log.v(TAG, "onActivityStarted activity = " + activity.getClass().getName()); + } + + @Override + public void onActivityStopped(Activity activity) { + Log.v(TAG, "onActivityStopped activity = " + activity.getClass().getName()); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + Log.v(TAG, "onActivitySaveInstanceState activity = " + activity.getClass().getName()); + } + + @Override + public void onActivityResumed(Activity activity) { + Log.v(TAG, "onActivityResumed activity = " + activity.getClass().getName()); + setCurrentActivity(activity); + } + + @Override + public void onActivityPaused(Activity activity) { + Log.v(TAG, "onActivityPaused activity = " + activity.getClass().getName()); + setCurrentActivity(ACTIVITY_LIST.isEmpty() ? null : ACTIVITY_LIST.get(ACTIVITY_LIST.size() - 1)); + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + Log.v(TAG, "onActivityCreated activity = " + activity.getClass().getName()); + ACTIVITY_LIST.add(activity); + } + + @Override + public void onActivityDestroyed(Activity activity) { + Log.v(TAG, "onActivityDestroyed activity = " + activity.getClass().getName()); + ACTIVITY_LIST.remove(activity); + } + + }); + + } + + + private static List ACTIVITY_LIST = new LinkedList<>(); + + private static WeakReference CURRENT_ACTIVITY_REF; + public static Activity getCurrentActivity() { + return CURRENT_ACTIVITY_REF == null ? null : CURRENT_ACTIVITY_REF.get(); + } + public static void setCurrentActivity(Activity activity) { + if (CURRENT_ACTIVITY_REF == null || ! activity.equals(CURRENT_ACTIVITY_REF.get())) { + CURRENT_ACTIVITY_REF = new WeakReference<>(activity); + } + } + + + + @Override + public void onCreate() { + super.onCreate(); + INSTANCE = this; + init(this); + } + + + +} diff --git a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/layout/unit_auto_activity.xml similarity index 92% rename from APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml rename to APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/layout/unit_auto_activity.xml index dd43c9407..3d399ca1c 100755 --- a/APIJSON-Android/APIJSONTest/app/src/main/res/layout/unit_auto_activity.xml +++ b/APIJSON-Android/APIJSONTest/UnitAuto-Apk/src/main/res/layout/unit_auto_activity.xml @@ -4,15 +4,17 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".ui.UnitAutoActivity" + tools:context="unitauto.apk.UnitAutoActivity" > + android:text="@string/horizontal" />