├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ ├── Baidu.xml
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LogView_GitHub.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── tony
│ │ └── com
│ │ └── logview
│ │ ├── MainActivity.java
│ │ └── TestActivity.java
│ └── res
│ ├── layout
│ ├── activity_main.xml
│ └── activity_test.xml
│ ├── menu
│ ├── menu_main.xml
│ └── menu_test.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── logmodel
├── .gitignore
├── build.gradle
├── logmodel.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── tony
│ │ └── com
│ │ └── logmodel
│ │ ├── CommonUtils
│ │ └── LogUtils.java
│ │ ├── LogConfig.java
│ │ ├── LogView.java
│ │ ├── LogWindow.java
│ │ ├── adpater
│ │ └── SimpleTextAdapter.java
│ │ ├── control
│ │ ├── LogCtrl.java
│ │ └── TraceBuffer.java
│ │ └── model
│ │ ├── LogCat.java
│ │ ├── LogMainThread.java
│ │ ├── LogManager.java
│ │ ├── MainThread.java
│ │ ├── TraceLevel.java
│ │ └── TraceObject.java
│ └── res
│ └── values
│ └── strings.xml
├── settings.gradle
└── source
├── instance1.gif
└── instance2.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | LogView
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/Baidu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Baidu
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | 1.7
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LogView_GitHub.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LogView
2 | ##Describe
3 | Hi,guys ,this is a android logcat library based on [Lynx](https://github.com/pedrovgs/Lynx),so you can show your Android logcat in a float view .But it’s different. I think it is more
4 | useful for hybrid app. Because it's very simple to import it and don't need other jars.
5 | Firstly,I am so sorry for my screenshots gif.It's too big , so I have to translate them to the end.
6 |
7 |
8 | ##Add it to your project
9 |
10 | There are two ways to use this lib.
11 |
12 | 1. Just import this model to your project , but do't forget change your build.gradle and setting.gradle.
13 | 2. Cd the list of my logmodel, and execute "./gradlew makeJar"(if it does't work , please use gradle makeJar) on the console.There will be build a jar(log.jar) in the libs list.
14 |
15 | ## ~~USE GRADLE DEPENDENCIES~~ (Discard)
16 |
17 | allprojects {
18 | repositories {
19 | ...
20 | maven { url "https://jitpack.io" }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile 'com.github.sanyinchen:LogView:v1.0'
26 | }
27 |
28 | ## USAGES
29 | It's very simple to use this lib.You should add two line codes to your activity.
30 | such as:
31 |
32 | LogWindow logWindow = new LogWindow(this, getApplication());
33 | logWindow.creatLogView();
34 |
35 | Please be careful this , you need a promise to execute your application:
36 |
37 |
38 |
39 | Yes,it's onlely need one piece of promise and two code lines.No more other jars.
40 | I think it's very import for a finished project.Because we usually don't want to import too much jars that we don't need in release.
41 |
42 | ## Summary
43 | * Thanks for [Lynx](https://github.com/pedrovgs/Lynx),it‘s a very nice job.
44 | * If you have any question,please email to me(My email:sanyinchen@gmail.com)
45 | * Welcome to subscribe my [google+](https://plus.google.com/u/0/100465464266192894461)
46 |
47 | ## Screenshots
48 | 
49 | 
50 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | apply plugin: 'com.android.application'
5 |
6 | android {
7 | compileSdkVersion 23
8 | buildToolsVersion "23.0.3"
9 |
10 | defaultConfig {
11 | applicationId "tony.com.logview"
12 | minSdkVersion 15
13 | targetSdkVersion 23
14 | versionCode 1
15 | versionName "1.0"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | lintOptions {
24 | checkReleaseBuilds false
25 | abortOnError false
26 | }
27 | }
28 |
29 | dependencies {
30 | compile fileTree(dir: 'libs', include: ['*.jar'])
31 | compile project(':logmodel')
32 | // compile 'com.android.support:appcompat-v7:23.1.0'
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/sanyinchen/Tools/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/java/tony/com/logview/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logview;
5 |
6 | import android.content.Intent;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.widget.Button;
12 | import tony.com.logmodel.LogView;
13 | import tony.com.logmodel.LogWindow;
14 |
15 | public class MainActivity extends AppCompatActivity {
16 |
17 | int i = 0;
18 | Button testButton;
19 | Button startActivityButton;
20 | Button finishTestButton;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_main);
26 | testButton = (Button) findViewById(R.id.mybutton);
27 | startActivityButton = (Button) findViewById(R.id.startActivity);
28 | finishTestButton = (Button) findViewById(R.id.finishActivity);
29 | final LogWindow logWindow = new LogWindow(this, getApplication()).setregisterLifeCycleInStop(false);
30 | testButton.setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | // createFloatView();
34 | logWindow.creatLogView();
35 | }
36 | });
37 | startActivityButton.setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | // onDestroy();
41 | startActivity(new Intent(getBaseContext(), TestActivity.class));
42 | }
43 | });
44 | finishTestButton.setOnClickListener(new View.OnClickListener() {
45 | @Override
46 | public void onClick(View v) {
47 | finish();
48 | }
49 | });
50 |
51 | new Thread() {
52 | @Override
53 | public void run() {
54 | super.run();
55 |
56 | while (true) {
57 | System.out.println("test-->" + (++i));
58 | Log.e("srcomp", "Just test error work: " + i);
59 | Log.d("srcomp", "Just test: " + (++i));
60 | Log.i("srcomp", "Just test: info : " + (++i));
61 | try {
62 | Thread.sleep(1000);
63 | } catch (InterruptedException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | }
68 | }.start();
69 |
70 | }
71 |
72 | @Override
73 | protected void onDestroy() {
74 | super.onDestroy();
75 | Log.d("srcomp", "Activity destory");
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/tony/com/logview/TestActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logview;
5 |
6 | import android.annotation.TargetApi;
7 | import android.os.Build;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.os.Bundle;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.webkit.ConsoleMessage;
13 | import android.webkit.WebChromeClient;
14 | import android.webkit.WebView;
15 | import android.webkit.WebViewClient;
16 | import android.widget.Button;
17 |
18 | import tony.com.logmodel.LogWindow;
19 |
20 | public class TestActivity extends AppCompatActivity {
21 | private LogWindow logWindow;
22 |
23 | @TargetApi(Build.VERSION_CODES.KITKAT)
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_test);
28 | logWindow = new LogWindow(this, getApplication()).setregisterLifeCycleInStop(false);
29 | logWindow.creatLogView();
30 | Button button = (Button) findViewById(R.id.test_finish);
31 | button.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | finish();
35 | }
36 | });
37 | WebView webView = (WebView) findViewById(R.id.test_web);
38 | webView.setWebChromeClient(new DefaultWebChromeClient());
39 | webView.setWebViewClient(new DefaultWebViewClient());
40 | webView.loadUrl("https://developer.android.google.cn/");
41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
42 | webView.setWebContentsDebuggingEnabled(true);
43 | }
44 |
45 | }
46 |
47 | @Override
48 | public void finish() {
49 | super.finish();
50 | logWindow.dismiss();
51 | }
52 |
53 | private class DefaultWebViewClient extends WebViewClient {
54 |
55 | }
56 |
57 | private class DefaultWebChromeClient extends WebChromeClient {
58 |
59 | @Override
60 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
61 |
62 | Log.d("srcomp", "[console]" + consoleMessage.message());
63 | return super.onConsoleMessage(consoleMessage);
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
23 |
24 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
4 |
14 |
15 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_test.xml:
--------------------------------------------------------------------------------
1 |
4 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LogView
3 |
4 | Hello world!
5 | Settings
6 | TestActivity
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.3.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
22 | maven { url "https://repo.maven.apache.org/maven2" }
23 | }
24 |
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Nov 24 10:17:33 CST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/logmodel/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/logmodel/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | apply plugin: 'com.android.library'
5 |
6 | android {
7 | compileSdkVersion 23
8 | buildToolsVersion "23.0.1"
9 |
10 | defaultConfig {
11 | minSdkVersion 11
12 | targetSdkVersion 18
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_7
24 | targetCompatibility JavaVersion.VERSION_1_7
25 | }
26 | }
27 | task makeJar(type: Copy) {
28 |
29 | from('build/intermediates/bundles/release/')
30 | into('build/libs/')
31 | include('classes.jar')
32 | rename('classes.jar', 'log.jar')
33 |
34 | }
35 | dependencies {
36 |
37 | compile fileTree(dir: 'libs', include: ['*.jar'])
38 | compile 'com.android.support:appcompat-v7:23.1.0'
39 | }
40 |
--------------------------------------------------------------------------------
/logmodel/logmodel.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/logmodel/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/sanyinchen/Tools/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/logmodel/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/CommonUtils/LogUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.CommonUtils;
5 |
6 | import android.content.Context;
7 | import android.util.DisplayMetrics;
8 |
9 | /**
10 | * Created by sanyinchen on 15/11/26.
11 | */
12 | public class LogUtils {
13 | private static int[] disPlay;
14 |
15 | public static int diptopx(Context context, float dipValue) {
16 | if (context == null) {
17 | return 0;
18 | }
19 | float scale = context.getResources().getDisplayMetrics().density;
20 | return (int) (dipValue * scale + 0.5f);
21 | }
22 |
23 | public static int[] getDevDispplay(Context context) {
24 | if (disPlay == null) {
25 | disPlay = new int[2];
26 | DisplayMetrics dm = context.getResources().getDisplayMetrics();
27 | disPlay[0] = dm.widthPixels;
28 | disPlay[1] = dm.heightPixels;
29 | }
30 | return disPlay;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/LogConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel;
5 |
6 | import java.io.Serializable;
7 |
8 | import tony.com.logmodel.model.TraceLevel;
9 |
10 | /**
11 | * Created by sanyinchen on 15/11/24.
12 | */
13 | public class LogConfig implements Serializable, Cloneable {
14 | private static final long serialVersionUID = 293939299388293L;
15 |
16 | private static final float DEFAULT_TEXT_SIZE_IN_PX = 36;
17 |
18 | private int maxNumberOfTracesToShow = 800;
19 | private String filter;
20 | private TraceLevel filterTraceLevel;
21 | private Float textSizeInPx;
22 | private int samplingRate = 150;
23 |
24 | public LogConfig() {
25 | // filter = "console";
26 | filter = "comp";
27 | filterTraceLevel = TraceLevel.VERBOSE;
28 | }
29 |
30 | public LogConfig setMaxNumberOfTracesToShow(int maxNumberOfTracesToShow) {
31 | if (maxNumberOfTracesToShow <= 0) {
32 | throw new IllegalArgumentException(
33 | "You can't use a max number of traces equals or lower than zero.");
34 | }
35 |
36 | this.maxNumberOfTracesToShow = maxNumberOfTracesToShow;
37 | return this;
38 | }
39 |
40 | public LogConfig setFilter(String filter) {
41 | if (filter == null) {
42 | throw new IllegalArgumentException("filter can't be null");
43 | }
44 | this.filter = filter;
45 | return this;
46 | }
47 |
48 | public LogConfig setFilterTraceLevel(TraceLevel filterTraceLevel) {
49 | if (filterTraceLevel == null) {
50 | throw new IllegalArgumentException("filterTraceLevel can't be null");
51 | }
52 | this.filterTraceLevel = filterTraceLevel;
53 | return this;
54 | }
55 |
56 | public LogConfig setTextSizeInPx(float textSizeInPx) {
57 | this.textSizeInPx = textSizeInPx;
58 | return this;
59 | }
60 |
61 | public LogConfig setSamplingRate(int samplingRate) {
62 | this.samplingRate = samplingRate;
63 | return this;
64 | }
65 |
66 | public int getMaxNumberOfTracesToShow() {
67 | return maxNumberOfTracesToShow;
68 | }
69 |
70 | public String getFilter() {
71 | return filter;
72 | }
73 |
74 | public TraceLevel getFilterTraceLevel() {
75 | return filterTraceLevel;
76 | }
77 |
78 | public boolean hasFilter() {
79 | return !"".equals(filter) || !TraceLevel.VERBOSE.equals(filterTraceLevel);
80 | }
81 |
82 | public float getTextSizeInPx() {
83 | return textSizeInPx == null ? DEFAULT_TEXT_SIZE_IN_PX : textSizeInPx;
84 | }
85 |
86 | public boolean hasTextSizeInPx() {
87 | return textSizeInPx != null;
88 | }
89 |
90 | public int getSamplingRate() {
91 | return samplingRate;
92 | }
93 |
94 | @Override
95 | public boolean equals(Object o) {
96 | if (this == o) {
97 | return true;
98 | }
99 | if (!(o instanceof LogConfig)) {
100 | return false;
101 | }
102 |
103 | LogConfig that = (LogConfig) o;
104 |
105 | if (maxNumberOfTracesToShow != that.maxNumberOfTracesToShow) {
106 | return false;
107 | }
108 | if (samplingRate != that.samplingRate) {
109 | return false;
110 | }
111 | if (filter != null ? !filter.equals(that.filter) : that.filter != null) {
112 | return false;
113 | }
114 | if (textSizeInPx != null ? !textSizeInPx.equals(that.textSizeInPx)
115 | : that.textSizeInPx != null) {
116 | return false;
117 | }
118 | if (filterTraceLevel != that.filterTraceLevel) {
119 | return false;
120 | }
121 | return true;
122 | }
123 |
124 | @Override
125 | public int hashCode() {
126 | int result = maxNumberOfTracesToShow;
127 | result = 31 * result + (filter != null ? filter.hashCode() : 0);
128 | result = 31 * result + (textSizeInPx != null ? textSizeInPx.hashCode() : 0);
129 | result = 31 * result + samplingRate;
130 | return result;
131 | }
132 |
133 | @Override
134 | public Object clone() {
135 | return new LogConfig().setMaxNumberOfTracesToShow(getMaxNumberOfTracesToShow())
136 | .setFilter(filter)
137 | .setFilterTraceLevel(filterTraceLevel)
138 | .setSamplingRate(getSamplingRate());
139 | }
140 |
141 | @Override
142 | public String toString() {
143 | return "LynxConfig{"
144 | + "maxNumberOfTracesToShow="
145 | + maxNumberOfTracesToShow
146 | + ", filter='"
147 | + filter
148 | + '\''
149 | + ", textSizeInPx="
150 | + textSizeInPx
151 | + ", samplingRate="
152 | + samplingRate
153 | + '}';
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/LogView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | import android.annotation.TargetApi;
11 | import android.content.Context;
12 | import android.graphics.Color;
13 | import android.graphics.drawable.ColorDrawable;
14 | import android.os.Build;
15 | import android.text.Editable;
16 | import android.text.TextWatcher;
17 | import android.util.Log;
18 | import android.view.Gravity;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.AbsListView;
23 | import android.widget.AdapterView;
24 | import android.widget.ArrayAdapter;
25 | import android.widget.Button;
26 | import android.widget.EditText;
27 | import android.widget.LinearLayout;
28 | import android.widget.ListView;
29 | import android.widget.ProgressBar;
30 | import android.widget.SeekBar;
31 | import android.widget.Spinner;
32 | import android.widget.TextView;
33 | import tony.com.logmodel.CommonUtils.LogUtils;
34 | import tony.com.logmodel.adpater.SimpleTextAdapter;
35 | import tony.com.logmodel.control.LogCtrl;
36 | import tony.com.logmodel.model.LogCat;
37 | import tony.com.logmodel.model.LogMainThread;
38 | import tony.com.logmodel.model.LogManager;
39 | import tony.com.logmodel.model.TraceLevel;
40 | import tony.com.logmodel.model.TraceObject;
41 |
42 | /**
43 | * Created by sanyinchen on 15/11/24.
44 | */
45 | public class LogView extends LinearLayout implements LogCtrl.View {
46 |
47 | private Button settingButton;
48 | private EditText filterEditText;
49 | private LinearLayout bottomLayout;
50 | private Spinner spinner;
51 | private ListView mListView;
52 | private SimpleTextAdapter simpleTextAdapter;
53 | private List data;
54 | private LogCtrl logCtrl;
55 | private int lastScrollPosition;
56 | private OnClickListener refreshClickListener;
57 | private LinearLayout extraSetLayout;
58 |
59 | private SeekBar widthSeekBar;
60 | private SeekBar heidthSeekBar;
61 | private SeekBar touchAreaSeekBar;
62 | private Map extraData;
63 | private ChangeWindowListener changeWindowListener;
64 | private LinearLayout.LayoutParams listLayoutParams;
65 | private LogManager logManager;
66 | private LogConfig logConfig;
67 |
68 | public LogView(Context context, Map extraData) {
69 | super(context);
70 | this.extraData = extraData;
71 | initializeView();
72 | hookListener();
73 | initializePresenter();
74 |
75 | // this.setFocusable(false);
76 | }
77 |
78 | public LogView setRefreshAction() {
79 |
80 | return this;
81 | }
82 |
83 | public LogManager getLogManager() {
84 | return logManager;
85 | }
86 |
87 | public void setChangeWindowListener(ChangeWindowListener changeWindowListener) {
88 | this.changeWindowListener = changeWindowListener;
89 | }
90 |
91 | private void hookListener() {
92 | data = new ArrayList();
93 | simpleTextAdapter = new SimpleTextAdapter(data, getContext());
94 | mListView.setAdapter(simpleTextAdapter);
95 |
96 | mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
97 | @Override
98 | public void onScrollStateChanged(AbsListView view, int scrollState) {
99 |
100 | }
101 |
102 | @Override
103 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
104 | if (lastScrollPosition - firstVisibleItem != 1) {
105 | lastScrollPosition = firstVisibleItem;
106 | }
107 | int lastVisiblePositionInTheList = firstVisibleItem + visibleItemCount;
108 | if (logCtrl != null) {
109 | logCtrl.onScrollToPosition(lastVisiblePositionInTheList);
110 | }
111 | }
112 | });
113 |
114 | ArrayAdapter adapter =
115 | new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, TraceLevel.values());
116 | spinner.setAdapter(adapter);
117 | spinner.setSelection(0);
118 |
119 | spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
120 | @Override
121 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
122 | if (logCtrl != null && position != 1) {
123 | logCtrl.updateFilterTraceLevel((TraceLevel) parent.getItemAtPosition(position));
124 | }
125 | if (logCtrl != null && position == 1) {
126 |
127 | logCtrl.updateFilterTraceLevel((TraceLevel) parent.getItemAtPosition(position));
128 | logCtrl.updateFilter("console");
129 | filterEditText.setText("console");
130 | }
131 | }
132 |
133 | @Override
134 | public void onNothingSelected(AdapterView> parent) {
135 |
136 | }
137 | });
138 |
139 | filterEditText.addTextChangedListener(new TextWatcher() {
140 | @Override
141 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
142 |
143 | }
144 |
145 | @Override
146 | public void onTextChanged(CharSequence s, int start, int before, int count) {
147 | logCtrl.updateFilter(s.toString().trim());
148 | updateView();
149 | }
150 |
151 | @Override
152 | public void afterTextChanged(Editable s) {
153 |
154 | }
155 | });
156 |
157 | settingButton.setOnClickListener(new OnClickListener() {
158 | @Override
159 | public void onClick(View v) {
160 | if (extraSetLayout.getVisibility() == VISIBLE) {
161 | extraSetLayout.setVisibility(GONE);
162 | } else {
163 | extraSetLayout.setVisibility(VISIBLE);
164 | }
165 | }
166 | });
167 |
168 | heidthSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
169 | @Override
170 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
171 |
172 | }
173 |
174 | @Override
175 | public void onStartTrackingTouch(SeekBar seekBar) {
176 |
177 | }
178 |
179 | @Override
180 | public void onStopTrackingTouch(SeekBar seekBar) {
181 | if (changeWindowListener != null) {
182 | changeWindowListener.changeWindowHeight(seekBar.getProgress());
183 | }
184 | }
185 | });
186 |
187 | widthSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
188 | @Override
189 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
190 |
191 | }
192 |
193 | @Override
194 | public void onStartTrackingTouch(SeekBar seekBar) {
195 |
196 | }
197 |
198 | @Override
199 | public void onStopTrackingTouch(SeekBar seekBar) {
200 | if (changeWindowListener != null) {
201 | changeWindowListener.changeWindowsWidth(seekBar.getProgress());
202 | }
203 | }
204 | });
205 |
206 | touchAreaSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
207 | @Override
208 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
209 | listLayoutParams.setMargins(0, LogUtils.diptopx(getContext(), progress), 0, 0);
210 | updateView();
211 | // if (changeWindowListener != null) {
212 | // changeWindowListener.changeTouchArea(progress);
213 | // }
214 | }
215 |
216 | @Override
217 | public void onStartTrackingTouch(SeekBar seekBar) {
218 |
219 | }
220 |
221 | @Override
222 | public void onStopTrackingTouch(SeekBar seekBar) {
223 |
224 | }
225 | });
226 |
227 | }
228 |
229 | private void updateView() {
230 | this.invalidate();
231 | }
232 |
233 | private void initializePresenter() {
234 | logManager = new LogManager(new LogCat(), new LogMainThread());
235 | logConfig = new LogConfig();
236 | logCtrl = new LogCtrl(logManager, this, logConfig);
237 | logCtrl.resume();
238 | filterEditText.setText(logConfig.getFilter());
239 | }
240 |
241 | private void initializeView() {
242 | this.setOrientation(VERTICAL);
243 |
244 | filterEditText = new EditText(getContext());
245 | bottomLayout = new LinearLayout(getContext());
246 | spinner = new Spinner(getContext());
247 |
248 | LinearLayout.LayoutParams refreshLayoutParams =
249 | new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 5);
250 | filterEditText.setHint("setFilter");
251 | filterEditText.setTextColor(Color.BLACK);
252 | filterEditText.setSingleLine();
253 | filterEditText.setGravity(Gravity.CENTER_VERTICAL);
254 | bottomLayout.addView(filterEditText, refreshLayoutParams);
255 |
256 | LinearLayout.LayoutParams spinnerLayoutParams = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 4);
257 | spinnerLayoutParams.setMargins(LogUtils.diptopx(getContext(), 6), 0, 0, 0);
258 | spinner.setGravity(Gravity.CENTER);
259 | bottomLayout.addView(spinner, spinnerLayoutParams);
260 |
261 | LinearLayout.LayoutParams refreshButtonLayoutParams =
262 | new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 2);
263 | refreshButtonLayoutParams.setMargins(LogUtils.diptopx(getContext(), 6), 0, 0, 0);
264 |
265 | settingButton = new Button(getContext());
266 | settingButton.setText("setting");
267 | LinearLayout.LayoutParams settingButtonLayoutParams =
268 | new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 3);
269 | settingButtonLayoutParams.setMargins(LogUtils.diptopx(getContext(), 6), 0, 0, 0);
270 | bottomLayout.addView(settingButton, settingButtonLayoutParams);
271 |
272 | mListView = new ListView(getContext());
273 | mListView.setDivider(new ColorDrawable(Color.WHITE));
274 | mListView.setBackgroundDrawable(new ColorDrawable(Color.argb(200, 0, 0, 0)));
275 | mListView.setStackFromBottom(true);// 设置从底部开始填充
276 |
277 | listLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1);
278 | listLayoutParams.setMargins(0, LogUtils.diptopx(getContext(), 25), 0, 0);
279 | this.addView(mListView, listLayoutParams);
280 |
281 | LinearLayout.LayoutParams bottomLayoutLayoutParams =
282 | new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
283 | this.addView(bottomLayout, bottomLayoutLayoutParams);
284 |
285 | extraSetLayout = new LinearLayout(getContext());
286 | extraSetLayout.setOrientation(VERTICAL);
287 | // 宽度进读条设置
288 | LinearLayout widthLayout = new LinearLayout(getContext());
289 | TextView widthlab = new TextView(getContext());
290 | widthlab.setText("控件宽度:");
291 | LinearLayout.LayoutParams widthParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
292 | ViewGroup.LayoutParams.WRAP_CONTENT);
293 | widthLayout.addView(widthlab, widthParams);
294 | //widthProgeressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleHorizontal);
295 | widthSeekBar = new SeekBar(getContext());
296 | widthSeekBar.setMax(LogUtils.getDevDispplay(getContext())[0]);
297 | widthSeekBar.setProgress(LogUtils.getDevDispplay(getContext())[0]);
298 | LinearLayout.LayoutParams widthProgressBarParams = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
299 | widthLayout.addView(widthSeekBar, widthProgressBarParams);
300 | extraSetLayout.addView(widthLayout);
301 |
302 | // 高度进度条设置
303 | LinearLayout heightLayout = new LinearLayout(getContext());
304 | TextView heigthlab = new TextView(getContext());
305 | heigthlab.setText("控件高度:");
306 | LinearLayout.LayoutParams heigthParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
307 | ViewGroup.LayoutParams.WRAP_CONTENT);
308 | heightLayout.addView(heigthlab, heigthParams);
309 | // heidthProgressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleHorizontal);
310 |
311 | heidthSeekBar = new SeekBar(getContext());
312 | heidthSeekBar.setMax(LogUtils.getDevDispplay(getContext())[1]);
313 | heidthSeekBar.setProgress((int) extraData.get("width"));
314 |
315 | LinearLayout.LayoutParams heidthProgressBarParams = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
316 | heightLayout.addView(heidthSeekBar, heidthProgressBarParams);
317 | extraSetLayout.addView(heightLayout);
318 |
319 | // 触摸区域设置
320 | LinearLayout touchAreaLayout = new LinearLayout(getContext());
321 | TextView touchLab = new TextView(getContext());
322 | touchLab.setText("触摸区域:");
323 | LinearLayout.LayoutParams touchParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
324 | ViewGroup.LayoutParams.WRAP_CONTENT);
325 | touchAreaLayout.addView(touchLab, touchParams);
326 | // heidthProgressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleHorizontal);
327 |
328 | touchAreaSeekBar = new SeekBar(getContext());
329 | touchAreaSeekBar.setMax((int) extraData.get("touchAreaMax"));
330 | touchAreaSeekBar.setProgress((int) extraData.get("touchArea"));
331 |
332 | LinearLayout.LayoutParams touchAreaSeekBarParams = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
333 | touchAreaLayout.addView(touchAreaSeekBar, touchAreaSeekBarParams);
334 | extraSetLayout.addView(touchAreaLayout);
335 | this.addView(extraSetLayout);
336 |
337 | extraSetLayout.setVisibility(GONE);
338 | mListView.setFocusable(false);
339 | mListView.setItemsCanFocus(false);
340 |
341 | }
342 |
343 | @Override
344 | protected void onAttachedToWindow() {
345 | super.onAttachedToWindow();
346 | if (isVisible()) {
347 | resumePresenter();
348 | }
349 | }
350 |
351 | @Override
352 | protected void onVisibilityChanged(View changedView, int visibility) {
353 | super.onVisibilityChanged(changedView, visibility);
354 | if (changedView != this) {
355 | return;
356 | }
357 |
358 | if (visibility == View.VISIBLE) {
359 | resumePresenter();
360 | } else {
361 | pausePresenter();
362 | }
363 | }
364 |
365 | private boolean isVisible() {
366 | return getVisibility() == View.VISIBLE;
367 | }
368 |
369 | private void resumePresenter() {
370 | if (isPresenterReady()) {
371 | logCtrl.resume();
372 | int lastPosition = data.size() - 1;
373 | mListView.setSelection(lastPosition);
374 | }
375 | }
376 |
377 | private boolean isPresenterReady() {
378 | return logCtrl != null;
379 | }
380 |
381 | @Override
382 | protected void onDetachedFromWindow() {
383 | super.onDetachedFromWindow();
384 | pausePresenter();
385 | Log.d("srcomp", "View destory");
386 | }
387 |
388 | private void pausePresenter() {
389 | if (isPresenterReady()) {
390 | logCtrl.pause();
391 | }
392 | }
393 |
394 | @Override
395 | public void showTraces(List traces, int removedTraces) {
396 | if (lastScrollPosition == 0) {
397 | lastScrollPosition = mListView.getFirstVisiblePosition();
398 | }
399 | if (data != null) {
400 | data.clear();
401 | data.addAll(traces);
402 | }
403 | // Log.d("srcomp", "data size: " + data.size());
404 | simpleTextAdapter.notifyDataSetChanged();
405 | updateScrollPosition(removedTraces);
406 |
407 | }
408 |
409 | private void updateScrollPosition(int removedTraces) {
410 | boolean shouldUpdateScrollPosition = removedTraces > 0;
411 | if (shouldUpdateScrollPosition) {
412 | int newScrollPosition = lastScrollPosition - removedTraces;
413 | lastScrollPosition = newScrollPosition;
414 | mListView.setSelectionFromTop(newScrollPosition, 0);
415 | }
416 | }
417 |
418 | @Override
419 | public void clear() {
420 | data.clear();
421 | simpleTextAdapter.notifyDataSetChanged();
422 | }
423 |
424 | @Override
425 | public void disableAutoScroll() {
426 | mListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
427 | }
428 |
429 | @Override
430 | public void enableAutoScroll() {
431 | mListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
432 | }
433 |
434 | @Override
435 | public void agentRefreshAction(android.view.View.OnClickListener onClickListener) {
436 |
437 | }
438 |
439 | @Override
440 | public boolean onTouchEvent(MotionEvent event) {
441 | return super.onTouchEvent(event);
442 |
443 | }
444 |
445 | public interface ChangeWindowListener {
446 | void changeWindowHeight(int height);
447 |
448 | void changeWindowsWidth(int width);
449 |
450 | }
451 |
452 | }
453 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/LogWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel;
5 |
6 | import java.lang.ref.WeakReference;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import android.annotation.TargetApi;
11 | import android.app.Activity;
12 | import android.app.Application;
13 | import android.content.Context;
14 | import android.graphics.PixelFormat;
15 | import android.os.Build;
16 | import android.os.Bundle;
17 | import android.util.Log;
18 | import android.view.KeyEvent;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.view.WindowManager;
23 |
24 | import tony.com.logmodel.CommonUtils.LogUtils;
25 |
26 | /**
27 | * Created by sanyinchen on 15/11/25.
28 | */
29 | public class LogWindow {
30 | private LogView logView;
31 | private WindowManager.LayoutParams params;
32 | private WindowManager wm;
33 | private boolean isAdd = false;
34 | private Context context;
35 | private View.OnTouchListener onTouchListener;
36 | private Application mApplication;
37 | private WeakReference owf;
38 | private boolean registerLifeCycleInStop = false;
39 | private LogConfig logConfig;
40 | private int INITIALHEIGHT = 5;
41 | private int MINHEIGHT = 170;
42 | private int MAXHEIGHTOFFSET = 10;
43 | private int INITIALTOPUCH = 25;
44 | private int MAXTOUCHAREA = 50;
45 | private int MINWEDITH = 100;
46 | private LogView.ChangeWindowListener changeWindowListener;
47 |
48 | public LogWindow setregisterLifeCycleInStop(boolean registerLifeCycleInStopn) {
49 | this.registerLifeCycleInStop = registerLifeCycleInStopn;
50 | return this;
51 | }
52 |
53 | public LogWindow(Context context, Application application) {
54 | this.context = context;
55 | this.mApplication = application;
56 | owf = new WeakReference(this);
57 | }
58 |
59 | public LogWindow setOnTouchListener(View.OnTouchListener onTouchListener) {
60 | this.onTouchListener = onTouchListener;
61 | return this;
62 | }
63 |
64 | public LogWindow setWindowManager(WindowManager wm, WindowManager.LayoutParams params) {
65 | this.wm = wm;
66 | this.params = params;
67 | return this;
68 | }
69 |
70 | public LogWindow setLogCOnfig(LogConfig logConfig) {
71 | this.logConfig = logConfig;
72 | return this;
73 | }
74 |
75 | public void dismiss() {
76 | if (isAdd && logView != null && logView.getParent() != null && wm != null) {
77 | wm.removeView(logView);
78 | }
79 | }
80 |
81 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
82 | public void creatLogView() {
83 | Log.d("srcomp", "creat LogView");
84 | if (!isAdd) {
85 | Map extradata = new HashMap<>();
86 | extradata.put("heidth", (LogUtils.getDevDispplay(context)[1]) / INITIALHEIGHT);
87 | extradata.put("width", LogUtils.getDevDispplay(context)[0]);
88 | extradata.put("touchArea", LogUtils.diptopx(context, INITIALTOPUCH));
89 | extradata.put("touchAreaMax", LogUtils.diptopx(context, MAXTOUCHAREA));
90 | if (wm == null) {
91 | wm = (WindowManager) context.getSystemService(
92 | Context.WINDOW_SERVICE);
93 | params = new WindowManager.LayoutParams();
94 | params.format = PixelFormat.RGBA_8888;
95 | params.type = WindowManager.LayoutParams.TYPE_APPLICATION;
96 | params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
97 | params.width = WindowManager.LayoutParams.MATCH_PARENT;
98 | params.height = LogUtils.diptopx(context, (int) extradata.get("heidth"));
99 |
100 | }
101 | isAdd = true;
102 | if (logView == null) {
103 |
104 | logView = new LogView(context, extradata);
105 | }
106 | if (onTouchListener == null) {
107 | onTouchListener = new View.OnTouchListener() {
108 | int lastX, lastY;
109 | int paramX, paramY;
110 | int startX, startY;
111 |
112 | public boolean onTouch(View v, MotionEvent event) {
113 | switch (event.getAction()) {
114 |
115 | case MotionEvent.ACTION_DOWN:
116 | lastX = (int) event.getRawX();
117 | lastY = (int) event.getRawY();
118 | paramX = params.x;
119 | paramY = params.y;
120 | startX = lastX;
121 | startY = lastY;
122 | break;
123 | case MotionEvent.ACTION_MOVE:
124 | int dx = (int) event.getRawX() - lastX;
125 | int dy = (int) event.getRawY() - lastY;
126 | params.x = paramX + dx;
127 | params.y = paramY + dy;
128 | // 更新悬浮窗位置
129 | wm.updateViewLayout(logView, params);
130 | break;
131 |
132 | default:
133 | break;
134 | }
135 |
136 | return false;
137 | }
138 | };
139 | }
140 | if (changeWindowListener == null) {
141 | changeWindowListener = new LogView.ChangeWindowListener() {
142 |
143 | @Override
144 | public void changeWindowHeight(int height) {
145 |
146 | if (height < LogUtils.diptopx(context, MINHEIGHT)) {
147 | height = LogUtils.diptopx(context, MINHEIGHT);
148 | }
149 | if (height >= LogUtils.getDevDispplay(context)[1] - LogUtils
150 | .diptopx(context, MAXHEIGHTOFFSET)) {
151 | height = LogUtils.getDevDispplay(context)[1] - LogUtils.diptopx(context, MAXHEIGHTOFFSET);
152 | }
153 | params.height = height;
154 | wm.updateViewLayout(logView, params);
155 | }
156 |
157 | @Override
158 | public void changeWindowsWidth(int width) {
159 | if (width <= LogUtils.diptopx(context, MINWEDITH)) {
160 | width = LogUtils.diptopx(context, MINWEDITH);
161 | }
162 | params.width = width;
163 | wm.updateViewLayout(logView, params);
164 | }
165 |
166 | };
167 | }
168 |
169 | logView.setOnTouchListener(onTouchListener);
170 | logView.setChangeWindowListener(changeWindowListener);
171 | if (logConfig != null && logView.getLogManager() != null) {
172 | logView.getLogManager().setLogConfig(logConfig);
173 | }
174 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
175 | mApplication.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
176 | @Override
177 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
178 |
179 | }
180 |
181 | @Override
182 | public void onActivityStarted(Activity activity) {
183 |
184 | }
185 |
186 | @Override
187 | public void onActivityResumed(Activity activity) {
188 |
189 | }
190 |
191 | @Override
192 | public void onActivityPaused(Activity activity) {
193 |
194 | }
195 |
196 | @Override
197 | public void onActivityStopped(Activity activity) {
198 |
199 | LogWindow logWindow = owf.get();
200 | if (logWindow == null) {
201 | return;
202 | }
203 | if (logWindow.registerLifeCycleInStop) {
204 | Context context = logWindow.context;
205 | WindowManager wm = logWindow.wm;
206 | LogView logView = logWindow.logView;
207 |
208 | if (context == activity) {
209 | if (wm != null && logView != null && activity != null && (
210 | logView.isActivated() || logView.isEnabled()
211 | )) {
212 | wm.removeViewImmediate(logView);
213 | }
214 | }
215 | if (activity != null) {
216 | activity.getApplication().unregisterActivityLifecycleCallbacks(this);
217 | }
218 | }
219 | }
220 |
221 | @Override
222 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
223 |
224 | }
225 |
226 | @Override
227 | public void onActivityDestroyed(Activity activity) {
228 | // LogWindow logWindow = owf.get();
229 | LogWindow logWindow = owf.get();
230 | if (logWindow == null) {
231 | return;
232 | }
233 | Context context = logWindow.context;
234 | WindowManager wm = logWindow.wm;
235 | LogView logView = logWindow.logView;
236 | Boolean registerLifeCycleInStop = logWindow.registerLifeCycleInStop;
237 | if (!registerLifeCycleInStop) {
238 |
239 | if (context == activity) {
240 | if (wm != null && logView != null && activity != null && activity.isFinishing() && (
241 | logView.isActivated() || logView.isEnabled()
242 | )) {
243 | wm.removeViewImmediate(logView);
244 | }
245 | }
246 | if (activity != null) {
247 | activity.getApplication().unregisterActivityLifecycleCallbacks(this);
248 | }
249 | }
250 | }
251 | });
252 | }
253 | logView.setOnKeyListener(new View.OnKeyListener() {
254 | @Override
255 | public boolean onKey(View v, int keyCode, KeyEvent event) {
256 | if (KeyEvent.KEYCODE_BACK == event.getKeyCode() && event.getAction() == KeyEvent.ACTION_UP) {
257 | wm.removeViewImmediate(logView);
258 | }
259 | return false;
260 | }
261 | });
262 | wm.addView(logView, params);
263 |
264 | }
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/adpater/SimpleTextAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.adpater;
5 |
6 | import java.util.List;
7 |
8 | import org.w3c.dom.Text;
9 |
10 | import android.content.Context;
11 | import android.graphics.Color;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.BaseAdapter;
15 | import android.widget.TextView;
16 | import tony.com.logmodel.model.TraceLevel;
17 | import tony.com.logmodel.model.TraceObject;
18 |
19 | /**
20 | * Created by sanyinchen on 15/11/25.
21 | */
22 | public class SimpleTextAdapter extends BaseAdapter {
23 | private List data;
24 | private Context context;
25 |
26 | public SimpleTextAdapter(List data, Context context) {
27 | this.data = data;
28 | this.context = context;
29 | }
30 |
31 | @Override
32 | public int getCount() {
33 | return data.size();
34 | }
35 |
36 | @Override
37 | public Object getItem(int position) {
38 | return data.get(position);
39 | }
40 |
41 | @Override
42 | public long getItemId(int position) {
43 | return position;
44 | }
45 |
46 | @Override
47 | public View getView(int position, View convertView, ViewGroup parent) {
48 | ViewHolder viewHolder;
49 | if (convertView == null) {
50 |
51 | TextView textView = new TextView(context);
52 | textView.setTextColor(Color.WHITE);
53 | convertView = textView;
54 | viewHolder = new ViewHolder();
55 | viewHolder.logview = textView;
56 | convertView.setTag(viewHolder);
57 | } else {
58 | viewHolder = (ViewHolder) convertView.getTag();
59 | }
60 |
61 | // viewHolder.logview.setText(data.get(position).getDate() + " " + data.get(position).getMessage());
62 | TraceObject traceObject = data.get(position);
63 | viewHolder.logview.setText("[" + traceObject.getTraceLevel() + "] " + traceObject.getMessage());
64 | viewHolder.logview.setTextColor(Color.WHITE);
65 | if (traceObject.getMessage().contains("[console]")) {
66 | viewHolder.logview.setTextColor(Color.GREEN);
67 | }
68 | if (traceObject.getTraceLevel() == TraceLevel.ERROR) {
69 | viewHolder.logview.setTextColor(Color.RED);
70 | }
71 |
72 | return convertView;
73 | }
74 |
75 | public static class ViewHolder {
76 | TextView logview;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/control/LogCtrl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.control;
5 |
6 | import java.util.List;
7 |
8 | import android.util.Log;
9 | import android.view.View;
10 | import tony.com.logmodel.LogConfig;
11 | import tony.com.logmodel.LogView;
12 | import tony.com.logmodel.model.LogManager;
13 | import tony.com.logmodel.model.TraceLevel;
14 | import tony.com.logmodel.model.TraceObject;
15 |
16 | /**
17 | * Created by sanyinchen on 15/11/24.
18 | */
19 | public class LogCtrl implements LogManager.Listener {
20 | private static final int MIN_VISIBLE_POSITION_TO_ENABLE_AUTO_SCROLL = 3;
21 | private LogManager logManager;
22 | private LogView logView;
23 | private TraceBuffer traceBuffer;
24 | private boolean isInitalized;
25 |
26 | public LogCtrl(LogManager logManager, LogView logView, LogConfig logConfig) {
27 | this.logManager = logManager;
28 | this.logView = logView;
29 | if (logConfig == null) {
30 | throw new IllegalArgumentException("logConfig must not be null");
31 | }
32 | traceBuffer = new TraceBuffer(logConfig.getMaxNumberOfTracesToShow());
33 | setLogConfig(logConfig);
34 | }
35 |
36 | public void resume() {
37 | if (!isInitalized) {
38 | isInitalized = true;
39 | logManager.registerListener(this);
40 | logManager.startReading();
41 | }
42 | }
43 |
44 | public void pause() {
45 | if (isInitalized) {
46 | isInitalized = false;
47 | logManager.unregisterListener();
48 | logManager.stopReading();
49 | }
50 | }
51 |
52 | public void setLogConfig(LogConfig config) {
53 |
54 | updateBufferConfig(config);
55 | updateLogConfig(config);
56 | }
57 |
58 | private void updateLogConfig(LogConfig logConfig) {
59 | if (logManager != null) {
60 | logManager.setLogConfig(logConfig);
61 | }
62 | }
63 |
64 | private void updateBufferConfig(LogConfig lynxConfig) {
65 | traceBuffer.setBufferSize(lynxConfig.getMaxNumberOfTracesToShow());
66 | refreshTraces();
67 | }
68 |
69 | private void refreshTraces() {
70 | onNewTraces(traceBuffer.getTraces());
71 | }
72 |
73 | @Override
74 | public void onNewTraces(List traces) {
75 | // test codes
76 | // Log.i("srcomp", "bucket size -->" + traces.size());
77 | // for (TraceObject o : traces) {
78 | // Log.i("srcomp", o.toString());
79 | // }
80 | int tracesRemoved = updateTraceBuffer(traces);
81 | List tracesToNotify = getCurrentTraces();
82 | logView.showTraces(tracesToNotify, tracesRemoved);
83 | // Log.d("srcomp", "tracesRemoved-->" + tracesRemoved);
84 | // Log.d("srcomp", "traceBuffer size: " + traceBuffer.getCurrentNumberOfTraces());
85 |
86 | }
87 |
88 | private int updateTraceBuffer(List traces) {
89 | return traceBuffer.add(traces);
90 | }
91 |
92 | public void updateFilter(String filter) {
93 | if (isInitalized) {
94 | LogConfig lynxConfig = logManager.getLogConfig();
95 | lynxConfig.setFilter(filter);
96 | logManager.setLogConfig(lynxConfig);
97 | clearView();
98 | restartLog();
99 | }
100 | }
101 |
102 | private void clearView() {
103 | traceBuffer.clear();
104 | logView.clear();
105 | }
106 |
107 | public List getCurrentTraces() {
108 | return traceBuffer.getTraces();
109 | }
110 |
111 | public void onScrollToPosition(int lastVisiblePositionInTheList) {
112 | if (shouldDisableAutoScroll(lastVisiblePositionInTheList)) {
113 | // Log.d("srcomp","禁止滑动");
114 | logView.disableAutoScroll();
115 | } else {
116 | // Log.d("srcomp","开放滑动");
117 | logView.enableAutoScroll();
118 | }
119 | }
120 |
121 | private boolean shouldDisableAutoScroll(int lastVisiblePosition) {
122 | int positionOffset = traceBuffer.getCurrentNumberOfTraces() - lastVisiblePosition;
123 | return positionOffset >= MIN_VISIBLE_POSITION_TO_ENABLE_AUTO_SCROLL;
124 | }
125 |
126 | public void updateFilterTraceLevel(TraceLevel level) {
127 | if (isInitalized) {
128 | clearView();
129 | LogConfig lynxConfig = logManager.getLogConfig();
130 | lynxConfig.setFilterTraceLevel(level);
131 | logManager.setLogConfig(lynxConfig);
132 | restartLog();
133 | }
134 | }
135 |
136 | private void restartLog() {
137 | logManager.reStart();
138 | }
139 |
140 | public interface View {
141 |
142 | void showTraces(List traces, int removedTraces);
143 |
144 | void clear();
145 |
146 | void disableAutoScroll();
147 |
148 | void enableAutoScroll();
149 |
150 | void agentRefreshAction(android.view.View.OnClickListener onClickListener);
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/control/TraceBuffer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.control;
5 |
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | import tony.com.logmodel.model.TraceObject;
10 |
11 | /**
12 | * Created by sanyinchen on 15/11/24.
13 | */
14 | public class TraceBuffer {
15 |
16 | private int bufferSize;
17 | private final List traces;
18 |
19 | TraceBuffer(int bufferSize) {
20 | this.bufferSize = bufferSize;
21 | traces = new LinkedList();
22 | }
23 |
24 | void setBufferSize(int bufferSize) {
25 | this.bufferSize = bufferSize;
26 | removeExceededTracesIfNeeded();
27 | }
28 |
29 | int add(List traces) {
30 | this.traces.addAll(traces);
31 | return removeExceededTracesIfNeeded();
32 | }
33 |
34 | List getTraces() {
35 | return traces;
36 | }
37 |
38 | public int getCurrentNumberOfTraces() {
39 | return traces.size();
40 | }
41 |
42 | public void clear() {
43 | traces.clear();
44 | }
45 |
46 | private int removeExceededTracesIfNeeded() {
47 | int tracesToDiscard = getNumberOfTracesToDiscard();
48 | if (tracesToDiscard > 0) {
49 | discardTraces(tracesToDiscard);
50 | }
51 | return tracesToDiscard;
52 | }
53 |
54 | private int getNumberOfTracesToDiscard() {
55 | int currentTracesSize = this.traces.size();
56 | int tracesToDiscard = currentTracesSize - bufferSize;
57 | tracesToDiscard = tracesToDiscard < 0 ? 0 : tracesToDiscard;
58 | return tracesToDiscard;
59 | }
60 |
61 | private void discardTraces(int tracesToDiscard) {
62 | for (int i = 0; i < tracesToDiscard; i++) {
63 | traces.remove(0);
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/LogCat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 | import java.io.BufferedReader;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 |
9 | /**
10 | * Created by sanyinchen on 15/11/24.
11 | */
12 | public class LogCat extends Thread {
13 | private Process process;
14 | private BufferedReader bufferedReader;
15 | private LogCatListner logCatListner;
16 | private boolean continueReading = true;
17 |
18 | public void stopReading() {
19 | continueReading = false;
20 | }
21 |
22 | // 设置监听
23 | public void setListener(LogCatListner listener) {
24 | logCatListner = listener;
25 | }
26 |
27 | public LogCatListner getCurrentListener() {
28 | return logCatListner;
29 | }
30 |
31 | private void readLogCat() {
32 | BufferedReader bufferedReader = getBufferedReader();
33 | String trace = null;
34 | try {
35 | trace = bufferedReader.readLine();
36 | while (trace != null && continueReading) {
37 | notifyListener(trace);
38 | trace = bufferedReader.readLine();
39 | }
40 |
41 | } catch (IOException e) {
42 | e.printStackTrace();
43 | }
44 |
45 | }
46 |
47 | private BufferedReader getBufferedReader() {
48 | if (bufferedReader == null && process != null) {
49 | bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
50 | }
51 | return bufferedReader;
52 | }
53 |
54 | private void notifyListener(String trace) {
55 | if (logCatListner != null) {
56 | // Log.d("srcomp", "底层trace分发-----" + trace);
57 | // System.out.println("-----------trace:" + trace+"--------------");
58 | logCatListner.onTraceRead(trace);
59 | }
60 | }
61 |
62 | // 主要执行操作
63 | @Override
64 | public void run() {
65 | super.run();
66 | try {
67 | process = Runtime.getRuntime().exec("logcat -v time");
68 | } catch (IOException e) {
69 | e.printStackTrace();
70 | }
71 | readLogCat();
72 | }
73 |
74 | // 回调
75 | public interface LogCatListner {
76 | void onTraceRead(String traceMsg);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/LogMainThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 |
6 | import android.os.Handler;
7 | import android.os.Looper;
8 |
9 | /**
10 | * Created by sanyinchen on 15/11/24.
11 | */
12 | public class LogMainThread implements MainThread {
13 | private final Handler handler;
14 |
15 | public LogMainThread() {
16 | this.handler = new Handler(Looper.getMainLooper());
17 | }
18 |
19 | @Override
20 | public void post(Runnable runnable) {
21 | handler.post(runnable);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/LogManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 |
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | import android.util.Log;
10 | import tony.com.logmodel.LogConfig;
11 |
12 | /**
13 | * Created by sanyinchen on 15/11/24.
14 | */
15 | public class LogManager {
16 | private LogCat logCat;
17 | private MainThread mainThread;
18 | private List tracesBuffer;
19 | private Listener listener;
20 | private LogConfig logConfig = new LogConfig();
21 | private long lastNotification;
22 |
23 | public LogManager(LogCat logCat, MainThread mainThread) {
24 | this.logCat = logCat;
25 | this.mainThread = mainThread;
26 | tracesBuffer = new LinkedList<>();
27 | }
28 |
29 | public void startReading() {
30 | logCat.setListener(new LogCat.LogCatListner() {
31 | @Override
32 | public void onTraceRead(String traceMsg) {
33 | // Log.d("srcomp", "startReading -----");
34 | addTraceToBuffer(traceMsg);
35 | notifyNewTraces();
36 | }
37 | });
38 | if (logCat.getState().equals(Thread.State.NEW)) {
39 | Log.d("srcomp", "logCatThread start-----");
40 | logCat.start();
41 | }
42 | }
43 |
44 | public void reStart() {
45 | LogCat.LogCatListner logCatListner = logCat.getCurrentListener();
46 | if (logCatListner == null) {
47 | logCatListner = new LogCat.LogCatListner() {
48 | @Override
49 | public void onTraceRead(String traceMsg) {
50 | addTraceToBuffer(traceMsg);
51 | }
52 | };
53 | }
54 | lastNotification = 0;
55 | if (tracesBuffer != null) {
56 | tracesBuffer.clear();
57 | } else {
58 | tracesBuffer = new LinkedList<>();
59 | }
60 | if (logCat != null || logCat.isAlive()) {
61 | logCat.stopReading();
62 | logCat.interrupt();
63 | logCat = null;
64 | }
65 | logCat = new LogCat();
66 | logCat.setListener(logCatListner);
67 | logCat.start();
68 | }
69 |
70 | public void stopReading() {
71 | logCat.stopReading();
72 | logCat.interrupt();
73 | }
74 |
75 | private synchronized void addTraceToBuffer(String trace) {
76 | if (shouldAddTrace(trace)) {
77 | //Log.d("srcomp", "addTraceToBuffer -----" + trace);
78 | TraceObject traceObject = null;
79 | try {
80 | traceObject = TraceObject.fromString(trace);
81 | } catch (Exception e) {
82 | e.printStackTrace();
83 | }
84 | if (traceObject != null) {
85 | if (!tracesBuffer.contains(traceObject)) {
86 | tracesBuffer.add(traceObject);
87 | }
88 | } else {
89 | Log.e("srcomp", "error type trace");
90 | }
91 | } else {
92 | // Log.e("srcomp", "shouldAddTrace failure");
93 | }
94 |
95 | }
96 |
97 | private boolean shouldAddTrace(String trace) {
98 | boolean hasFilterConfigured = logConfig.hasFilter();
99 | return !hasFilterConfigured || traceMatchesFilter(trace);
100 | }
101 |
102 | private synchronized boolean traceMatchesFilter(String logcatTrace) {
103 | TraceLevel levelFilter = logConfig.getFilterTraceLevel();
104 | String filter = logConfig.getFilter().toLowerCase();
105 | String logcatTraceLowercase = logcatTrace.toLowerCase();
106 | return logcatTraceLowercase.contains(filter) && containsTraceLevel(logcatTrace, levelFilter);
107 | }
108 |
109 | private boolean containsTraceLevel(String logcatTrace, TraceLevel levelFilter) {
110 | return levelFilter.equals(TraceLevel.VERBOSE) || hasTraceLevelEqualOrHigher(logcatTrace,
111 | levelFilter);
112 | }
113 |
114 | private boolean hasTraceLevelEqualOrHigher(String logcatTrace, TraceLevel levelFilter) {
115 | TraceLevel level = TraceLevel.getTraceLevel(logcatTrace.charAt(TraceObject.TRACE_LEVEL_INDEX));
116 | return level.ordinal() >= levelFilter.ordinal();
117 | }
118 |
119 | private boolean shouldNotifyListeners() {
120 | long now = System.currentTimeMillis();
121 | long timeFromLastNotification = now - lastNotification;
122 | boolean hasTracesToNotify = tracesBuffer.size() > 0;
123 | return timeFromLastNotification > logConfig.getSamplingRate() && hasTracesToNotify;
124 | }
125 |
126 | private void notifyNewTraces() {
127 | if (shouldNotifyListeners()) {
128 | final List traces = new LinkedList<>(tracesBuffer);
129 | tracesBuffer.clear();
130 | finalNotification(traces);
131 | }
132 | }
133 |
134 | private synchronized void finalNotification(final List tracesBuffer) {
135 | mainThread.post(new Runnable() {
136 | @Override
137 | public void run() {
138 | if (listener != null) {
139 | listener.onNewTraces(tracesBuffer);
140 | lastNotification = System.currentTimeMillis();
141 | }
142 | }
143 | });
144 |
145 | }
146 |
147 | public void registerListener(Listener listener) {
148 | this.listener = listener;
149 | }
150 |
151 | public void unregisterListener() {
152 | this.listener = null;
153 | }
154 |
155 | public LogConfig getLogConfig() {
156 | return logConfig;
157 | }
158 |
159 | public void setLogConfig(LogConfig logConfig) {
160 | this.logConfig = logConfig;
161 | }
162 |
163 | public interface Listener {
164 | void onNewTraces(List traces);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/MainThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 |
6 | /**
7 | * Created by sanyinchen on 15/11/24.
8 | */
9 | public interface MainThread {
10 | void post(Runnable runnable);
11 | }
12 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/TraceLevel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 |
6 | /**
7 | * Created by sanyinchen on 15/11/24.
8 | */
9 | public enum TraceLevel {
10 | VERBOSE("V"), JS("J"), DEBUG("D"), INFO("I"), WARNING("W"), ERROR("E"), ASSERT("A"), WTF("F");
11 |
12 | private final String value;
13 |
14 | TraceLevel(String value) {
15 | this.value = value;
16 | }
17 |
18 | public String getValue() {
19 | return value;
20 | }
21 |
22 | public static TraceLevel getTraceLevel(char traceString) {
23 | TraceLevel traceLevel;
24 | switch (traceString) {
25 | case 'J':
26 | traceLevel = TraceLevel.JS;
27 | break;
28 | case 'V':
29 | traceLevel = TraceLevel.VERBOSE;
30 | break;
31 | case 'A':
32 | traceLevel = TraceLevel.ASSERT;
33 | break;
34 | case 'I':
35 | traceLevel = TraceLevel.INFO;
36 | break;
37 | case 'W':
38 | traceLevel = TraceLevel.WARNING;
39 | break;
40 | case 'E':
41 | traceLevel = TraceLevel.ERROR;
42 | break;
43 | case 'F':
44 | traceLevel = TraceLevel.WTF;
45 | break;
46 | default:
47 | traceLevel = TraceLevel.DEBUG;
48 | }
49 | return traceLevel;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/logmodel/src/main/java/tony/com/logmodel/model/TraceObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | package tony.com.logmodel.model;
5 |
6 | /**
7 | * Created by sanyinchen on 15/11/24.
8 | */
9 | public class TraceObject {
10 | private static final char TRACE_LEVEL_SEPARATOR = '/';
11 | private static final int END_OF_DATE_INDEX = 18;
12 | private static final int START_OF_MESSAGE_INDEX = 21;
13 | public static final int MIN_TRACE_SIZE = 21;
14 | public static final int TRACE_LEVEL_INDEX = 19;
15 |
16 | private TraceLevel traceLevel;
17 | private String message;
18 | private String date;
19 |
20 | public TraceObject(TraceLevel traceLevel, String message, String date) {
21 | this.traceLevel = traceLevel;
22 | this.message = message;
23 | this.date = date;
24 | }
25 |
26 | public String getDate() {
27 | return date;
28 | }
29 |
30 | public void setDate(String date) {
31 | this.date = date;
32 | }
33 |
34 | // egc "02-07 17:45:33.014 D/Any debug trace"
35 | public static TraceObject fromString(String locatTrace) throws Exception {
36 | if (locatTrace == null || locatTrace.length() < MIN_TRACE_SIZE
37 | || locatTrace.charAt(20) != TRACE_LEVEL_SEPARATOR) {
38 | // throw new Exception("Consturctor traceobject Error");
39 | return null;
40 | } else {
41 | TraceLevel level = TraceLevel.getTraceLevel(locatTrace.charAt(TRACE_LEVEL_INDEX));
42 | String date = locatTrace.substring(0, END_OF_DATE_INDEX);
43 | String message = locatTrace.substring(START_OF_MESSAGE_INDEX, locatTrace.length());
44 | return new TraceObject(level, message, date);
45 | }
46 | }
47 |
48 | public TraceLevel getTraceLevel() {
49 | return this.traceLevel;
50 | }
51 |
52 | public String getMessage() {
53 | return this.message;
54 | }
55 |
56 | @Override
57 | public boolean equals(Object o) {
58 | if (this == o) {
59 | return true;
60 | }
61 | if (!(o instanceof TraceObject)) {
62 |
63 | return false;
64 | }
65 | TraceObject traceObject = (TraceObject) o;
66 | return traceObject.getMessage().equals(message) && traceObject.getTraceLevel() == traceLevel || traceObject
67 | .getDate().equals(getDate()) || message.contains(((TraceObject) o).getMessage()) || extraCompare(message);
68 | }
69 |
70 | protected boolean extraCompare(String trace) {
71 | String[] tests = trace.split("Trace\\{");
72 | if (tests.length > 1) {
73 | return true;
74 | }
75 | return false;
76 | }
77 |
78 | @Override
79 | public int hashCode() {
80 | int result = traceLevel.hashCode();
81 | result = 31 * result + message.hashCode() + date.hashCode();
82 | return result;
83 | }
84 |
85 | @Override
86 | public String toString() {
87 | return "Trace{" + "'level=" + traceLevel + ", message='" + message + '\'' + '}';
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/logmodel/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 | LogModel
6 |
7 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Apache licence, Inc. All Rights Reserved.
3 | */
4 | include ':app', ':logmodel'
5 |
--------------------------------------------------------------------------------
/source/instance1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/source/instance1.gif
--------------------------------------------------------------------------------
/source/instance2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyinchen/LogView/c83097ac0cbc44b88ef84c24d5bd593c10861049/source/instance2.gif
--------------------------------------------------------------------------------