未验证 提交 de819f3d 编写于 作者: H Hugin 提交者: GitHub

Merge pull request #10 from didi/master

pull request
package com.didichuxing.doraemonkit.adb;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.didichuxing.doraemonkit.adb.test", appContext.getPackageName());
}
}
<manifest package="com.didichuxing.doraemonkit.adb" />
package com.didichuxing.doraemonkit.adb;
import android.content.Context;
import android.util.Base64;
import android.util.Log;
import com.cgutman.adblib.AdbBase64;
import com.cgutman.adblib.AdbConnection;
import com.cgutman.adblib.AdbCrypto;
import com.cgutman.adblib.AdbStream;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
/**
* Created by yangmenglin on 2018/11/1.
*/
public class AdbConnector {
private static final String TAG = "AdbConnector";
private AdbConnection connection;
private AdbStream stream;
private AdbBase64 getBase64Impl() {
return new AdbBase64() {
@Override
public String encodeToString(byte[] data) {
return Base64.encodeToString(data, Base64.DEFAULT);
}
};
}
// This function loads a keypair from the specified files if one exists, and if not,
// it creates a new keypair and saves it in the specified files
private AdbCrypto setupCrypto(String pubKeyFile, String privKeyFile)
throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
File pub = new File(pubKeyFile);
File priv = new File(privKeyFile);
AdbCrypto c = null;
// Try to load a key pair from the files
if (pub.exists() && priv.exists()) {
try {
c = AdbCrypto.loadAdbKeyPair(getBase64Impl(), priv, pub);
} catch (Exception e) {
// Failed to read from file
c = null;
}
}
if (c == null) {
// We couldn't load a key, so let's generate a new one
c = AdbCrypto.generateAdbKeyPair(getBase64Impl());
// Save it
c.saveAdbKeyPair(priv, pub);
Log.d(TAG, "Generated new keypair");
} else {
Log.d(TAG, "Loaded existing keypair");
}
return c;
}
private AdbConnection connection(Context context) throws Exception {
// Setup the crypto object required for the AdbConnection
String path = context.getCacheDir().getAbsolutePath();
Log.d(TAG, "connection path " + path);
AdbCrypto crypto = setupCrypto(path + File.separatorChar + "pub.key",
path + File.separatorChar + "priv.key");
Log.e(TAG, "Socket connecting...");
Socket sock = new Socket(AdbConstant.HOST, AdbConstant.PORT);
// Connect the socket to the remote host
Log.e(TAG, "Socket connected");
// Construct the AdbConnection object
AdbConnection adb = AdbConnection.create(sock, crypto);
// Start the application layer connection process
Log.e(TAG, "ADB connecting...");
adb.connect();
Log.e(TAG, "ADB connected");
return adb;
}
public String openShell(Context context,String cmd) throws Exception {
if (connection == null) {
connection = connection(context);
}
stream = connection.open(cmd);
StringBuilder stringBuilder = new StringBuilder();
byte[] bytes = stream.read();
stringBuilder.append(new String(bytes));
while (bytes != null) {
stringBuilder.append(new String(bytes));
try {
bytes = stream.read();
} catch (Exception e) {
bytes = null;
Log.d("morning", e.getMessage());
}
}
Log.d("morning", "length is " + stringBuilder.length());
return stringBuilder.toString();
}
}
package com.didichuxing.doraemonkit.adb;
/**
* Created by yangmenglin on 2018/11/1.
*/
public class AdbConstant {
public static final String HOST = "127.0.0.1";
public static final int PORT = 5555;
}
package com.didichuxing.doraemonkit.adb;
import android.content.Context;
/**
* Created by yangmenglin on 2018/11/1.
*/
public class AdbManager {
static class Holder {
private static AdbManager INSTANCE = new AdbManager();
}
private AdbService adbService;
public static AdbManager getInstance() {
return Holder.INSTANCE;
}
public void init(Context context) {
if (adbService == null) {
adbService = new AdbService(context);
}
}
private AdbManager() {
}
public void performAdbRequest(String cmd,Callback callback){
adbService.performAdbRequest(cmd,callback);
}
}
package com.didichuxing.doraemonkit.adb;
import android.content.Context;
import android.text.TextUtils;
/**
* Created by yangmenglin on 2018/11/1.
*/
public class AdbService {
private ThreadPoolProxy mProxy;
private AdbConnector mAdbConnector;
private Context mContext;
public AdbService(Context context){
mProxy = ThreadPoolProxyFactory.getThreadPoolProxy();
mAdbConnector = new AdbConnector();
mContext = context;
}
public void performAdbRequest(final String cmd, final Callback callback) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
String response = mAdbConnector.openShell(mContext, cmd);
if (!TextUtils.isEmpty(response)) {
if (callback != null) {
callback.onSuccess(response);
}
} else {
if (callback != null) {
callback.onFail("");
}
}
} catch (Exception e) {
if (callback != null) {
callback.onFail(e.getMessage());
}
}
}
};
mProxy.execute(runnable);
}
}
package com.didichuxing.doraemonkit.adb;
/**
* Created by yangmenglin on 2018/11/1.
*/
public interface Callback {
void onSuccess(String adbResponse);
void onFail(String failString);
}
package com.didichuxing.doraemonkit.adb;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolProxy {
ThreadPoolExecutor mExecutor;
private int mCorePoolSize;
private int mMaximumPoolSize;
/**
* @param corePoolSize 核心池的大小
* @param maximumPoolSize 最大线程数
*/
public ThreadPoolProxy(int corePoolSize, int maximumPoolSize) {
mCorePoolSize = corePoolSize;
mMaximumPoolSize = maximumPoolSize;
}
/**
* 初始化ThreadPoolExecutor
* 双重检查加锁,只有在第一次实例化的时候才启用同步机制,提高了性能
*/
private void initThreadPoolExecutor() {
if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
synchronized (ThreadPoolProxy.class) {
if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
long keepAliveTime = 3000;
TimeUnit unit = TimeUnit.MILLISECONDS;
BlockingQueue workQueue = new LinkedBlockingDeque<>();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
mExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, handler);
}
}
}
}
/**
执行任务和提交任务的区别?
1.有无返回值
execute->没有返回值
submit-->有返回值
2.Future的具体作用?
1.有方法可以接收一个任务执行完成之后的结果,其实就是get方法,get方法是一个阻塞方法
2.get方法的签名抛出了异常===>可以处理任务执行过程中可能遇到的异常
*/
/**
* 执行任务
*/
public void execute(Runnable task) {
initThreadPoolExecutor();
mExecutor.execute(task);
}
/**
* 提交任务
*/
public Future submit(Runnable task) {
initThreadPoolExecutor();
return mExecutor.submit(task);
}
/**
* 移除任务
*/
public void remove(Runnable task) {
initThreadPoolExecutor();
mExecutor.remove(task);
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.adb;
public class ThreadPoolProxyFactory {
private static ThreadPoolProxy mThreadPoolProxy;
public static ThreadPoolProxy getThreadPoolProxy() {
if (mThreadPoolProxy == null) {
synchronized (ThreadPoolProxyFactory.class) {
if (mThreadPoolProxy == null) {
mThreadPoolProxy = new ThreadPoolProxy(5, 5);
}
}
}
return mThreadPoolProxy;
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.adb;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
apply plugin: 'com.novoda.bintray-release'
// 配置发布
publish {
def groupProjectID = 'com.didichuxing.doraemonkit'
def artifactProjectID = 'adb'
def publishVersionID = '1.0.0'
userOrg = 'doraemonkit'
repoName = 'DoraemonKit'
groupId = groupProjectID
artifactId = artifactProjectID
publishVersion = publishVersionID
desc = '{library description}'
website = '{github_url}'
}
\ No newline at end of file
......@@ -2,18 +2,27 @@ apply plugin: 'com.android.application'
apply from: 'doraemonkit.gradle'
android {
compileSdkVersion 26
compileSdkVersion 27
defaultConfig {
applicationId "com.didichuxing.doraemondemo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
storeFile file("keystore/test.keystore")
storePassword "test123456"
keyAlias "test"
keyPassword "test123456"
}
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
......@@ -21,13 +30,11 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:appcompat-v7:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation project(':doraemonkit')
// implementation 'com.didichuxing.doraemonkit:doraemonkit:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okio:okio:1.15.0'
}
......@@ -9,6 +9,7 @@ if (applyPlugin) {
// 这里引用正常库
dependencies {
implementation project(":doraemonkit")
implementation project(":doraemonkit-aop")
}
} else {
// 引用no-op的库
......
package com.didichuxing.doraemondemo;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.StrictMode;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoorManager;
/**
* Created by zhangweida on 2018/6/22.
......
apply plugin: 'groovy'
apply from: 'upload.gradle'
targetCompatibility = JavaVersion.VERSION_1_7
sourceCompatibility = JavaVersion.VERSION_1_7
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.android.tools.build:gradle:3.0.1'
compile 'org.aspectj:aspectjtools:1.8.6'
compile 'org.aspectj:aspectjrt:1.8.6'
}
\ No newline at end of file
package didichuxing.doraemon.plugin
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile
class DoraemonPlugin implements Plugin<Project> {
@Override void apply(Project project) {
def hasApp = project.plugins.withType(AppPlugin)
def hasLib = project.plugins.withType(LibraryPlugin)
if (!hasApp && !hasLib) {
throw new IllegalStateException("'android' or 'android-library' plugin required.")
}
final def log = project.logger
final def variants
if (hasApp) {
variants = project.android.applicationVariants
} else {
variants = project.android.libraryVariants
}
project.dependencies {
implementation 'org.aspectj:aspectjrt:1.8.6'
}
variants.all { variant ->
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = [
"-showWeaveInfo",
"-1.5",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
]
log.debug "ajc args: " + Arrays.toString(args)
MessageHandler handler = new MessageHandler(true)
new Main().run(args, handler)
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break
case IMessage.WARNING:
log.warn message.message, message.thrown
break
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
}
}
......@@ -4,16 +4,14 @@ apply from: 'upload.gradle'
android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 15
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
}
buildTypes {
......@@ -27,10 +25,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation files('libs/AdbLib.jar')
compileOnly project(":doraemonkit")
compileOnly 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
compileOnly 'com.squareup.okhttp3:okhttp:3.12.1'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.didichuxing.doraemonkit.aop"/>
package com.didichuxing.doraemonkit.kit.network.aspect;
package parking.didi.com.aop;
import com.didichuxing.doraemonkit.kit.network.NetworkManager;
import com.didichuxing.doraemonkit.kit.network.httpurlconnection.HttpUrlConnectionProxy;
......
package com.didichuxing.doraemonkit;
package parking.didi.com.aop;
import android.app.Application;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterManager;
import com.didichuxing.doraemonkit.util.LogHelper;
......
package com.didichuxing.doraemonkit.kit.network.aspect;
package parking.didi.com.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
......
package com.didichuxing.doraemonkit.kit.network.aspect;
package parking.didi.com.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
......
apply plugin: 'com.novoda.bintray-release'
// 配置发布
publish {
def groupProjectID = 'com.didichuxing.doraemonkit'
def artifactProjectID = 'doraemonkit-aop'
def publishVersionID = '1.0.0'
userOrg = 'doraemonkit'
repoName = 'DoraemonKit'
groupId = groupProjectID
artifactId = artifactProjectID
publishVersion = publishVersionID
desc = '{library description}'
website = '{github_url}'
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ apply plugin: 'com.novoda.bintray-release'
publish {
def groupProjectID = 'com.didichuxing.doraemonkit'
def artifactProjectID = 'doraemonkit-no-op'
def publishVersionID = '1.1.7'
def publishVersionID = '1.1.8'
userOrg = 'doraemonkit'
repoName = 'DoraemonKit'
......
......@@ -37,10 +37,11 @@ dependencies {
}
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
compileOnly 'com.squareup.okio:okio:1.15.0'
compileOnly 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
testImplementation 'junit:junit:4.12'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.google.zxing:core:3.3.0'
// Android P禁用hide api,这个库可以支持hide api的反射访问
implementation 'me.weishu:free_reflection:2.0.0'
}
......@@ -13,7 +13,7 @@ import com.didichuxing.doraemonkit.kit.IKit;
import com.didichuxing.doraemonkit.kit.alignruler.AlignRuler;
import com.didichuxing.doraemonkit.kit.blockmonitor.BlockMonitorKit;
import com.didichuxing.doraemonkit.kit.colorpick.ColorPicker;
import com.didichuxing.doraemonkit.kit.crash.Crash;
import com.didichuxing.doraemonkit.kit.crash.CrashCapture;
import com.didichuxing.doraemonkit.kit.custom.Custom;
import com.didichuxing.doraemonkit.kit.dataclean.DataClean;
import com.didichuxing.doraemonkit.kit.fileexplorer.FileExplorer;
......@@ -29,6 +29,7 @@ import com.didichuxing.doraemonkit.kit.parameter.ram.Ram;
import com.didichuxing.doraemonkit.kit.sysinfo.SysInfo;
import com.didichuxing.doraemonkit.kit.temporaryclose.TemporaryClose;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterKit;
import com.didichuxing.doraemonkit.kit.timecounter.instrumentation.HandlerHooker;
import com.didichuxing.doraemonkit.kit.viewcheck.ViewChecker;
import com.didichuxing.doraemonkit.kit.weaknetwork.WeakNetwork;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoor;
......@@ -89,6 +90,7 @@ public class DoraemonKit {
return;
}
sHasInit = true;
HandlerHooker.doHook(app);
ServiceHookManager.getInstance().install();
app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
int startedActivityCounts;
......@@ -160,7 +162,7 @@ public class DoraemonKit {
tool.add(new GpsMock());
}
tool.add(new WebDoor());
tool.add(new Crash());
tool.add(new CrashCapture());
tool.add(new LogInfo());
tool.add(new DataClean());
tool.add(new WeakNetwork());
......
package com.didichuxing.doraemonkit.config;
import android.content.Context;
import android.os.Environment;
import com.didichuxing.doraemonkit.constant.SharedPrefsKey;
import com.didichuxing.doraemonkit.util.SharedPrefsUtil;
public class CrashCaptureConfig {
public static boolean isCrashCaptureOpen(Context context) {
return SharedPrefsUtil.getBoolean(context, SharedPrefsKey.CRASH_OPEN, false);
return SharedPrefsUtil.getBoolean(context, SharedPrefsKey.CRASH_CAPTURE_OPEN, false);
}
public static void setCrashCaptureOpen(Context context, boolean open) {
SharedPrefsUtil.putBoolean(context, SharedPrefsKey.CRASH_OPEN, open);
SharedPrefsUtil.putBoolean(context, SharedPrefsKey.CRASH_CAPTURE_OPEN, open);
}
}
......@@ -8,7 +8,6 @@ public interface BundleKey {
String FILE_KEY = "file_key";
String FRAGMENT_INDEX = "fragment_index";
String ACCESSIBILITY_DATA = "accessibility_data";
String PERFORMANCE_TYPE = "PERFORMANCE_TYPE";
String PERFORMANCE_TYPE = "performance_type";
String KEY_URL = "key_url";
}
\ No newline at end of file
......@@ -6,4 +6,5 @@ package com.didichuxing.doraemonkit.constant;
public interface CachesKey {
String WEB_DOOR_HISTORY = "web_door_history";
String CRASH_HISTORY = "crash";
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ public interface SharedPrefsKey {
String FRAME_INFO_MEMORY_OPEN = "frame_info_memory_open";
String FRAME_INFO_TRAFFIC_OPEN = "frame_info_traffic_open";
String GPS_MOCK_OPEN = "gps_mock_open";
String CRASH_OPEN = "crash_open";
String CRASH_CAPTURE_OPEN = "crash_capture_open";
String FLOAT_ICON_POS_X = "float_icon_pos_x";
String FLOAT_ICON_POS_Y = "float_icon_pos_y";
String LOG_INFO_OPEN = "log_info_open";
......
......@@ -15,10 +15,10 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.Choreographer;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.config.PerformanceInfoConfig;
import com.didichuxing.doraemonkit.kit.custom.PerformanceInfo;
import com.didichuxing.doraemonkit.kit.custom.UploadMonitorInfoBean;
import com.didichuxing.doraemonkit.kit.custom.UploadMonitorItem;
import com.didichuxing.doraemonkit.kit.network.NetworkManager;
import com.didichuxing.doraemonkit.util.FileManager;
import com.didichuxing.doraemonkit.util.JsonUtil;
......@@ -54,6 +54,10 @@ public class PerformanceDataManager {
private int mLastSkippedFrames;
private float mLastCpuRate;
private float mLastMemoryInfo;
private long mUpBytes;
private long mDownBytes;
private long mLastUpBytes;
private long mLastDownBytes;
private Handler mHandler;
private HandlerThread mHandlerThread;
private float mMaxMemory;
......@@ -67,6 +71,7 @@ public class PerformanceDataManager {
private static final int MSG_CPU = 1;
private static final int MSG_MEMORY = 2;
private static final int MSG_SAVE_LOCAL = 3;
private static final int MSG_NET_FLOW = 4;
private UploadMonitorInfoBean mUploadMonitorBean;
private boolean mUploading;
private Handler mMainHandler = new Handler(Looper.getMainLooper());
......@@ -179,6 +184,10 @@ public class PerformanceDataManager {
} else if (msg.what == MSG_MEMORY) {
executeMemoryData();
mHandler.sendEmptyMessageDelayed(MSG_MEMORY, NORMAL_FRAME_RATE * 1000);
} else if (msg.what == MSG_NET_FLOW){
mLastUpBytes = NetworkManager.get().getTotalRequestSize() - mUpBytes;
mLastDownBytes = NetworkManager.get().getTotalResponseSize() - mDownBytes;
mHandler.sendEmptyMessageDelayed(MSG_NET_FLOW, NORMAL_FRAME_RATE * 1000);
} else if (msg.what == MSG_SAVE_LOCAL){
saveToLocal();
mHandler.sendEmptyMessageDelayed(MSG_SAVE_LOCAL, NORMAL_FRAME_RATE * 1000);
......@@ -213,6 +222,14 @@ public class PerformanceDataManager {
mHandler.sendEmptyMessageDelayed(MSG_CPU, NORMAL_FRAME_RATE * 1000);
}
public void startMonitorNetFlowInfo() {
mHandler.sendEmptyMessageDelayed(MSG_NET_FLOW, NORMAL_FRAME_RATE * 1000);
}
public void stopMonitorNetFlowInfo() {
mHandler.removeMessages(MSG_NET_FLOW);
}
public void startUploadMonitorData() {
mUploading = true;
if (mUploadMonitorBean != null) {
......@@ -229,6 +246,7 @@ public class PerformanceDataManager {
}
if (PerformanceInfoConfig.isTrafficOpen(mContext)) {
NetworkManager.get().startMonitor();
startMonitorNetFlowInfo();
}
mHandler.sendEmptyMessageDelayed(MSG_SAVE_LOCAL, NORMAL_FRAME_RATE * 1000);
}
......@@ -240,6 +258,7 @@ public class PerformanceDataManager {
stopMonitorFrameInfo();
stopMonitorCPUInfo();
stopMonitorMemoryInfo();
stopMonitorNetFlowInfo();
NetworkManager.get().stopMonitor();
}
......@@ -270,11 +289,25 @@ public class PerformanceDataManager {
mUploadMonitorBean.performanceArray = new ArrayList<>();
}
}
PerformanceInfo info = new PerformanceInfo();
NetworkManager networkManager = NetworkManager.get();
long upSize = networkManager.getTotalRequestSize();
long downSize = networkManager.getTotalResponseSize();
UploadMonitorItem info = new UploadMonitorItem();
info.cpu = mLastCpuRate;
info.fps = mLastFrameRate;
info.memory = mLastMemoryInfo;
info.upFlow = mLastUpBytes;
info.downFlow = mLastDownBytes;
mUpBytes = upSize;
mDownBytes = downSize;
info.timestamp = System.currentTimeMillis();
String pageName = "unkown";
if (DoraemonKit.getCurrentResumedActivity() != null) {
pageName = DoraemonKit.getCurrentResumedActivity().getLocalClassName();
}
info.page = pageName;
mUploadMonitorBean.performanceArray.add(info);
}
......@@ -478,4 +511,12 @@ public class PerformanceDataManager {
writeFpsDataIntoFile();
}
}
public long getLastUpBytes() {
return mLastUpBytes;
}
public long getLastDownBytes() {
return mLastDownBytes;
}
}
......@@ -11,7 +11,10 @@ import com.didichuxing.doraemonkit.kit.Category;
import com.didichuxing.doraemonkit.kit.IKit;
import com.didichuxing.doraemonkit.ui.UniversalActivity;
public class Crash implements IKit {
/**
* Created by wanglikun on 2019/6/12
*/
public class CrashCapture implements IKit {
@Override
public int getCategory() {
return Category.TOOLS;
......@@ -37,11 +40,11 @@ public class Crash implements IKit {
@Override
public void onAppInit(Context context) {
CrashCaptureManager.getInstance().init(context);
if (CrashCaptureConfig.isCrashCaptureOpen(context)) {
CrashHandlerManager.getInstance().init(context);
CrashCaptureManager.getInstance().start();
} else {
CrashCaptureManager.getInstance().stop();
}
}
}
}
\ No newline at end of file
......@@ -3,24 +3,19 @@ package com.didichuxing.doraemonkit.kit.crash;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.TextView;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.constant.BundleKey;
import com.didichuxing.doraemonkit.ui.base.BaseFragment;
import com.didichuxing.doraemonkit.ui.crash.CrashCaptureAdapter;
import com.didichuxing.doraemonkit.ui.crash.CrashHistoryAdapter;
import com.didichuxing.doraemonkit.ui.widget.titlebar.TitleBar;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CrashCaptureFragment extends BaseFragment {
public class CrashCaptureDetailFragment extends BaseFragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
......@@ -28,10 +23,9 @@ public class CrashCaptureFragment extends BaseFragment {
initView();
}
@Override
protected int onRequestLayout() {
return R.layout.dk_fragment_crash_capture;
return R.layout.dk_fragment_crash_capture_detail;
}
private void initView() {
......@@ -39,7 +33,7 @@ public class CrashCaptureFragment extends BaseFragment {
mTitleBar.setOnTitleBarClickListener(new TitleBar.OnTitleBarClickListener() {
@Override
public void onLeftClick() {
getActivity().onBackPressed();
finish();
}
@Override
......@@ -47,35 +41,19 @@ public class CrashCaptureFragment extends BaseFragment {
}
});
File file = new File(CrashHandlerManager.getInstance().getFilePath());
if (file.exists()) {
ListView crash = findViewById(R.id.lv_crash);
final List<File> listFiles = Arrays.asList(file.listFiles());
if (listFiles != null && listFiles.size() != 0) {
Collections.sort(listFiles, new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
return Long.valueOf(rhs.lastModified())
.compareTo(lhs.lastModified());
}
});
crash.setAdapter(new CrashCaptureAdapter(listFiles));
} else {
Toast.makeText(getContext(), R.string.dk_crash_capture_no_record, Toast.LENGTH_SHORT).show();
}
crash.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Bundle bundle = new Bundle();
File listFile = listFiles.get(position);
bundle.putSerializable(BundleKey.FILE_KEY, listFile);
showContent(CrashDetailFragment.class, bundle);
}
});
TextView noRecordHint = findViewById(R.id.no_record_hint);
RecyclerView crashList = findViewById(R.id.crash_list);
List<CrashInfo> caches = CrashCaptureManager.getInstance().getCrashCaches();
if (caches.isEmpty()) {
noRecordHint.setVisibility(View.VISIBLE);
crashList.setVisibility(View.GONE);
} else {
Toast.makeText(getContext(), R.string.dk_crash_capture_no_record, Toast.LENGTH_SHORT).show();
noRecordHint.setVisibility(View.GONE);
crashList.setVisibility(View.VISIBLE);
crashList.setLayoutManager(new LinearLayoutManager(getContext()));
CrashHistoryAdapter adapter = new CrashHistoryAdapter(getContext());
adapter.append(caches);
crashList.setAdapter(adapter);
}
}
}
......@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.format.Formatter;
import android.view.View;
import com.didichuxing.doraemonkit.R;
......@@ -13,6 +14,7 @@ import com.didichuxing.doraemonkit.ui.base.BaseFragment;
import com.didichuxing.doraemonkit.ui.setting.SettingItem;
import com.didichuxing.doraemonkit.ui.setting.SettingItemAdapter;
import com.didichuxing.doraemonkit.ui.widget.titlebar.HomeTitleBar;
import com.didichuxing.doraemonkit.util.FileUtil;
public class CrashCaptureMainFragment extends BaseFragment {
@Override
......@@ -31,27 +33,26 @@ public class CrashCaptureMainFragment extends BaseFragment {
titleBar.setListener(new HomeTitleBar.OnTitleBarClickListener() {
@Override
public void onRightClick() {
getActivity().finish();
finish();
}
});
RecyclerView mSettingList = findViewById(R.id.setting_list);
mSettingList.setLayoutManager(new LinearLayoutManager(getContext()));
RecyclerView settingList = findViewById(R.id.setting_list);
settingList.setLayoutManager(new LinearLayoutManager(getContext()));
SettingItemAdapter mSettingItemAdapter = new SettingItemAdapter(getContext());
mSettingItemAdapter.append(new SettingItem(R.string.dk_crash_capture_switch, CrashCaptureConfig.isCrashCaptureOpen(getContext())));
mSettingItemAdapter.append(new SettingItem(R.string.dk_crash_capture_look, R.drawable.dk_more_icon));
mSettingItemAdapter.append(new SettingItem(R.string.dk_crash_capture_clean_data));
SettingItem item = new SettingItem(R.string.dk_crash_capture_clean_data);
item.rightDesc = Formatter.formatFileSize(getContext(), FileUtil.getDirectorySize(CrashCaptureManager.getInstance().getCrashCacheDir()));
mSettingItemAdapter.append(item);
mSettingItemAdapter.setOnSettingItemSwitchListener(new SettingItemAdapter.OnSettingItemSwitchListener() {
@Override
public void onSettingItemSwitch(View view, SettingItem data, boolean on) {
if (data.desc == R.string.dk_crash_capture_switch) {
CrashCaptureConfig.setCrashCaptureOpen(getContext(), on);
if (on) {
CrashHandlerManager.getInstance().init(getContext());
CrashCaptureManager.getInstance().start();
} else {
CrashHandlerManager.getInstance().remove();
CrashCaptureManager.getInstance().stop();
}
}
}
......@@ -60,13 +61,13 @@ public class CrashCaptureMainFragment extends BaseFragment {
@Override
public void onSettingItemClick(View view, SettingItem data) {
if (data.desc == R.string.dk_crash_capture_look) {
showContent(CrashCaptureFragment.class);
showContent(CrashCaptureDetailFragment.class);
} else if (data.desc == R.string.dk_crash_capture_clean_data) {
CrashHandlerManager.getInstance().cleanHistoricalData();
CrashCaptureManager.getInstance().clearCacheHistory();
showToast(R.string.dk_crash_capture_clean_data);
}
}
});
mSettingList.setAdapter(mSettingItemAdapter);
settingList.setAdapter(mSettingItemAdapter);
}
}
package com.didichuxing.doraemonkit.kit.crash;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.Toast;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.constant.CachesKey;
import com.didichuxing.doraemonkit.util.CacheUtils;
import com.didichuxing.doraemonkit.util.FileUtil;
import com.didichuxing.doraemonkit.util.LogHelper;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by wanglikun on 2019-06-12
*/
public class CrashCaptureManager implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashCaptureManager";
private final Thread.UncaughtExceptionHandler mDefaultHandler;
private final Handler mHandler;
private Context mContext;
private CrashCaptureManager() {
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
}
private static class Holder {
private static final CrashCaptureManager INSTANCE = new CrashCaptureManager();
}
public static CrashCaptureManager getInstance() {
return Holder.INSTANCE;
}
public void init(Context context) {
mContext = context.getApplicationContext();
}
public void start() {
Thread.setDefaultUncaughtExceptionHandler(this);
}
public void stop() {
Thread.setDefaultUncaughtExceptionHandler(mDefaultHandler);
}
@Override
public void uncaughtException(final Thread t, final Throwable e) {
LogHelper.d(TAG, t.toString());
LogHelper.d(TAG, Log.getStackTraceString(e));
CacheUtils.saveObject(e, getCrashCacheFile());
post(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, mContext.getString(R.string.dk_crash_capture_tips), Toast.LENGTH_SHORT).show();
}
});
postDelay(new Runnable() {
@Override
public void run() {
if (mDefaultHandler != null) {
mDefaultHandler.uncaughtException(t, e);
}
}
}, 2000);
}
private void post(Runnable r) {
mHandler.post(r);
}
private void postDelay(Runnable r, long delayMillis) {
mHandler.postDelayed(r, delayMillis);
}
public File getCrashCacheDir() {
File dir = new File(mContext.getCacheDir() + File.separator + CachesKey.CRASH_HISTORY);
if (!dir.exists()) {
dir.mkdir();
}
return dir;
}
private File getCrashCacheFile() {
String fileName = new Date().toString();
return new File(getCrashCacheDir() + File.separator + fileName);
}
public void clearCacheHistory() {
FileUtil.deleteDirectory(getCrashCacheDir());
}
public List<CrashInfo> getCrashCaches() {
File[] caches = getCrashCacheDir().listFiles();
List<CrashInfo> result = new ArrayList<>();
if (caches == null) {
return result;
}
for (File cache : caches) {
Serializable serializable = CacheUtils.readObject(cache);
if (serializable instanceof Throwable) {
CrashInfo info = new CrashInfo((Throwable) serializable, cache.lastModified());
result.add(info);
}
}
return result;
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.crash;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.widget.Toast;
import com.didichuxing.doraemonkit.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class CrashHandlerManager implements Thread.UncaughtExceptionHandler {
private static final String TAG = CrashHandlerManager.class.getSimpleName();
private static class Holder {
private static CrashHandlerManager INSTANCE = new CrashHandlerManager();
}
private String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/doraemon/Crash/";
private Thread.UncaughtExceptionHandler mDefaultHandler;
private Map<String, String> infos = new HashMap<String, String>();
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final int CRASH = 10;
private Handler handler;
private Context mContext;
private Boolean isOpen = false;
public static CrashHandlerManager getInstance() {
return CrashHandlerManager.Holder.INSTANCE;
}
private CrashHandlerManager() {
}
public void init(Context context) {
if (!isOpen) {
isOpen = true;
mContext = context.getApplicationContext();
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
CrashHandlerThread crashHandlerThread = new CrashHandlerThread(TAG);
crashHandlerThread.start();
handler = new Handler(crashHandlerThread.getLooper(), crashHandlerThread);
}
}
public void remove() {
if (isOpen) {
isOpen = false;
Thread.setDefaultUncaughtExceptionHandler(mDefaultHandler);
mDefaultHandler = null;
}
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, R.string.dk_crash_capture_tips, Toast.LENGTH_LONG).show();
}
});
}
if (!handleException(ex) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
handler.sendEmptyMessage(CRASH);
collectDeviceInfo();
saveCrashInfo2File(ex);
return true;
}
private void collectDeviceInfo() {
try {
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null"
: pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (PackageManager.NameNotFoundException e) {
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
} catch (Exception e) {
}
}
}
public String getFilePath() {
return path;
}
private String saveCrashInfo2File(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n");
}
sb.append("\n");
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
sb.append(result);
try {
String fileName = formatter.format(new Date()) + ".txt";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
fos.close();
}
return fileName;
} catch (Exception e) {
}
return null;
}
public void cleanHistoricalData() {
try {
File file = new File(getFilePath());
if (file.exists()) {
RecursionDeleteFile(file);
}
} catch (Exception e) {
}
}
public void RecursionDeleteFile(File file) {
if (file.isFile()) {
file.delete();
return;
}
if (file.isDirectory()) {
File[] childFile = file.listFiles();
if (childFile == null || childFile.length == 0) {
file.delete();
return;
}
for (File f : childFile) {
RecursionDeleteFile(f);
}
file.delete();
}
}
private class CrashHandlerThread extends HandlerThread implements android.os.Handler.Callback {
public CrashHandlerThread(String name) {
super(name);
}
@Override
public boolean handleMessage(Message msg) {
if (msg.what == CRASH) {
Toast.makeText(mContext, R.string.dk_crash_capture_tips, Toast.LENGTH_LONG).show();
}
return true;
}
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.crash;
import java.io.Serializable;
/**
* Created by wanglikun on 2019-06-12
*/
public class CrashInfo implements Serializable {
public final Throwable tr;
public final long time;
public CrashInfo(Throwable tr, long l) {
this.tr = tr;
this.time = l;
}
}
\ No newline at end of file
......@@ -11,20 +11,22 @@ import android.view.View;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.kit.common.PerformanceDataManager;
import com.didichuxing.doraemonkit.ui.base.BaseFragment;
import com.didichuxing.doraemonkit.ui.fileexplorer.FileInfo;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.DividerItemDecoration;
import com.didichuxing.doraemonkit.ui.widget.titlebar.HomeTitleBar;
import com.didichuxing.doraemonkit.ui.widget.titlebar.TitleBar;
import com.didichuxing.doraemonkit.util.JsonUtil;
import com.google.gson.reflect.TypeToken;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class PageDataFragment extends BaseFragment {
private RecyclerView mRvList;
......@@ -99,53 +101,75 @@ public class PageDataFragment extends BaseFragment {
return dataItems;
}
Map<String,List<UploadMonitorItem>> listMap = new TreeMap<>();
for (UploadMonitorInfoBean infoBean : infoBeans) {
if(null == infoBean || null == infoBean.performanceArray || 0 >= infoBean.performanceArray.size()){
continue;
}
PageDataItem item = new PageDataItem();
List<PerformanceInfo> performanceInfos = infoBean.performanceArray;
item.pageName = infoBean.appName;
item.upNetWork =new PageDataItemChild<>(R.string.dk_frameinfo_upstream);
item.downNetWork = new PageDataItemChild<>(R.string.dk_frameinfo_downstream);
item.memory = new PageDataItemChild<>(R.string.dk_frameinfo_ram);
item.cpu = new PageDataItemChild<>(R.string.dk_frameinfo_cpu);
item.fps = new PageDataItemChild<>(R.string.dk_frameinfo_fps);
List<UploadMonitorItem> performanceInfos = infoBean.performanceArray;
for (UploadMonitorItem item : performanceInfos) {
List<UploadMonitorItem> itemList = listMap.get(item.page);
if(null == itemList){
itemList = new ArrayList<>();
listMap.put(item.page, itemList);
}
for (PerformanceInfo info : performanceInfos) {
setValue(item.memory,info.memory);
setValue(item.cpu,info.cpu);
setValue(item.fps,info.fps);
itemList.add(item);
}
}
item.memory.avg /= performanceInfos.size();
item.cpu.avg /= performanceInfos.size();
item.fps.avg /= performanceInfos.size();
dataItems.add(item);
for (String pageName : listMap.keySet()) {
dataItems.addAll(getPageItemData(pageName, listMap.get(pageName)));
}
return dataItems;
}
private void setValue(PageDataItemChild<Float> child, float newValue) {
child.min = Math.min(null == child.min ? 0:child.min, newValue);
child.max = Math.max(null == child.max ? 0:child.max, newValue);
child.avg = (null == child.avg ? 0:child.avg)+newValue;
}
private void setValue(PageDataItemChild<Integer> child, int newValue) {
child.min = Math.min(null == child.min ? 0:child.min, newValue);
child.max = Math.max(null == child.max ? 0:child.max, newValue);
child.avg = (null == child.avg ? 0:child.avg)+newValue;
private List<PageDataItem> getPageItemData(String appName, List<UploadMonitorItem> performanceInfos) {
List<PageDataItem> dataItems = new ArrayList<>();
PageDataItem item = new PageDataItem();
item.pageName = appName;
item.upNetWork =new PageDataItemChild(R.string.dk_frameinfo_upstream);
item.downNetWork = new PageDataItemChild(R.string.dk_frameinfo_downstream);
item.memory = new PageDataItemChild(R.string.dk_frameinfo_ram);
item.cpu = new PageDataItemChild(R.string.dk_frameinfo_cpu);
item.fps = new PageDataItemChild(R.string.dk_frameinfo_fps);
for (UploadMonitorItem monitorItem : performanceInfos) {
setValue(item.upNetWork,monitorItem.upFlow);
setValue(item.downNetWork,monitorItem.downFlow);
setValue(item.memory,monitorItem.memory);
setValue(item.cpu,monitorItem.cpu);
setValue(item.fps,monitorItem.fps);
}
int size = performanceInfos.size();
if(0 < size){
item.upNetWork.avg /= size;
item.downNetWork.avg /= size;
item.memory.avg /= size;
item.cpu.avg /= size;
item.fps.avg /= size;
}else{
item.upNetWork.avg = 0;
item.downNetWork.avg = 0;
item.memory.avg = 0;
item.cpu.avg = 0;
item.fps.avg = 0;
}
dataItems.add(item);
return dataItems;
}
private void setValue(PageDataItemChild<Double> child, double newValue) {
child.min = Math.min(null == child.min ? 0:child.min, newValue);
child.max = Math.max(null == child.max ? 0:child.max, newValue);
child.avg = (null == child.avg ? 0:child.avg)+newValue;
private void setValue(PageDataItemChild child, double newValue) {
child.min = 0 == child.min || 0 == newValue ? child.min+newValue : Math.min(child.min, newValue);
child.max = 0 == child.max || 0 == newValue ? child.max+newValue : Math.max(child.max, newValue);
child.avg += newValue;
}
private String getFileString(File file) {
......
......@@ -6,27 +6,27 @@ import android.view.View;
public class PageDataItem {
public String pageName;
public PageDataItemChild<Double> upNetWork;
public PageDataItemChild<Double> downNetWork;
public PageDataItemChild<Float> memory;
public PageDataItemChild<Float> cpu;
public PageDataItemChild<Integer> fps;
public PageDataItemChild upNetWork;
public PageDataItemChild downNetWork;
public PageDataItemChild memory;
public PageDataItemChild cpu;
public PageDataItemChild fps;
public PageDataItem() {
}
}
class PageDataItemChild<T extends Number> {
class PageDataItemChild {
@StringRes
public int nameResId;
public T min;
public T max;
public T avg;
public double min;
public double max;
public double avg;
public PageDataItemChild(int nameResId) {
this.nameResId = nameResId;
}
public int getVisibility(PageDataItemChild<? extends Number> child){
public int getVisibility(PageDataItemChild child){
return 0 < getValue(child.min)+ getValue(child.max) + getValue(child.avg)
? View.VISIBLE: View.GONE;
}
......@@ -43,23 +43,27 @@ class PageDataItemChild<T extends Number> {
this.nameResId = nameResId;
}
public void setMin(T min) {
public double getMin() {
return min;
}
public void setMin(double min) {
this.min = min;
}
public T getMax() {
public double getMax() {
return max;
}
public void setMax(T max) {
public void setMax(double max) {
this.max = max;
}
public T getAvg() {
public double getAvg() {
return avg;
}
public void setAvg(T avg) {
public void setAvg(double avg) {
this.avg = avg;
}
}
......@@ -10,6 +10,8 @@ import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsRecyclerAdapter;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsViewBinder;
import java.text.DecimalFormat;
public class PageDataItemAdapter extends AbsRecyclerAdapter<AbsViewBinder<PageDataItem>, PageDataItem> {
private Context mContext;
public PageDataItemAdapter(Context context) {
......@@ -63,7 +65,7 @@ public class PageDataItemAdapter extends AbsRecyclerAdapter<AbsViewBinder<PageDa
}
}
private void setValue(View iteView, PageDataItemChild<? extends Number> data) {
private void setValue(View iteView, PageDataItemChild data) {
int visibility = data.getVisibility(data);
iteView.setVisibility(visibility);
if(View.GONE == visibility){
......@@ -72,23 +74,28 @@ public class PageDataItemAdapter extends AbsRecyclerAdapter<AbsViewBinder<PageDa
String rule = getFormatRule(data.nameResId);
((TextView)iteView.findViewById(R.id.data_name_txt)).setText(data.nameResId);
((TextView)iteView.findViewById(R.id.high_data_txt)).setText(String.format(rule, data.max));
((TextView)iteView.findViewById(R.id.low_data_txt)).setText(String.format(rule, data.min));
((TextView)iteView.findViewById(R.id.avg_data_txt)).setText(String.format("%s - "+rule, mContext.getString(R.string.dk_frameinfo_avg_value), data.avg));
((TextView)iteView.findViewById(R.id.high_data_txt)).setText(String.format(rule, getFormatText(data.nameResId, data.max)));
((TextView)iteView.findViewById(R.id.low_data_txt)).setText(String.format(rule, getFormatText(data.nameResId, data.min)));
((TextView)iteView.findViewById(R.id.avg_data_txt)).setText(String.format("%s - "+rule, mContext.getString(R.string.dk_frameinfo_avg_value),getFormatText(data.nameResId, data.avg)));
}
private String getFormatText(int nameResId, double value){
if (nameResId == R.string.dk_frameinfo_downstream || nameResId == R.string.dk_frameinfo_upstream) {
return RealTimePerformDataFloatPage.getFlowTxt((long) value);
}
DecimalFormat df=new DecimalFormat(".#");
return df.format(value);
}
private String getFormatRule(int nameResId){
String formatRule = "";
if (nameResId == R.string.dk_frameinfo_ram) {
formatRule = "%.1fM";
formatRule = "%sM";
} else if (nameResId == R.string.dk_frameinfo_cpu) {
formatRule = "%.1f%%";
formatRule = "%s%%";
} else if (nameResId == R.string.dk_frameinfo_fps) {
formatRule = "%s";
} else if (nameResId == R.string.dk_frameinfo_downstream) {
formatRule = "%.1fB";
} else if (nameResId == R.string.dk_frameinfo_upstream) {
formatRule = "%.1fB";
} else if (nameResId == R.string.dk_frameinfo_downstream || nameResId == R.string.dk_frameinfo_upstream) {
formatRule = "%s";
}
return formatRule;
......
......@@ -15,15 +15,11 @@ import android.widget.TextView;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.config.PerformanceInfoConfig;
import com.didichuxing.doraemonkit.kit.common.PerformanceDataManager;
import com.didichuxing.doraemonkit.kit.network.NetworkManager;
import com.didichuxing.doraemonkit.kit.network.bean.NetworkRecord;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterManager;
import com.didichuxing.doraemonkit.ui.base.BaseFloatPage;
import com.didichuxing.doraemonkit.ui.base.TouchProxy;
import com.didichuxing.doraemonkit.util.UIUtils;
import java.util.List;
/**
*
*/
......@@ -119,17 +115,27 @@ public class RealTimePerformDataFloatPage extends BaseFloatPage implements Touch
mDownNetworkTxt.setVisibility(View.VISIBLE);
mUpNetworkTxt.setVisibility(View.VISIBLE);
List<NetworkRecord> records = NetworkManager.get().getRecords();
long requestLength = null != records && 0 < records.size() ? records.get(records.size() - 1).requestLength : 0;
long responseLength = null != records && 0 < records.size() ? records.get(records.size() - 1).responseLength : 0;
mDownNetworkTxt.setText(String.format("%s: %sB", getString(R.string.dk_frameinfo_downstream), requestLength));
mUpNetworkTxt.setText(String.format("%s: %sB", getString(R.string.dk_frameinfo_upstream), responseLength));
mDownNetworkTxt.setText(String.format("%s%s", getString(R.string.dk_frameinfo_downstream), getFlowTxt(manager.getLastDownBytes())));
mUpNetworkTxt.setText(String.format("%s%s", getString(R.string.dk_frameinfo_upstream), getFlowTxt(manager.getLastUpBytes())));
}else{
mDownNetworkTxt.setVisibility(View.INVISIBLE);
mUpNetworkTxt.setVisibility(View.INVISIBLE);
}
}
public static String getFlowTxt(long flowBytes) {
String upFlowTxt = flowBytes+"B";
if(1073741824 < flowBytes) {
upFlowTxt = flowBytes/1073741824 +"GB";
}else if(1048576 < flowBytes) {
upFlowTxt = flowBytes/1048576 +"MB";
}else if(1024 < flowBytes) {
upFlowTxt = flowBytes/1024 +"KB";
}
return upFlowTxt;
}
@Override
public void onMove(int x, int y, int dx, int dy) {
getLayoutParams().x += dx;
......
......@@ -5,6 +5,6 @@ import java.util.List;
public class UploadMonitorInfoBean {
public long timestamp;
public String appName;
public List<PerformanceInfo> performanceArray;
public List<UploadMonitorItem> performanceArray;
}
package com.didichuxing.doraemonkit.kit.custom;
public class UploadMonitorItem {
public String page = "unkown";
public long timestamp;
public int fps;
public float memory;
public float cpu;
public long upFlow;
public long downFlow;
}
......@@ -50,14 +50,13 @@ public class SpAdapter extends AbsRecyclerAdapter<AbsViewBinder<SpBean>, SpBean>
if (spBean.value.getClass().getSimpleName() != SpInputType.HASHSET) {
key.setText(spBean.key);
type.setText(spBean.value.getClass().getSimpleName());
inputView.setInput(spBean.value, new SpInputView.OnDataChangeListener() {
inputView.setInput(spBean, new SpInputView.OnDataChangeListener() {
@Override
public void onDataChanged(Object o) {
spBean.value = o;
public void onDataChanged() {
inputView.refresh();
if (onSpDataChangerListener != null) {
onSpDataChangerListener.onDataChanged(spBean.key, spBean.value);
onSpDataChangerListener.onDataChanged(spBean);
}
}
});
}
......@@ -70,8 +69,8 @@ public class SpAdapter extends AbsRecyclerAdapter<AbsViewBinder<SpBean>, SpBean>
this.onSpDataChangerListener = onSpDataChangerListener;
}
public interface OnSpDataChangerListener<T> {
void onDataChanged(String key, T t);
public interface OnSpDataChangerListener {
void onDataChanged(SpBean spBean);
}
}
package com.didichuxing.doraemonkit.kit.fileexplorer;
class SpBean<T> {
import com.didichuxing.doraemonkit.constant.SpInputType;
public class SpBean {
public String key;
public T value;
public Object value;
public Class clazz;
private SpBean() {
}
public SpBean(String key, Object value) {
this.key = key;
this.value = value;
clazz = value.getClass();
}
public Object toDefaultClass(String string) {
setDefaultClass(string);
return value;
}
private void setDefaultClass(String string) {
switch (clazz.getSimpleName()) {
case SpInputType.FLOAT:
value = Float.valueOf(string);
break;
case SpInputType.INTEGER:
value = Integer.valueOf(string);
break;
case SpInputType.STRING:
value = String.valueOf(string);
break;
case SpInputType.LONG:
value = Long.valueOf(string);
break;
}
}
}
package com.didichuxing.doraemonkit.kit.fileexplorer;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
......@@ -15,77 +14,73 @@ import com.didichuxing.doraemonkit.constant.BundleKey;
import com.didichuxing.doraemonkit.constant.SpInputType;
import com.didichuxing.doraemonkit.ui.base.BaseFragment;
import com.didichuxing.doraemonkit.ui.widget.titlebar.TitleBar;
import com.didichuxing.doraemonkit.util.SharedPrefsUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import static com.didichuxing.doraemonkit.util.FileUtil.XML;
public class SpFragment extends BaseFragment {
private ArrayList<SpBean> spBeans;
private SharedPreferences.Editor edit;
private String spNameFileName;
private String spTableName;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_submit) {
boolean commit = edit.commit();
if (commit) {
finish();
showToast(R.string.dk_success);
} else {
showToast(R.string.dk_fail);
}
} else if (id == R.id.btn_cancel) {
finish();
}
}
};
@Override
protected int onRequestLayout() {
return R.layout.dk_fragment_sp_show;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle data = getArguments();
if (data != null) {
File mFile = (File) data.getSerializable(BundleKey.FILE_KEY);
spNameFileName = mFile.getName().replace(XML, "");
SharedPreferences sharedPreferences = getActivity().getSharedPreferences(spNameFileName, Context.MODE_PRIVATE);
edit = sharedPreferences.edit();
Map<String, ?> all = sharedPreferences.getAll();
spBeans = new ArrayList<>(all.size());
SpBean spBean;
for (Map.Entry<String, ?> entry : all.entrySet()) {
Object value = entry.getValue();
spBean = new SpBean();
spBean.key = entry.getKey();
spBean.value = value;
spBeans.add(spBean);
}
private List<SpBean> getSpBeans() {
ArrayList<SpBean> spBeans = new ArrayList<>();
File mFile = (File) getArguments().getSerializable(BundleKey.FILE_KEY);
if (mFile == null) {
return spBeans;
}
spTableName = mFile.getName().replace(XML, "");
SharedPreferences sp = SharedPrefsUtil.getSharedPrefs(getActivity(), spTableName);
edit = sp.edit();
Map<String, ?> all = sp.getAll();
if (all.isEmpty()) {
return spBeans;
}
for (Map.Entry<String, ?> entry : all.entrySet()) {
spBeans.add(new SpBean(entry.getKey(), entry.getValue()));
}
return spBeans;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (spBeans != null && spBeans.size() > 0) {
List<SpBean> spBeans = getSpBeans();
if (spBeans.isEmpty()) {
finish();
return;
}
RecyclerView recyclerView = findViewById(R.id.rv_sp);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
SpAdapter spAdapter = new SpAdapter(getActivity());
spAdapter.setOnSpDataChangerListener(new SpAdapter.OnSpDataChangerListener() {
@Override
public void onDataChanged(SpBean bean) {
spUpData(bean);
}
});
spAdapter.append(spBeans);
recyclerView.setAdapter(spAdapter);
if (spTableName != null) {
TitleBar mTitleBar = findViewById(R.id.title_bar);
mTitleBar.setTitle(spNameFileName);
mTitleBar.setTitle(spTableName);
mTitleBar.setOnTitleBarClickListener(new TitleBar.OnTitleBarClickListener() {
@Override
public void onLeftClick() {
onBackPressed();
finish();
}
@Override
......@@ -93,47 +88,31 @@ public class SpFragment extends BaseFragment {
}
});
RecyclerView recyclerView = findViewById(R.id.rv_sp);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
SpAdapter spAdapter = new SpAdapter(getActivity());
spAdapter.append(spBeans);
spAdapter.setOnSpDataChangerListener(new SpAdapter.OnSpDataChangerListener() {
@Override
public void onDataChanged(String key, Object o) {
spUpData(key, o);
}
});
recyclerView.setAdapter(spAdapter);
findViewById(R.id.btn_submit).setOnClickListener(mOnClickListener);
findViewById(R.id.btn_cancel).setOnClickListener(mOnClickListener);
} else {
finish();
}
}
public void spUpData(String key, Object o) {
String simpleName = o.getClass().getSimpleName();
if (simpleName.equals(SpInputType.STRING)) {
edit.putString(key, o.toString());
}
if (simpleName.equals(SpInputType.BOOLEAN)) {
edit.putBoolean(key, (Boolean) o);
}
if (simpleName.equals(SpInputType.HASHSET)) {
edit.putStringSet(key, (HashSet) o);
}
if (simpleName.equals(SpInputType.INTEGER)) {
edit.putInt(key, (Integer) o);
}
if (simpleName.equals(SpInputType.FLOAT)) {
edit.putFloat(key, (Float) o);
}
if (simpleName.equals(SpInputType.LONG)) {
edit.putLong(key, (Long) o);
public void spUpData(SpBean bean) {
String key = bean.key;
switch (bean.value.getClass().getSimpleName()) {
case SpInputType.STRING:
SharedPrefsUtil.putString(getActivity(), key, bean.value.toString());
break;
case SpInputType.BOOLEAN:
SharedPrefsUtil.putBoolean(getActivity(), spTableName, key, (Boolean) bean.value);
break;
case SpInputType.INTEGER:
SharedPrefsUtil.putInt(getActivity(), spTableName, key, (Integer) bean.value);
break;
case SpInputType.FLOAT:
SharedPrefsUtil.putFloat(getActivity(), spTableName, key, (Float) bean.value);
break;
case SpInputType.LONG:
SharedPrefsUtil.putLong(getActivity(), spTableName, key, (Long) bean.value);
break;
}
}
}
}
......@@ -2,36 +2,35 @@ package com.didichuxing.doraemonkit.kit.fileexplorer;
import android.content.Context;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.constant.SpInputType;
import java.util.ArrayList;
import java.util.List;
import com.didichuxing.doraemonkit.ui.widget.bottomview.BottomUpWindow;
import com.didichuxing.doraemonkit.ui.widget.bottomview.EditSpInputView;
public class SpInputView extends FrameLayout {
private Spinner spinner;
private EditText sp_input;
private static final List<Boolean> selected = new ArrayList<Boolean>() {{
add(true);
add(false);
}};
private OnDataChangeListener onDataChangeListener;
private static final int FLOAT = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
private static final int INTEGER = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED;
private static final int STRING = InputType.TYPE_CLASS_TEXT;
private TextView spValue;
private Switch switchBtn;
private SpBean bean;
public SpInputView(Context context) {
super(context);
init();
super(context, null);
}
public SpInputView(Context context, @Nullable AttributeSet attrs) {
......@@ -48,43 +47,36 @@ public class SpInputView extends FrameLayout {
private void init() {
View inflate = LayoutInflater.from(getContext()).inflate(R.layout.kd_item_sp_input, this, true);
spinner = inflate.findViewById(R.id.spinner);
spinner.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, selected));
sp_input = inflate.findViewById(R.id.sp_input);
switchBtn = inflate.findViewById(R.id.switch_btn);
spValue = inflate.findViewById(R.id.tv_sp_value);
}
private String currentStatue = "";
public <T> void setInput(final T t, final OnDataChangeListener onDataChangeListener) {
currentStatue = t.getClass().getSimpleName();
switch (currentStatue) {
public void setInput(final SpBean bean, final OnDataChangeListener onDataChangeListener) {
this.bean = bean;
this.onDataChangeListener = onDataChangeListener;
switch (bean.value.getClass().getSimpleName()) {
case SpInputType.BOOLEAN:
spinner.setSelection(selected.indexOf(t));
spinner.setVisibility(VISIBLE);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
switchBtn.setChecked((Boolean) bean.value);
switchBtn.setVisibility(VISIBLE);
switchBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
onDataChangeListener.onDataChanged(parent.getSelectedItem());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
bean.value = isChecked;
onDataChangeListener.onDataChanged();
}
});
sp_input.setVisibility(GONE);
spValue.setVisibility(GONE);
break;
case SpInputType.INTEGER:
case SpInputType.LONG:
initEdt(bean, INTEGER);
break;
case SpInputType.FLOAT:
sp_input.setInputType(InputType.TYPE_CLASS_NUMBER);
initEdt(t, onDataChangeListener);
initEdt(bean, FLOAT);
break;
case SpInputType.STRING:
sp_input.setInputType(InputType.TYPE_CLASS_TEXT);
initEdt(t, onDataChangeListener);
initEdt(bean, STRING);
break;
default:
break;
......@@ -94,32 +86,44 @@ public class SpInputView extends FrameLayout {
}
}
private <T> void initEdt(T t, final OnDataChangeListener onDataChangeListener) {
sp_input.setText(t.toString());
sp_input.setVisibility(VISIBLE);
spinner.setVisibility(GONE);
sp_input.addTextChangedListener(new TextWatcher() {
private void initEdt(final SpBean spBean, final int inputType) {
spValue.setVisibility(VISIBLE);
switchBtn.setVisibility(GONE);
spValue.setText(spBean.value.toString());
spValue.setOnClickListener(new OnClickListener() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void onClick(View v) {
showInputView(v, spBean, inputType);
}
});
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void refresh() {
if (bean != null) {
spValue.setText(bean.value.toString());
}
}
private void showInputView(View view, final SpBean spBean, int inputType) {
new BottomUpWindow(getContext()).setContent(new EditSpInputView(getContext(), spBean, inputType))
.show(view).setOnSubmitListener(new BottomUpWindow.OnSubmitListener() {
@Override
public void submit(Object object) {
spBean.value = object;
if (onDataChangeListener != null) {
onDataChangeListener.onDataChanged();
}
}
@Override
public void afterTextChanged(Editable s) {
onDataChangeListener.onDataChanged(s.toString());
public void cancel() {
}
});
}
public interface OnDataChangeListener<T> {
void onDataChanged(T t);
public interface OnDataChangeListener {
void onDataChanged();
}
}
......
package com.didichuxing.doraemonkit.kit.network.bean;
public class NetflowInfo {
public long flow;
public long timestamp;
public String page;
public boolean isUp;
}
package com.didichuxing.doraemonkit.kit.parameter.frameInfo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.config.PerformanceInfoConfig;
import com.didichuxing.doraemonkit.constant.BundleKey;
import com.didichuxing.doraemonkit.kit.parameter.AbsParameterFragment;
import com.didichuxing.doraemonkit.kit.common.PerformanceDataManager;
import com.didichuxing.doraemonkit.kit.common.PerformanceFragment;
import com.didichuxing.doraemonkit.kit.parameter.AbsParameterFragment;
import com.didichuxing.doraemonkit.ui.realtime.datasource.DataSourceFactory;
import com.didichuxing.doraemonkit.ui.setting.SettingItem;
import com.didichuxing.doraemonkit.ui.setting.SettingItemAdapter;
import java.util.Collection;
import java.util.List;
......@@ -22,6 +21,12 @@ import java.util.List;
public class FrameInfoFragment extends AbsParameterFragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
PerformanceDataManager.getInstance().init(getContext().getApplicationContext());
}
@Override
protected int getTitle() {
return R.string.dk_kit_frame_info_desc;
......@@ -75,4 +80,4 @@ public class FrameInfoFragment extends AbsParameterFragment {
closeChartPage();
}
}
\ No newline at end of file
}
package com.didichuxing.doraemonkit.kit.timecounter;
import android.text.TextUtils;
import android.util.Printer;
import com.didichuxing.doraemonkit.util.LogHelper;
/**
* @author: linjizong
* @date: 2019/2/19
* @desc:
*/
public class PrinterParser implements Printer {
private static final String DISPATCHING_TAG = ">>>>> Dispatching";
private static final String FINISHED_TAG = "<<<<< Finished";
private static final String HANDLER_NAME = "android.app.ActivityThread$H";
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING = 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int CANCEL_VISIBLE_BEHIND = 147;
public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
public static final int ATTACH_AGENT = 155;
public static final int APPLICATION_INFO_CHANGED = 156;
public static final int ACTIVITY_MOVED_TO_DISPLAY = 157;
private int sCurrentMsg;
public void parse(String log) {
if (TextUtils.isEmpty(log)) {
return;
}
if (!log.contains(HANDLER_NAME)) {
return;
}
if (log.startsWith(DISPATCHING_TAG)) {
if (log.endsWith(String.valueOf(PAUSE_ACTIVITY))) {
LogHelper.d("PinterParser", "pause");
TimeCounterManager.get().onActivityStart();
sCurrentMsg = PAUSE_ACTIVITY;
} else if (log.endsWith(String.valueOf(LAUNCH_ACTIVITY))) {
LogHelper.d("PinterParser", "launch");
TimeCounterManager.get().onActivityLaunch();
sCurrentMsg = LAUNCH_ACTIVITY;
}
} else if (log.startsWith(FINISHED_TAG)) {
if (sCurrentMsg == PAUSE_ACTIVITY) {
LogHelper.d("PinterParser", "pause end");
TimeCounterManager.get().onActivityPaused();
} else if (sCurrentMsg == LAUNCH_ACTIVITY) {
LogHelper.d("PinterParser", "launch end");
TimeCounterManager.get().onActivityCreated();
}
sCurrentMsg = 0;
}
}
@Override
public void println(String x) {
parse(x);
}
}
......@@ -3,7 +3,6 @@ package com.didichuxing.doraemonkit.kit.timecounter;
import android.os.Looper;
import com.didichuxing.doraemonkit.constant.PageTag;
import com.didichuxing.doraemonkit.kit.blockmonitor.core.BlockMonitorManager;
import com.didichuxing.doraemonkit.kit.timecounter.bean.CounterInfo;
import com.didichuxing.doraemonkit.kit.timecounter.counter.ActivityCounter;
import com.didichuxing.doraemonkit.kit.timecounter.counter.AppCounter;
......@@ -22,8 +21,6 @@ public class TimeCounterManager {
private static TimeCounterManager INSTANCE = new TimeCounterManager();
}
private PrinterParser mParser = new PrinterParser();
public static TimeCounterManager get() {
return TimeCounterManager.Holder.INSTANCE;
}
......@@ -39,12 +36,8 @@ public class TimeCounterManager {
mAppCounter.end();
}
public long getAppInitTime() {
return mAppCounter.getTime();
}
public void onActivityStart() {
mActivityCounter.start();
public void onActivityPause() {
mActivityCounter.pause();
}
public void onActivityPaused() {
......@@ -55,7 +48,7 @@ public class TimeCounterManager {
mActivityCounter.launch();
}
public void onActivityCreated() {
public void onActivityLaunched() {
mActivityCounter.launchEnd();
}
......@@ -68,9 +61,6 @@ public class TimeCounterManager {
return;
}
mIsRunning = true;
// 卡顿检测和跳转耗时统计都使用了Printer的方式,无法同时工作
BlockMonitorManager.getInstance().stop();
Looper.getMainLooper().setMessageLogging(mParser);
PageIntent pageIntent = new PageIntent(TimeCounterFloatPage.class);
pageIntent.tag = PageTag.PAGE_TIME_COUNTER;
pageIntent.mode = PageIntent.MODE_SINGLE_INSTANCE;
......@@ -93,7 +83,8 @@ public class TimeCounterManager {
public List<CounterInfo> getHistory() {
return mActivityCounter.getHistory();
}
public CounterInfo getAppSetupInfo(){
return mAppCounter.getAppSetupInfo();
public CounterInfo getAppSetupInfo() {
return mAppCounter.getAppSetupInfo();
}
}
......@@ -34,7 +34,7 @@ public class ActivityCounter {
private String mCurrentActivity;
private List<CounterInfo> mCounterInfos = new ArrayList<>();
public void start() {
public void pause() {
mStartTime = System.currentTimeMillis();
mPauseCostTime = 0;
mRenderCostTime = 0;
......@@ -77,13 +77,18 @@ public class ActivityCounter {
public void render() {
mRenderStartTime = System.currentTimeMillis();
Activity activity = DoraemonKit.getCurrentResumedActivity();
final Activity activity = DoraemonKit.getCurrentResumedActivity();
if (activity != null && activity.getWindow() != null) {
mCurrentActivity = activity.getClass().getSimpleName();
activity.getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
renderEnd();
activity.getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
renderEnd();
}
});
}
});
} else {
......
......@@ -8,7 +8,6 @@ import com.didichuxing.doraemonkit.kit.timecounter.bean.CounterInfo;
public class AppCounter {
private long mStartTime;
private long mCost;
private CounterInfo mCounterInfo = new CounterInfo();
public void start() {
......@@ -16,17 +15,12 @@ public class AppCounter {
}
public void end() {
mCost = System.currentTimeMillis() - mStartTime;
mCounterInfo.title = "App Setup Cost";
mCounterInfo.totalCost = mCost;
mCounterInfo.totalCost = System.currentTimeMillis() - mStartTime;;
mCounterInfo.type = CounterInfo.TYPE_APP;
mCounterInfo.time = System.currentTimeMillis();
}
public long getTime() {
return mCost;
}
public CounterInfo getAppSetupInfo() {
return mCounterInfo;
}
......
package com.didichuxing.doraemonkit.kit.timecounter.instrumentation;
import android.app.Application;
import android.os.Handler;
import com.didichuxing.doraemonkit.util.LogHelper;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import me.weishu.reflection.Reflection;
import static com.didichuxing.doraemonkit.BuildConfig.DEBUG;
public class HandlerHooker {
private static final String TAG = "HandlerHooker";
//是否已经hook成功
private static boolean isHookSucceed = false;
public static void doHook(Application app) {
try {
if (isHookSucceed()) {
return;
}
Reflection.unseal(app);
hookInstrumentation();
isHookSucceed = true;
} catch (Exception e) {
if (DEBUG) {
LogHelper.e(TAG, e.toString());
}
}
}
static boolean isHookSucceed() {
return isHookSucceed;
}
private static void hookInstrumentation() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
Class<?> c = Class.forName("android.app.ActivityThread");
Method currentActivityThread = c.getDeclaredMethod("currentActivityThread");
boolean acc = currentActivityThread.isAccessible();
if (!acc) {
currentActivityThread.setAccessible(true);
}
Object o = currentActivityThread.invoke(null);
if (!acc) {
currentActivityThread.setAccessible(acc);
}
Field f = c.getDeclaredField("mH");
acc = f.isAccessible();
if (!acc) {
f.setAccessible(true);
}
Handler handler = (Handler) f.get(o);
if (!acc) {
f.setAccessible(acc);
}
f = Handler.class.getDeclaredField("mCallback");
acc = f.isAccessible();
if (!acc) {
f.setAccessible(true);
}
Handler.Callback oldCallback = (Handler.Callback) f.get(handler);
ProxyHandlerCallback proxyMHCallback = new ProxyHandlerCallback(oldCallback,handler);
f.set(handler, proxyMHCallback);
if (!acc) {
f.setAccessible(acc);
}
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.timecounter.instrumentation;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterManager;
import com.didichuxing.doraemonkit.util.Reflector;
/**
* @author: linjizong
* @date: 2019/6/3
* @desc:
*/
class ProxyHandlerCallback implements Handler.Callback {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int EXECUTE_TRANSACTION = 159;
public static final String LAUNCH_ITEM_CLASS = "android.app.servertransaction.ResumeActivityItem";
public static final String PAUSE_ITEM_CLASS = "android.app.servertransaction.PauseActivityItem";
public final Handler.Callback mOldCallback;
public final Handler mHandler;
ProxyHandlerCallback(Handler.Callback oldCallback, Handler handler) {
mOldCallback = oldCallback;
mHandler = handler;
}
@Override
public boolean handleMessage(Message msg) {
int msgType = preDispatch(msg);
if (mOldCallback != null && mOldCallback.handleMessage(msg)) {
postDispatch(msgType);
return true;
}
mHandler.handleMessage(msg);
postDispatch(msgType);
return true;
}
private int preDispatch(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY:
TimeCounterManager.get().onActivityLaunch();
break;
case PAUSE_ACTIVITY:
TimeCounterManager.get().onActivityPause();
break;
case EXECUTE_TRANSACTION:
return handlerActivity(msg);
}
return msg.what;
}
private int handlerActivity(Message msg) {
Object obj = msg.obj;
Object activityCallback = Reflector.QuietReflector.with(obj).method("getLifecycleStateRequest").call();
if (activityCallback != null) {
String transactionName = activityCallback.getClass().getCanonicalName();
if (TextUtils.equals(transactionName, LAUNCH_ITEM_CLASS)) {
TimeCounterManager.get().onActivityLaunch();
return LAUNCH_ACTIVITY;
} else if (TextUtils.equals(transactionName, PAUSE_ITEM_CLASS)) {
TimeCounterManager.get().onActivityPause();
return PAUSE_ACTIVITY;
}
}
return msg.what;
}
private void postDispatch(int msgType) {
switch (msgType) {
case LAUNCH_ACTIVITY:
TimeCounterManager.get().onActivityLaunched();
break;
case PAUSE_ACTIVITY:
TimeCounterManager.get().onActivityPaused();
break;
}
}
}
......@@ -37,7 +37,11 @@ public class FloatIconPage extends BaseFloatPage implements TouchProxy.OnTouchEv
getRootView().setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return mTouchProxy.onTouchEvent(v, event);
if (getRootView() != null) {
return mTouchProxy.onTouchEvent(v, event);
} else {
return false;
}
}
});
}
......
package com.didichuxing.doraemonkit.ui.crash;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.kit.crash.CrashInfo;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsRecyclerAdapter;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsViewBinder;
import com.didichuxing.doraemonkit.util.FormatUtil;
/**
* Created by wanglikun on 2019-06-12
*/
public class CrashHistoryAdapter extends AbsRecyclerAdapter<AbsViewBinder<CrashInfo>, CrashInfo> {
public CrashHistoryAdapter(Context context) {
super(context);
}
@Override
protected AbsViewBinder<CrashInfo> createViewHolder(View view, int viewType) {
return new CrashHistoryViewHolder(view);
}
@Override
protected View createView(LayoutInflater inflater, ViewGroup parent, int viewType) {
return inflater.inflate(R.layout.dk_item_crash_history, parent, false);
}
public static class CrashHistoryViewHolder extends AbsViewBinder<CrashInfo> {
private TextView mContent;
private TextView mTime;
public CrashHistoryViewHolder(View view) {
super(view);
}
@Override
protected void getViews() {
mContent = getView(R.id.content);
mTime = getView(R.id.time);
}
@Override
public void bind(CrashInfo info) {
mContent.setText(Log.getStackTraceString(info.tr));
mTime.setText(FormatUtil.format(info.time));
}
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.ui.widget.bottomview;
import android.view.View;
/**
* 可提交的view
*
* @author vinda
* @since 15/5/21
*/
public abstract class AssociationView {
private OnStateChangeListener onStateChangeListener;
/**
* 提交
*/
public abstract Object submit();
/**
* 取消
*/
public abstract void cancel();
/**
* 获取视图
*
* @return
*/
public abstract View getView();
/**
* 能否提交
*
* @return
*/
public abstract boolean isCanSubmit();
public abstract void onShow();
public abstract void onHide();
final void setOnStateChangeListener(OnStateChangeListener listener) {
onStateChangeListener = listener;
}
final OnStateChangeListener getOnStateChangeListener() {
return onStateChangeListener;
}
interface OnStateChangeListener {
void onStateChanged();
}
}
package com.didichuxing.doraemonkit.ui.widget.bottomview;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
import com.didichuxing.doraemonkit.R;
/**
* 从底部向上弹出的选择器
*
* @author vinda
* @since 15/5/21
*/
public class BottomUpWindow extends PopupWindow {
private final String TAG = "BottomUpSelectWindow";
private View thisView;
private View tv_submit;
private final View titleViiew;
private FrameLayout contentPanel;
private AssociationView associationView;
private View ll_panel;
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
final int vid = v.getId();
if (vid == R.id.tv_submit) {
Object submit = associationView.submit();
if (mOnSubmitListener != null) {
mOnSubmitListener.submit(submit);
}
dismiss();
} else if (vid == R.id.tv_cancel) {
cancel();
}
}
};
public BottomUpWindow(Context context) {
super(context);
LayoutInflater layoutInflater = LayoutInflater.from(context);
thisView = layoutInflater.inflate(R.layout.dk_item_layout_bottom_up_select_window, null);
ll_panel = thisView.findViewById(R.id.ll_panel);
titleViiew = thisView.findViewById(R.id.tv_title);
contentPanel = thisView.findViewById(R.id.content);
this.setContentView(thisView);
initView();
this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
this.setFocusable(true);
this.setTouchable(true);
this.setOutsideTouchable(true);
ColorDrawable dw = new ColorDrawable(0x80000000);
this.setBackgroundDrawable(dw);
}
private void initView() {
tv_submit = thisView.findViewById(R.id.tv_submit);
tv_submit.setOnClickListener(onClickListener);
thisView.findViewById(R.id.tv_cancel).setOnClickListener(onClickListener);
//点击在上方时关闭
thisView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cancel();
}
});
}
/**
* 设置中间内容的view
*
* @param view
*/
public BottomUpWindow setContent(AssociationView view) {
associationView = view;
contentPanel.removeAllViews();
contentPanel.addView(associationView.getView());
associationView.setOnStateChangeListener(new AssociationView.OnStateChangeListener() {
@Override
public void onStateChanged() {
tv_submit.setEnabled(associationView.isCanSubmit());
}
});
return this;
}
@Override
public void dismiss() {
//动画
TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1);
animation.setDuration(200);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
ll_panel.setVisibility(View.GONE);
dismissWindow();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
ll_panel.startAnimation(animation);
if (associationView != null) {
associationView.onHide();
}
}
/**
* 隐藏整个窗口
*/
private void dismissWindow() {
try {
super.dismiss();
} catch (Throwable e) {
}
}
private void cancel() {
associationView.cancel();
dismiss();
if (mOnSubmitListener != null) {
mOnSubmitListener.cancel();
}
}
public BottomUpWindow show(View parent) {
this.showAtLocation(parent, Gravity.BOTTOM
| Gravity.CENTER_HORIZONTAL, 0, 0);
ll_panel.setVisibility(View.VISIBLE);
//动画
TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0);
animation.setDuration(200);
ll_panel.startAnimation(animation);
if (associationView != null) {
associationView.onShow();
}
return this;
}
private OnSubmitListener mOnSubmitListener;
public void setOnSubmitListener(OnSubmitListener onSubmitListener) {
this.mOnSubmitListener = onSubmitListener;
}
public interface OnSubmitListener {
void submit(Object object);
void cancel();
}
}
package com.didichuxing.doraemonkit.ui.widget.bottomview;
import android.content.Context;
import android.text.InputType;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import com.didichuxing.doraemonkit.kit.fileexplorer.SpBean;
public class EditSpInputView extends AssociationView {
private final EditText editText;
private SpBean spBean;
public EditSpInputView(Context context, SpBean spBean, int inputType) {
this.spBean = spBean;
editText = new EditText(context);
editText.setText(spBean.value.toString());
editText.setInputType(inputType | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
editText.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
editText.setSelection(spBean.value.toString().length());
}
@Override
public Object submit() {
return spBean.toDefaultClass(editText.getText().toString());
}
@Override
public void cancel() {
}
@Override
public View getView() {
return editText;
}
@Override
public boolean isCanSubmit() {
return true;
}
@Override
public void onShow() {
}
@Override
public void onHide() {
}
}
......@@ -37,7 +37,7 @@ public class CacheUtils {
return readObject(file);
}
private static boolean saveObject(Serializable ser, File file) {
public static boolean saveObject(Serializable ser, File file) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
......@@ -67,7 +67,7 @@ public class CacheUtils {
}
}
private static Serializable readObject(File file) {
public static Serializable readObject(File file) {
if (file == null || !file.exists() || file.isDirectory()) {
return null;
}
......
......@@ -40,7 +40,7 @@ public class DatabaseUtil {
Cursor cursor = database.query(tableName, null, null, null, null, null, null);
int rowCount = cursor.getCount();
String[][] words = new String[strings.length][rowCount];
for (int y = 0; y <rowCount; y++) {
for (int y = 0; y < rowCount; y++) {
if (cursor.moveToNext()) {
for (int x = 0; x < strings.length; x++) {
if (cursor.getType(x) == Cursor.FIELD_TYPE_BLOB) {
......
......@@ -38,7 +38,7 @@ public class DoraemonStatisticsUtil {
try {
jsonObject.put("appId", appId);
jsonObject.put("appName", appName);
jsonObject.put("version", "1.1.7");
jsonObject.put("version", "1.1.8");
jsonObject.put("type", type);
jsonObject.put("from", from);
} catch (JSONException e) {
......
......@@ -194,6 +194,16 @@ public class FileUtil {
}
return false;
}
public static boolean isTxt(File file) {
if (file == null) {
return false;
}
String suffix = getSuffix(file);
return TXT.equals(suffix);
}
/**
* @param file
*/
......
package com.didichuxing.doraemonkit.util;
import java.util.Date;
/**
* Created by wanglikun on 2019-06-12
*/
public class FormatUtil {
private FormatUtil() {
}
public static String format(long time) {
return new Date(time).toString();
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.util;
import java.lang.reflect.Field;
/**
* @author: linjizong
* @date: 2019/3/11
* @desc:
*/
public class ReflectUtils {
public static Object getField(Object object, String fieldName) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
package com.didichuxing.doraemonkit.util;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 反射工具类
*/
public class Reflector {
public static final String TAG = "Reflector";
protected Class<?> mType;
protected Object mCaller;
protected Constructor mConstructor;
protected Field mField;
protected Method mMethod;
public static class ReflectedException extends Exception {
public ReflectedException(String message) {
super(message);
}
public ReflectedException(String message, Throwable cause) {
super(message, cause);
}
}
public static Reflector on(@NonNull String name) throws ReflectedException {
return on(name, true, Reflector.class.getClassLoader());
}
public static Reflector on(@NonNull String name, boolean initialize) throws ReflectedException {
return on(name, initialize, Reflector.class.getClassLoader());
}
public static Reflector on(@NonNull String name, boolean initialize, @Nullable ClassLoader loader) throws ReflectedException {
try {
return on(Class.forName(name, initialize, loader));
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
public static Reflector on(@NonNull Class<?> type) {
Reflector reflector = new Reflector();
reflector.mType = type;
return reflector;
}
public static Reflector with(@NonNull Object caller) throws ReflectedException {
return on(caller.getClass()).bind(caller);
}
protected Reflector() {
}
public Reflector constructor(@Nullable Class<?>... parameterTypes) throws ReflectedException {
try {
mConstructor = mType.getDeclaredConstructor(parameterTypes);
mConstructor.setAccessible(true);
mField = null;
mMethod = null;
return this;
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
@SuppressWarnings("unchecked")
public <R> R newInstance(@Nullable Object ... initargs) throws ReflectedException {
if (mConstructor == null) {
throw new ReflectedException("Constructor was null!");
}
try {
return (R) mConstructor.newInstance(initargs);
} catch (InvocationTargetException e) {
throw new ReflectedException("Oops!", e.getTargetException());
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
protected Object checked(@Nullable Object caller) throws ReflectedException {
if (caller == null || mType.isInstance(caller)) {
return caller;
}
throw new ReflectedException("Caller [" + caller + "] is not a instance of type [" + mType + "]!");
}
protected void check(@Nullable Object caller, @Nullable Member member, @NonNull String name) throws ReflectedException {
if (member == null) {
throw new ReflectedException(name + " was null!");
}
if (caller == null && !Modifier.isStatic(member.getModifiers())) {
throw new ReflectedException("Need a caller!");
}
checked(caller);
}
public Reflector bind(@Nullable Object caller) throws ReflectedException {
mCaller = checked(caller);
return this;
}
public Reflector unbind() {
mCaller = null;
return this;
}
public Reflector field(@NonNull String name) throws ReflectedException {
try {
mField = findField(name);
mField.setAccessible(true);
mConstructor = null;
mMethod = null;
return this;
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
protected Field findField(@NonNull String name) throws NoSuchFieldException {
try {
return mType.getField(name);
} catch (NoSuchFieldException e) {
for (Class<?> cls = mType; cls != null; cls = cls.getSuperclass()) {
try {
return cls.getDeclaredField(name);
} catch (NoSuchFieldException ex) {
// Ignored
}
}
throw e;
}
}
@SuppressWarnings("unchecked")
public <R> R get() throws ReflectedException {
return get(mCaller);
}
@SuppressWarnings("unchecked")
public <R> R get(@Nullable Object caller) throws ReflectedException {
check(caller, mField, "Field");
try {
return (R) mField.get(caller);
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
public Reflector set(@Nullable Object value) throws ReflectedException {
return set(mCaller, value);
}
public Reflector set(@Nullable Object caller, @Nullable Object value) throws ReflectedException {
check(caller, mField, "Field");
try {
mField.set(caller, value);
return this;
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
public Reflector method(@NonNull String name, @Nullable Class<?>... parameterTypes) throws ReflectedException {
try {
mMethod = findMethod(name, parameterTypes);
mMethod.setAccessible(true);
mConstructor = null;
mField = null;
return this;
} catch (NoSuchMethodException e) {
throw new ReflectedException("Oops!", e);
}
}
protected Method findMethod(@NonNull String name, @Nullable Class<?>... parameterTypes) throws NoSuchMethodException {
try {
return mType.getMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
for (Class<?> cls = mType; cls != null; cls = cls.getSuperclass()) {
try {
return cls.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException ex) {
// Ignored
}
}
throw e;
}
}
public <R> R call(@Nullable Object... args) throws ReflectedException {
return callByCaller(mCaller, args);
}
@SuppressWarnings("unchecked")
public <R> R callByCaller(@Nullable Object caller, @Nullable Object... args) throws ReflectedException {
check(caller, mMethod, "Method");
try {
return (R) mMethod.invoke(caller, args);
} catch (InvocationTargetException e) {
throw new ReflectedException("Oops!", e.getTargetException());
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
public static class QuietReflector extends Reflector {
protected Throwable mIgnored;
public static QuietReflector on(@NonNull String name) {
return on(name, true, QuietReflector.class.getClassLoader());
}
public static QuietReflector on(@NonNull String name, boolean initialize) {
return on(name, initialize, QuietReflector.class.getClassLoader());
}
public static QuietReflector on(@NonNull String name, boolean initialize, @Nullable ClassLoader loader) {
Class<?> cls = null;
try {
cls = Class.forName(name, initialize, loader);
return on(cls, null);
} catch (Throwable e) {
// Log.w(LOG_TAG, "Oops!", e);
return on(cls, e);
}
}
public static QuietReflector on(@Nullable Class<?> type) {
return on(type, (type == null) ? new ReflectedException("Type was null!") : null);
}
private static QuietReflector on(@Nullable Class<?> type, @Nullable Throwable ignored) {
QuietReflector reflector = new QuietReflector();
reflector.mType = type;
reflector.mIgnored = ignored;
return reflector;
}
public static QuietReflector with(@Nullable Object caller) {
if (caller == null) {
return on((Class<?>) null);
}
return on(caller.getClass()).bind(caller);
}
protected QuietReflector() {
}
public Throwable getIgnored() {
return mIgnored;
}
protected boolean skip() {
return skipAlways() || mIgnored != null;
}
protected boolean skipAlways() {
return mType == null;
}
@Override
public QuietReflector constructor(@Nullable Class<?>... parameterTypes) {
if (skipAlways()) {
return this;
}
try {
mIgnored = null;
super.constructor(parameterTypes);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public <R> R newInstance(@Nullable Object... initargs) {
if (skip()) {
return null;
}
try {
mIgnored = null;
return super.newInstance(initargs);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return null;
}
@Override
public QuietReflector bind(@Nullable Object obj) {
if (skipAlways()) {
return this;
}
try {
mIgnored = null;
super.bind(obj);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public QuietReflector unbind() {
super.unbind();
return this;
}
@Override
public QuietReflector field(@NonNull String name) {
if (skipAlways()) {
return this;
}
try {
mIgnored = null;
super.field(name);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public <R> R get() {
if (skip()) {
return null;
}
try {
mIgnored = null;
return super.get();
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return null;
}
@Override
public <R> R get(@Nullable Object caller) {
if (skip()) {
return null;
}
try {
mIgnored = null;
return super.get(caller);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return null;
}
@Override
public QuietReflector set(@Nullable Object value) {
if (skip()) {
return this;
}
try {
mIgnored = null;
super.set(value);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public QuietReflector set(@Nullable Object caller, @Nullable Object value) {
if (skip()) {
return this;
}
try {
mIgnored = null;
super.set(caller, value);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public QuietReflector method(@NonNull String name, @Nullable Class<?>... parameterTypes) {
if (skipAlways()) {
return this;
}
try {
mIgnored = null;
super.method(name, parameterTypes);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return this;
}
@Override
public <R> R call(@Nullable Object... args) {
if (skip()) {
return null;
}
try {
mIgnored = null;
return super.call(args);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return null;
}
@Override
public <R> R callByCaller(@Nullable Object caller, @Nullable Object... args) {
if (skip()) {
return null;
}
try {
mIgnored = null;
return super.callByCaller(caller, args);
} catch (Throwable e) {
mIgnored = e;
// Log.w(LOG_TAG, "Oops!", e);
}
return null;
}
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package com.didichuxing.doraemonkit.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
/**
* Created by wanglikun on 2018/9/14.
......@@ -11,33 +12,62 @@ public class SharedPrefsUtil {
private static final String SHARED_PREFS_DORAEMON = "shared_prefs_doraemon";
private static SharedPreferences getSharedPrefs(Context context) {
return context.getSharedPreferences(SHARED_PREFS_DORAEMON, Context.MODE_PRIVATE);
return getSharedPrefs(context, SHARED_PREFS_DORAEMON);
}
public static void putString(Context context, String key, String value) {
getSharedPrefs(context).edit().putString(key, value).apply();
@Nullable
public static SharedPreferences getSharedPrefs(Context context, String name) {
return context.getSharedPreferences(name, Context.MODE_PRIVATE);
}
public static String getString(Context context,String key, String defVal) {
public static String getString(Context context, String key, String defVal) {
return getSharedPrefs(context).getString(key, defVal);
}
public static void putString(Context context, String key, String value) {
putString(context, SHARED_PREFS_DORAEMON, key, value);
}
public static void putString(Context context, String table, String key, String value) {
getSharedPrefs(context, table).edit().putString(key, value).apply();
}
public static void putBoolean(Context context, String key, boolean value) {
if (context == null) {
return;
}
getSharedPrefs(context).edit().putBoolean(key, value).apply();
putBoolean(context, SHARED_PREFS_DORAEMON, key, value);
}
public static void putBoolean(Context context, String table, String key, boolean value) {
getSharedPrefs(context, table).edit().putBoolean(key, value).apply();
}
public static boolean getBoolean(Context context,String key, boolean defVal) {
public static boolean getBoolean(Context context, String key, boolean defVal) {
return context != null && getSharedPrefs(context).getBoolean(key, defVal);
}
public static void putInt(Context context, String key, int value) {
getSharedPrefs(context).edit().putInt(key, value).apply();
putInt(context, SHARED_PREFS_DORAEMON, key, value);
}
public static int getInt(Context context,String key, int defVal) {
public static void putInt(Context context, String table, String key, Integer value) {
getSharedPrefs(context, table).edit().putInt(key, value).apply();
}
public static int getInt(Context context, String key, int defVal) {
return getSharedPrefs(context).getInt(key, defVal);
}
public static void putFloat(Context context, String table, String key, Float value) {
getSharedPrefs(context, table).edit().putFloat(key, value).apply();
}
public static void putFloat(Context context, String key, Float value) {
getSharedPrefs(context, SHARED_PREFS_DORAEMON).edit().putFloat(key, value).apply();
}
public static void putLong(Context context, String table, String key, Long value) {
getSharedPrefs(context, table).edit().putLong(key, value).apply();
}
}
......@@ -17,11 +17,19 @@
<View
style="@style/DK.Shadow.Bottom"/>
<ListView
android:id="@+id/lv_crash"
<android.support.v7.widget.RecyclerView
android:visibility="gone"
android:id="@+id/crash_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"/>
android:layout_height="match_parent" />
<TextView
android:id="@+id/no_record_hint"
android:text="@string/dk_crash_capture_no_record"
style="@style/DK.TextBig.Dark"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
......@@ -21,29 +21,4 @@
android:layout_height="0dp"
android:layout_weight="10" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/dk_cancel">
</Button>
<Button
android:id="@+id/btn_submit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/dk_submit">
</Button>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_crash_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawableRight="@drawable/dk_more_icon"
android:padding="@dimen/dk_dp_15"
android:textColor="@color/dk_color_333333"
android:textSize="@dimen/dk_font_size_14"/>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="center_horizontal"
style="@style/DK.TextBig.Dark"
android:id="@+id/time" />
<TextView
android:id="@+id/content"
style="@style/DK.Text.Dark"
android:gravity="left" />
<View style="@style/DK.Divider" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_panel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@color/foreground_wtf"
android:clickable="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="42dp">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/dk_cancel" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/tv_submit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/dk_submit" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentBottom="true"
android:background="@color/dk_color_000000" />
</RelativeLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/foreground_wtf" />
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -40,7 +40,7 @@
android:layout_centerVertical="true"
android:layout_alignWithParentIfMissing="true"
android:layout_toLeftOf="@id/right_icon"
android:layout_marginRight="5dp"
android:layout_marginRight="15dp"
android:text="@string/dk_app_name"
android:visibility="gone"/>
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="40dp">
<TextView
android:gravity="center"
android:id="@+id/tv_sp_key"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/tv_sp_type"
android:layout_width="0dp"
android:layout_height="wrap_content"
......
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginRight="5dp">
<EditText
android:id="@+id/sp_input"
<TextView
android:id="@+id/tv_sp_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableRight="@drawable/dk_sp_modify"
android:ellipsize="end"
android:gravity="center"
android:maxEms="6"
android:singleLine="true"
android:visibility="gone" />
<Spinner
android:id="@+id/spinner"
<Switch
android:id="@+id/switch_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
\ No newline at end of file
......@@ -173,5 +173,8 @@
<string name="dk_platform_monitor_view_stat_data">view statistics</string>
<string name="dk_platform_monitor_page_data">page data</string>
<string name="dk_log_text_loading">Loading...</string>
<string name="dk_crash_need_permission">Please authorize permissions</string>
<string name="dk_data_clean_toast">Clear system data</string>
<string name="dk_error_tips_permissions_less">Please authorize permissions</string>
</resources>
......@@ -172,4 +172,7 @@
<string name="dk_platform_monitor_view_stat_data">查看统计数据</string>
<string name="dk_platform_monitor_page_data">页面数据</string>
<string name="dk_log_text_loading">日志加载中...</string>
<string name="dk_crash_need_permission">请授权读写权限,避免crash文件丢失</string>
<string name="dk_data_clean_toast">清除系统资料</string>
<string name="dk_error_tips_permissions_less">请进行授权才可以使用该功能</string>
</resources>
......@@ -154,4 +154,19 @@
<string name="dk_network_detail_title_body">Message Body</string>
<string name="dk_network_detail_title_url">鏈接</string>
<string name="dk_network_summary_total_number_time_tips">總封包數</string>
<string name="dk_cancel">取消</string>
<string name="dk_confirm">確認</string>
<string name="dk_crash_need_permission">請授權讀寫權限,避免crash文件丟失</string>
<string name="dk_db_tips_insert">添加</string>
<string name="dk_delete">刪除</string>
<string name="dk_error_tips_permissions_less">請進行授權才可以使用該功能</string>
<string name="dk_fail">失敗</string>
<string name="dk_frameinfo_custom">自定義</string>
<string name="dk_hint">提示</string>
<string name="dk_share">分享</string>
<string name="dk_platform_monitor_data_button">開始測試</string>
<string name="dk_platform_monitor_data_button_stop">結束測試</string>
<string name="dk_success">成功</string>
<string name="dk_submit">提交</string>
<string name="dk_log_text_loading">日誌加載中...</string>
</resources>
\ No newline at end of file
......@@ -92,6 +92,7 @@
<string name="dk_crash_capture_switch">Crash日志收集开关</string>
<string name="dk_crash_capture_clean_data">一键清理Crash日志</string>
<string name="dk_crash_capture_summary_title">Crash日志列表</string>
<string name="dk_crash_need_permission">请授权读写权限,避免crash文件丢失</string>
<string name="dk_weak_network_switch">模拟弱网开关</string>
<string name="dk_weak_network_off">断网</string>
......@@ -185,5 +186,6 @@
<string name="dk_platform_monitor_view_stat_data">查看统计数据</string>
<string name="dk_platform_monitor_page_data">页面数据</string>
<string name="dk_log_text_loading">日志加载中...</string>
<string name="dk_data_clean_toast">清除系统资料</string>
</resources>
......@@ -3,7 +3,7 @@ apply plugin: 'com.novoda.bintray-release'
publish {
def groupProjectID = 'com.didichuxing.doraemonkit'
def artifactProjectID = 'doraemonkit'
def publishVersionID = '1.1.7'
def publishVersionID = '1.1.8'
userOrg = 'doraemonkit'
repoName = 'DoraemonKit'
......
apply plugin: 'com.android.library'
apply from: './upload.gradle'
android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
lintOptions {
abortOnError false
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation "com.android.support:design:26.0.2"
debugImplementation project(':doraemonkit')
releaseImplementation 'com.didichuxing.doraemonkit:doraemonkit:1.1.8'
implementation 'com.taobao.android:weex_inspector:0.18.10'
implementation "com.taobao.android:weex_sdk:0.24.0"
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.didichuxing.doraemonkit.weex">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:label="@string/app_name">
<activity android:name=".devtool.DevToolActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<activity android:name=".devtool.DevToolScanActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<activity android:name=".common.DKCommonActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
</application>
</manifest>
package com.didichuxing.doraemonkit.weex;
import android.app.Application;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.kit.IKit;
import com.didichuxing.doraemonkit.weex.log.WeexLogKit;
import com.didichuxing.doraemonkit.weex.devtool.DevToolKit;
import com.didichuxing.doraemonkit.weex.info.WeexInfoKit;
import com.didichuxing.doraemonkit.weex.storage.StorageKit;
import java.util.ArrayList;
import java.util.List;
/**
* @author haojianglong
* @date 2019-06-11
*/
public class DKWeexInstance {
private DKWeexInstance() {
}
public static DKWeexInstance getInstance() {
return SingleHolder.sInstance;
}
private static class SingleHolder {
private static final DKWeexInstance sInstance = new DKWeexInstance();
}
public void init(Application app) {
List<IKit> bizKits = new ArrayList<>();
bizKits.add(new WeexLogKit());
bizKits.add(new StorageKit());
bizKits.add(new WeexInfoKit());
bizKits.add(new DevToolKit());
DoraemonKit.install(app, bizKits);
}
}
package com.didichuxing.doraemonkit.weex.common;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.didichuxing.doraemonkit.ui.base.BaseActivity;
import com.didichuxing.doraemonkit.ui.base.BaseFragment;
/**
* @author haojianglong
* @date 2019-06-18
*/
public class DKCommonActivity extends BaseActivity {
private static final String CLASSNAME = "className";
public static void startWith(Context context, Class<? extends BaseFragment> clazz) {
Intent intent = new Intent(context, DKCommonActivity.class);
intent.putExtra(CLASSNAME, clazz);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if (bundle == null) {
finish();
return;
}
Class<BaseFragment> clazz = (Class<BaseFragment>) getIntent().getSerializableExtra(CLASSNAME);
showContent(clazz);
}
}
package com.didichuxing.doraemonkit.weex.devtool;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.widget.Toast;
import com.didichuxing.doraemonkit.zxing.activity.CaptureActivity;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.WXSDKEngine;
/**
* @author haojianglong
* @date 2019-06-25
*/
public class DevToolActivity extends AppCompatActivity {
private final int REQUEST_CODE_CAMERA = 0x100;
private final int REQUEST_CODE_SCAN = 0x101;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
String[] permissions = {Manifest.permission.CAMERA};
requestPermissions(permissions, REQUEST_CODE_CAMERA);
} else {
startScan();
}
} else {
startScan();
}
}
private void startScan() {
Intent intent = new Intent(this, DevToolScanActivity.class);
startActivityForResult(intent, REQUEST_CODE_SCAN);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_CAMERA) {
if (permissions.length > 0) {
for (int i = 0; i < permissions.length; i++) {
if (Manifest.permission.CAMERA.equals(permissions[i]) &&
grantResults[i] == PackageManager.PERMISSION_GRANTED) {
startScan();
return;
}
}
}
finish();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SCAN && resultCode == Activity.RESULT_OK) {
if (data != null && data.hasExtra(CaptureActivity.INTENT_EXTRA_KEY_QR_SCAN)) {
String code = data.getStringExtra(CaptureActivity.INTENT_EXTRA_KEY_QR_SCAN);
if (!TextUtils.isEmpty(code)) {
try {
Uri uri = Uri.parse(code);
handleScanResult(uri);
} catch (Exception e) {
e.printStackTrace();
} finally {
finish();
}
} else {
handleNoResult();
}
} else {
handleNoResult();
}
} else {
handleNoResult();
}
}
private void handleNoResult() {
Toast.makeText(getApplicationContext(), "没有扫描到任何内容>_<", Toast.LENGTH_SHORT);
finish();
}
private void handleScanResult(Uri uri) {
if (WXEnvironment.isApkDebugable()) {
String devToolUrl = uri.getQueryParameter("_wx_devtool");
if (!TextUtils.isEmpty(devToolUrl)) {
WXEnvironment.sRemoteDebugProxyUrl = devToolUrl;
WXEnvironment.sDebugServerConnectable = true;
WXSDKEngine.reload(getApplicationContext(), false);
}
}
finish();
}
}
package com.didichuxing.doraemonkit.weex.devtool;
import android.content.Context;
import android.content.Intent;
import com.didichuxing.doraemonkit.kit.Category;
import com.didichuxing.doraemonkit.kit.IKit;
import com.didichuxing.doraemonkit.weex.R;
/**
* @author haojianglong
* @date 2019-06-11
*/
public class DevToolKit implements IKit {
@Override
public int getCategory() {
return Category.BIZ;
}
@Override
public int getName() {
return R.string.dk_dev_tool_name;
}
@Override
public int getIcon() {
return R.drawable.dk_custom;
}
@Override
public void onClick(Context context) {
Intent intent = new Intent(context, DevToolActivity.class);
context.startActivity(intent);
}
@Override
public void onAppInit(Context context) {
}
}
package com.didichuxing.doraemonkit.weex.devtool;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.didichuxing.doraemonkit.ui.widget.titlebar.HomeTitleBar;
import com.didichuxing.doraemonkit.weex.R;
import com.didichuxing.doraemonkit.zxing.activity.CaptureActivity;
/**
* @author haojianglong
* @date 2019-06-18
*/
public class DevToolScanActivity extends CaptureActivity {
@Override
public void setContentView(View view) {
super.setContentView(view);
initTitleBar();
}
@Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
initTitleBar();
}
private void initTitleBar() {
HomeTitleBar homeTitleBar = new HomeTitleBar(this);
homeTitleBar.setBackgroundColor(getResources().getColor(R.color.foreground_wtf));
homeTitleBar.setTitle(getResources().getString(R.string.dk_dev_tool_title));
homeTitleBar.setIcon(R.drawable.dk_close_icon);
homeTitleBar.setListener(new HomeTitleBar.OnTitleBarClickListener() {
@Override
public void onRightClick() {
finish();
}
});
FrameLayout.LayoutParams params =
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
(int) getResources().getDimension(R.dimen.dk_home_title_height));
((FrameLayout) findViewById(android.R.id.content)).addView(homeTitleBar, params);
}
}
package com.didichuxing.doraemonkit.weex.info;
/**
* @author haojianglong
* @date 2019-06-25
*/
public class WeexInfo {
public String key;
public String value;
public WeexInfo(String key, String value) {
this.key = key;
this.value = value;
}
}
package com.didichuxing.doraemonkit.ui.crash;
package com.didichuxing.doraemonkit.weex.info;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.weex.R;
import java.io.File;
import java.util.List;
public class CrashCaptureAdapter extends BaseAdapter {
private List<File> files;
/**
* @author haojianglong
* @date 2019-06-25
*/
public class WeexInfoAdapter extends BaseAdapter {
public CrashCaptureAdapter(List<File> files) {
this.files = files;
private Context mContext;
private List<WeexInfo> mWeexInfos;
public void setWeexInfos(List<WeexInfo> infos) {
this.mWeexInfos = infos;
}
public WeexInfoAdapter(Context context) {
this.mContext = context;
}
@Override
public int getCount() {
return files.size();
return mWeexInfos.size();
}
@Override
public Object getItem(int position) {
return files.get(position);
return mWeexInfos.get(position);
}
@Override
public long getItemId(int position) {
return position;
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.dk_item_crash_capture, parent, false);
viewHolder = new ViewHolder(convertView);
convertView = LayoutInflater.from(mContext)
.inflate(R.layout.dk_fragment_info_item, null);
}
ViewHolder viewHolder;
if (convertView.getTag() == null) {
viewHolder = new ViewHolder();
viewHolder.keyText = convertView.findViewById(R.id.info_item_key);
viewHolder.valueText = convertView.findViewById(R.id.info_item_value);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.setData(files.get(position).getName());
setText(viewHolder.keyText, mWeexInfos.get(position).key);
setText(viewHolder.valueText, mWeexInfos.get(position).value);
convertView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
(int) mContext.getResources().getDimension(R.dimen.dk_title_height)));
return convertView;
}
private class ViewHolder {
private TextView textView;
public ViewHolder(View view) {
textView = view.findViewById(R.id.tv_crash_item);
private void setText(TextView textView, String text) {
if (TextUtils.isEmpty(text)) {
textView.setVisibility(View.GONE);
} else {
textView.setVisibility(View.VISIBLE);
textView.setText(text);
}
}
public void setData(String string) {
textView.setText(string);
}
class ViewHolder {
TextView keyText;
TextView valueText;
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册