├── niddler-java ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── chimerapps │ └── niddler │ ├── core │ └── JavaNiddler.java │ └── utils │ └── JavaLogUtil.java ├── niddler-noop ├── .gitignore ├── proguard-rules.txt ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── chimerapps │ │ └── niddler │ │ └── core │ │ └── AndroidNiddler.java └── build.gradle ├── niddler-example-java ├── .gitignore ├── src │ └── main │ │ ├── resources │ │ └── logging.properties │ │ └── kotlin │ │ └── com │ │ └── chimerapps │ │ └── niddler │ │ └── example │ │ └── main.kt └── build.gradle ├── niddler-java-noop ├── .gitignore ├── src │ └── main │ │ └── java │ │ └── com │ │ └── chimerapps │ │ └── niddler │ │ └── core │ │ └── JavaNiddler.java └── build.gradle ├── niddler-noop-base ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── chimerapps │ └── niddler │ ├── core │ ├── NiddlerRequest.java │ ├── NiddlerMessageBase.java │ ├── FakeNiddlerDebugger.java │ ├── NiddlerResponse.java │ ├── debug │ │ └── NiddlerDebugger.java │ └── Niddler.java │ ├── retrofit │ └── NiddlerRetrofitCallInjector.java │ └── interceptor │ └── okhttp │ └── NiddlerOkHttpInterceptor.java ├── niddler-example-android ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ └── styles.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ └── layout │ │ │ └── activity_main.xml │ │ ├── assets │ │ └── image.jpeg │ │ ├── java │ │ └── com │ │ │ └── chimerapps │ │ │ └── sampleapplication │ │ │ ├── api │ │ │ ├── Post.kt │ │ │ ├── ExampleXMLApi.kt │ │ │ ├── TimeoutApi.kt │ │ │ └── ExampleJsonApi.kt │ │ │ ├── NiddlerSampleApplication.kt │ │ │ └── activity │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml └── build.gradle ├── constants.gradle ├── gradle.properties ├── niddler ├── proguard-rules.txt ├── src │ └── main │ │ ├── res │ │ └── values │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── chimerapps │ │ └── niddler │ │ ├── service │ │ ├── MarshmallowCompatHelper.java │ │ ├── KitkatCompatHelper.java │ │ ├── JellyBeanCompatHelper.java │ │ ├── OreoCompatHelper.java │ │ └── NiddlerService.java │ │ ├── util │ │ └── AndroidLogUtil.java │ │ └── core │ │ ├── NiddlerServiceLifeCycleWatcher.java │ │ └── AndroidNiddler.java └── build.gradle ├── niddler_logo.png ├── .github └── FUNDING.yml ├── examplekeystore.keystore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── niddler-urlconnection ├── README.md ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── chimerapps │ └── niddler │ └── urlconnection │ ├── URLStreamHandlerHelper.java │ ├── DelayedHttpUrlConnection.java │ ├── NiddlerUrlConnectionRequest.java │ ├── NiddlerUrlConnectionResponse.java │ ├── DelegatingHttpsUrlConnection.java │ └── NiddlerUrlConnectionHandler.java ├── niddler-base ├── src │ └── main │ │ └── java │ │ └── com │ │ └── chimerapps │ │ └── niddler │ │ ├── core │ │ ├── MessageParser.java │ │ ├── NiddlerRequest.java │ │ ├── MessagesCache.java │ │ ├── NiddlerMessageBase.java │ │ ├── NiddlerResponse.java │ │ ├── ServerAuth.java │ │ ├── ServerConnection.java │ │ ├── NiddlerImpl.java │ │ ├── debug │ │ │ └── NiddlerDebugger.java │ │ ├── MessageBuilder.java │ │ └── NiddlerServer.java │ │ ├── util │ │ ├── StringUtil.java │ │ ├── LogUtil.java │ │ ├── ConditionVariable.java │ │ └── Base64.java │ │ ├── retrofit │ │ └── NiddlerRetrofitCallInjector.java │ │ └── interceptor │ │ └── okhttp │ │ ├── NiddlerOkHttpErrorResponse.java │ │ ├── NiddlerOkHttpRequest.java │ │ └── NiddlerOkHttpResponse.java └── build.gradle ├── publishLocal.sh ├── publish.sh ├── RELEASENOTES.md ├── gradlew.bat ├── scripts ├── publish-mavencentral.gradle └── publish-mavencentral-android.gradle ├── .gitignore ├── gradlew └── README.md /niddler-java/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /niddler-noop/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /niddler-example-java/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /niddler-java-noop/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /niddler-noop-base/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /niddler-example-android/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /constants.gradle: -------------------------------------------------------------------------------- 1 | project.ext { 2 | releaseVersion = '1.7.0' 3 | } 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true -------------------------------------------------------------------------------- /niddler/proguard-rules.txt: -------------------------------------------------------------------------------- 1 | -assumenosideeffects class com.chimerapps.niddler.** -------------------------------------------------------------------------------- /niddler-noop/proguard-rules.txt: -------------------------------------------------------------------------------- 1 | -assumenosideeffects class com.chimerapps.niddler.** -------------------------------------------------------------------------------- /niddler_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler_logo.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: NicolaVerbeeck 4 | -------------------------------------------------------------------------------- /examplekeystore.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/examplekeystore.keystore -------------------------------------------------------------------------------- /niddler-noop/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SampleApplication 3 | 4 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/assets/image.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/assets/image.jpeg -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chimerapps/niddler/HEAD/niddler-example-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':niddler-base', ':niddler-java', ':niddler-java-noop', ':niddler-noop-base', ':niddler', ':niddler-noop', ':niddler-example-java' 2 | include ':niddler-example-android', ':niddler-urlconnection' 3 | 4 | rootProject.name = 'niddler' -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 18 11:13:56 CEST 2020 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-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /niddler/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Niddler is running for \'%1$s\' on port \'%2$d\'. Touch to stop 5 | Niddler is running. Touch to stop. 6 | 7 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/java/com/chimerapps/sampleapplication/api/Post.kt: -------------------------------------------------------------------------------- 1 | package com.icapps.sampleapplication.api 2 | 3 | /** 4 | * Created by maartenvangiel on 14/11/2016. 5 | */ 6 | class Post { 7 | var userId: Int = 0 8 | var id: Int = 0 9 | var title: String? = null 10 | var body: String? = null 11 | } 12 | -------------------------------------------------------------------------------- /niddler-example-java/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | handlers=java.util.logging.ConsoleHandler 2 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 3 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] (%2$s) %5$s %6$s%n 4 | java.util.logging.ConsoleHandler.level=INFO 5 | .level=INFO -------------------------------------------------------------------------------- /niddler/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /niddler-urlconnection/README.md: -------------------------------------------------------------------------------- 1 | #niddler-urlconnection 2 | Helper library that allows inspection (no debugging support yet) of http(s) requests sent using `URL.openConnection(...)`. Note that this library is experimental at this stage 3 | 4 | ## Example use 5 | ```java 6 | NiddlerUrlConnectionHandler handler = NiddlerUrlConnectionHandler.install(niddler); 7 | handler.blacklist(".*raw\\.githubusercontent\\.com.*"); 8 | ``` -------------------------------------------------------------------------------- /niddler-example-android/src/main/java/com/chimerapps/sampleapplication/api/ExampleXMLApi.kt: -------------------------------------------------------------------------------- 1 | package com.icapps.sampleapplication.api 2 | 3 | import okhttp3.ResponseBody 4 | import retrofit2.Call 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * Created by maartenvangiel on 14/11/2016. 9 | */ 10 | interface ExampleXMLApi { 11 | 12 | @get:GET("/bcantoni/yql/master/lorem.ipsum.xml") 13 | val menu: Call 14 | 15 | } 16 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/MessageParser.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import org.json.JSONObject; 4 | 5 | /** 6 | * @author Nicola Verbeeck 7 | * Date 22/11/16. 8 | */ 9 | final class MessageParser { 10 | 11 | private MessageParser() { 12 | //Utility class 13 | } 14 | 15 | static ServerAuth.AuthReply parseAuthReply(final JSONObject jsonObject) { 16 | return new ServerAuth.AuthReply(jsonObject.optString("hashKey")); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /publishLocal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./gradlew clean --no-daemon 3 | ./gradlew \ 4 | :niddler:publishReleasePublicationToMavenLocal \ 5 | :niddler-base:publishReleasePublicationToMavenLocal \ 6 | :niddler-java:publishReleasePublicationToMavenLocal \ 7 | :niddler-java-noop:publishReleasePublicationToMavenLocal \ 8 | :niddler-noop:publishReleasePublicationToMavenLocal \ 9 | :niddler-noop-base:publishReleasePublicationToMavenLocal \ 10 | :niddler-urlconnection:publishReleasePublicationToMavenLocal \ 11 | --no-daemon -------------------------------------------------------------------------------- /niddler-example-android/src/main/java/com/chimerapps/sampleapplication/api/TimeoutApi.kt: -------------------------------------------------------------------------------- 1 | package com.icapps.sampleapplication.api 2 | 3 | import okhttp3.ResponseBody 4 | import retrofit2.Call 5 | import retrofit2.http.GET 6 | 7 | /** 8 | * @author Nicola Verbeeck 9 | */ 10 | interface TimeoutApi { 11 | @GET("/200") 12 | fun getOk(): Call 13 | 14 | @GET("/404") 15 | fun getNotFound(): Call 16 | 17 | @GET("/200?sleep=6000") 18 | fun getOkTimeout(): Call 19 | } -------------------------------------------------------------------------------- /niddler/src/main/java/com/chimerapps/niddler/service/MarshmallowCompatHelper.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.service; 2 | 3 | import android.app.PendingIntent; 4 | import android.os.Build; 5 | 6 | /** 7 | * @author Nicola Verbeeck 8 | */ 9 | final class MarshmallowCompatHelper { 10 | 11 | static int getPendingIntentFlags() { 12 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 13 | return PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE; 14 | } 15 | return PendingIntent.FLAG_CANCEL_CURRENT; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./gradlew clean --no-daemon 3 | ./gradlew \ 4 | :niddler:publishReleasePublicationToSonatypeRepository \ 5 | :niddler-base:publishReleasePublicationToSonatypeRepository \ 6 | :niddler-java:publishReleasePublicationToSonatypeRepository \ 7 | :niddler-java-noop:publishReleasePublicationToSonatypeRepository \ 8 | :niddler-noop:publishReleasePublicationToSonatypeRepository \ 9 | :niddler-noop-base:publishReleasePublicationToSonatypeRepository \ 10 | :niddler-urlconnection:publishReleasePublicationToSonatypeRepository \ 11 | --no-daemon 12 | -------------------------------------------------------------------------------- /niddler/src/main/java/com/chimerapps/niddler/service/KitkatCompatHelper.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.service; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Notification; 5 | import android.os.Build; 6 | import androidx.annotation.NonNull; 7 | 8 | /** 9 | * @author Nicola Verbeeck 10 | * @version 1 11 | */ 12 | @TargetApi(Build.VERSION_CODES.KITKAT_WATCH) 13 | class KitkatCompatHelper { 14 | 15 | static void setLocalOnly(@NonNull final Notification.Builder builder, final boolean localOnly) { 16 | builder.setLocalOnly(localOnly); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /niddler-java-noop/src/main/java/com/chimerapps/niddler/core/JavaNiddler.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | /** 4 | * @author Nicola Verbeeck 5 | * @version 1 6 | */ 7 | public final class JavaNiddler extends Niddler implements Niddler.PlatformNiddler { 8 | 9 | private JavaNiddler() { 10 | super(); 11 | } 12 | 13 | @Override 14 | public void closePlatform() { 15 | } 16 | 17 | public static class Builder extends Niddler.Builder { 18 | 19 | public Builder() { 20 | } 21 | 22 | @Override 23 | public JavaNiddler build() { 24 | return new JavaNiddler(); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /niddler-java-noop/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | } 7 | apply from: '../constants.gradle' 8 | 9 | apply plugin: 'java-library' 10 | 11 | sourceCompatibility = "1.7" 12 | targetCompatibility = "1.7" 13 | 14 | dependencies { 15 | api project(':niddler-noop-base') 16 | } 17 | 18 | ext { 19 | artifactVersion = project.ext.releaseVersion 20 | artifactName = 'niddler-java-noop' 21 | artifactGroup = 'com.chimerapps.niddler' 22 | artifactDescription = 'Niddler network inspector java no-op library' 23 | } 24 | 25 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle" -------------------------------------------------------------------------------- /niddler-java/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | mavenCentral() 5 | jcenter() 6 | 7 | } 8 | } 9 | apply from: '../constants.gradle' 10 | 11 | apply plugin: 'java-library' 12 | 13 | sourceCompatibility = 1.7 14 | targetCompatibility = 1.7 15 | 16 | dependencies { 17 | implementation "org.json:json:20080701" 18 | api project(':niddler-base') 19 | } 20 | 21 | ext { 22 | artifactVersion = project.ext.releaseVersion 23 | artifactName = 'niddler-java' 24 | artifactGroup = 'com.chimerapps.niddler' 25 | artifactDescription = 'Niddler network inspector java library' 26 | } 27 | 28 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle" -------------------------------------------------------------------------------- /niddler-urlconnection/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | mavenCentral() 5 | 6 | } 7 | } 8 | apply from: '../constants.gradle' 9 | 10 | apply plugin: 'java-library' 11 | 12 | sourceCompatibility = 1.7 13 | targetCompatibility = 1.7 14 | 15 | dependencies { 16 | api project(':niddler-base') 17 | compileOnly 'androidx.annotation:annotation:1.1.0' 18 | } 19 | 20 | ext { 21 | artifactVersion = project.ext.releaseVersion 22 | artifactName = 'niddler-urlconnection' 23 | artifactGroup = 'com.chimerapps.niddler' 24 | artifactDescription = 'Niddler network inspector urlconnection bindings' 25 | } 26 | 27 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle" 28 | -------------------------------------------------------------------------------- /niddler-noop-base/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | } 7 | 8 | apply from: '../constants.gradle' 9 | 10 | apply plugin: 'java' 11 | 12 | dependencies { 13 | compileOnly 'androidx.annotation:annotation:1.1.0' 14 | compileOnly 'com.squareup.okhttp3:okhttp:3.11.0' 15 | compileOnly 'com.squareup.retrofit2:retrofit:2.5.0' 16 | } 17 | 18 | sourceCompatibility = "1.7" 19 | targetCompatibility = "1.7" 20 | 21 | ext { 22 | artifactVersion = project.ext.releaseVersion 23 | artifactName = 'niddler-noop-base' 24 | artifactGroup = 'com.chimerapps.niddler' 25 | artifactDescription = 'Niddler network inspector base no-op library' 26 | } 27 | 28 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle" -------------------------------------------------------------------------------- /niddler-example-android/src/main/java/com/chimerapps/sampleapplication/api/ExampleJsonApi.kt: -------------------------------------------------------------------------------- 1 | package com.icapps.sampleapplication.api 2 | 3 | import okhttp3.MultipartBody 4 | import okhttp3.ResponseBody 5 | import retrofit2.Call 6 | import retrofit2.http.GET 7 | import retrofit2.http.Multipart 8 | import retrofit2.http.POST 9 | import retrofit2.http.Part 10 | import retrofit2.http.Path 11 | 12 | /** 13 | * Created by maartenvangiel on 14/11/2016. 14 | */ 15 | interface ExampleJsonApi { 16 | 17 | @get:GET("/posts") 18 | val posts: Call> 19 | 20 | @GET("/posts/{id}") 21 | fun getPost(@Path("id") id: Int): Call 22 | 23 | @Multipart 24 | @POST("/posts") 25 | fun createPost(@Part message: MultipartBody.Part, @Part attachment: MultipartBody.Part): Call 26 | 27 | } 28 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.util; 2 | 3 | import androidx.annotation.Nullable; 4 | import androidx.annotation.RestrictTo; 5 | 6 | 7 | /** 8 | * @author Nicola Verbeeck 9 | */ 10 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 11 | public final class StringUtil { 12 | 13 | private StringUtil() { 14 | // Utility class 15 | } 16 | 17 | public static long calculateMemoryUsage(final String input) { 18 | return 8 * (((input.length()) * 2) + 45) / 8; 19 | } 20 | 21 | public static boolean isEmpty(@Nullable final CharSequence str) { 22 | return str == null || str.length() == 0; 23 | } 24 | 25 | public static byte[] fromBase64(final String body) { 26 | return Base64.decode(body); 27 | } 28 | 29 | public static String toString(byte[] data) { 30 | return Base64.encodeUrl(data); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /niddler/src/main/java/com/chimerapps/niddler/service/JellyBeanCompatHelper.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.service; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Notification; 5 | import android.os.Build; 6 | import androidx.annotation.NonNull; 7 | 8 | /** 9 | * @author Nicola Verbeeck 10 | * @version 1 11 | */ 12 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 13 | final class JellyBeanCompatHelper { 14 | 15 | static void addBigText(@NonNull final Notification.Builder builder, @NonNull final String text) { 16 | builder.setStyle(new Notification.BigTextStyle().bigText(text)); 17 | } 18 | 19 | @NonNull 20 | static Notification build(@NonNull final Notification.Builder builder) { 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 22 | return builder.build(); 23 | } 24 | //noinspection deprecation 25 | return builder.getNotification(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/NiddlerRequest.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import java.util.List; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | 8 | /** 9 | * @author Nicola Verbeeck 10 | * Date 10/11/16. 11 | */ 12 | public interface NiddlerRequest extends NiddlerMessageBase { 13 | 14 | /** 15 | * @return The logical URL of this request 16 | */ 17 | @NonNull 18 | String getUrl(); 19 | 20 | /** 21 | * @return The logical method of this request. 22 | */ 23 | @NonNull 24 | String getMethod(); 25 | 26 | /** 27 | * @return Associated request-site stack trace if available/configured 28 | */ 29 | @Nullable 30 | StackTraceElement[] getRequestStackTrace(); 31 | 32 | /** 33 | * @return Optional request context to display in the UI 34 | */ 35 | @Nullable 36 | List getRequestContext(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/core/NiddlerRequest.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author Nicola Verbeeck 10 | * Date 10/11/16. 11 | */ 12 | public interface NiddlerRequest extends NiddlerMessageBase { 13 | 14 | /** 15 | * @return The logical URL of this request 16 | */ 17 | @NonNull 18 | String getUrl(); 19 | 20 | /** 21 | * @return The logical method of this request. 22 | */ 23 | @NonNull 24 | String getMethod(); 25 | 26 | /** 27 | * @return Associated request-site stack trace if available/configured 28 | */ 29 | @Nullable 30 | StackTraceElement[] getRequestStackTrace(); 31 | 32 | /** 33 | * @return Optional request context to display in the UI 34 | */ 35 | @Nullable 36 | List getRequestContext(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /niddler/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: '../constants.gradle' 2 | 3 | apply plugin: 'com.android.library' 4 | 5 | sourceCompatibility = 1.7 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | android { 12 | compileSdkVersion 28 13 | buildToolsVersion "28.0.3" 14 | 15 | defaultConfig { 16 | consumerProguardFiles 'proguard-rules.txt' 17 | minSdkVersion 14 18 | } 19 | } 20 | 21 | dependencies { 22 | api project(':niddler-base') 23 | compileOnly 'androidx.annotation:annotation:1.1.0' 24 | } 25 | 26 | ext { 27 | artifactVersion = project.ext.releaseVersion 28 | artifactName = 'niddler' 29 | artifactGroup = 'com.chimerapps.niddler' 30 | artifactDescription = 'Niddler network inspector library for android' 31 | } 32 | 33 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral-android.gradle" 34 | 35 | signReleasePublication { 36 | dependsOn assemble 37 | } -------------------------------------------------------------------------------- /niddler-noop/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply from: '../constants.gradle' 3 | 4 | apply plugin: 'com.android.library' 5 | 6 | dependencies { 7 | api project(':niddler-noop-base') 8 | compileOnly 'androidx.annotation:annotation:1.1.0' 9 | } 10 | 11 | sourceCompatibility = "1.7" 12 | targetCompatibility = "1.7" 13 | 14 | android { 15 | compileSdkVersion 28 16 | buildToolsVersion '28.0.3' 17 | 18 | defaultConfig { 19 | consumerProguardFiles 'proguard-rules.txt' 20 | minSdkVersion 14 21 | } 22 | } 23 | 24 | ext { 25 | artifactVersion = project.ext.releaseVersion 26 | artifactName = 'niddler-noop' 27 | artifactGroup = 'com.chimerapps.niddler' 28 | artifactDescription = 'Niddler network inspector library for android - noop version' 29 | } 30 | 31 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral-android.gradle" 32 | 33 | signReleasePublication { 34 | dependsOn assemble 35 | } -------------------------------------------------------------------------------- /niddler-urlconnection/src/main/java/com/chimerapps/niddler/urlconnection/URLStreamHandlerHelper.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.urlconnection; 2 | 3 | import java.io.IOException; 4 | import java.net.HttpURLConnection; 5 | import java.net.Proxy; 6 | import java.net.URL; 7 | import java.net.URLStreamHandler; 8 | 9 | import androidx.annotation.NonNull; 10 | 11 | /** 12 | * @author Nicola Verbeeck 13 | */ 14 | final class URLStreamHandlerHelper { 15 | 16 | public static HttpURLConnection openConnection(@NonNull final URLStreamHandler handler, @NonNull final URL url) throws IOException { 17 | return (HttpURLConnection) new URL(null, url.toString(), handler).openConnection(); 18 | } 19 | 20 | public static HttpURLConnection openConnection(@NonNull final URLStreamHandler handler, @NonNull final URL url, @NonNull final Proxy proxy) throws IOException { 21 | return (HttpURLConnection) new URL(null, url.toString(), handler).openConnection(proxy); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /niddler-base/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | } 7 | 8 | apply from: '../constants.gradle' 9 | 10 | apply plugin: 'java-library' 11 | 12 | sourceCompatibility = 1.7 13 | targetCompatibility = 1.7 14 | 15 | repositories { 16 | google() 17 | mavenCentral() 18 | jcenter() 19 | } 20 | 21 | dependencies { 22 | implementation 'org.java-websocket:Java-WebSocket:1.4.1' 23 | 24 | compileOnly 'com.squareup.okhttp3:okhttp:3.11.0' 25 | compileOnly 'com.squareup.retrofit2:retrofit:2.5.0' 26 | compileOnly 'androidx.annotation:annotation:1.1.0' 27 | compileOnly 'org.json:json:20080701' 28 | } 29 | 30 | ext { 31 | artifactVersion = project.ext.releaseVersion 32 | artifactName = 'niddler-base' 33 | artifactGroup = 'com.chimerapps.niddler' 34 | artifactDescription = 'Niddler network inspector base library' 35 | } 36 | 37 | apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle" 38 | -------------------------------------------------------------------------------- /niddler-example-java/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.71' 3 | repositories { 4 | mavenCentral() 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 9 | classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0' 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'kotlin' 15 | apply plugin: 'application' 16 | apply plugin: 'com.github.johnrengelman.shadow' 17 | 18 | mainClassName = "com.chimerapps.niddler.example.MainKt" 19 | 20 | repositories { 21 | mavenCentral() 22 | } 23 | 24 | compileKotlin { 25 | kotlinOptions { 26 | jvmTarget = "1.8" 27 | } 28 | } 29 | compileTestKotlin { 30 | kotlinOptions { 31 | jvmTarget = "1.8" 32 | } 33 | } 34 | 35 | dependencies { 36 | implementation project(':niddler-java') 37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 38 | implementation 'com.squareup.okhttp3:okhttp:3.11.0' 39 | } -------------------------------------------------------------------------------- /niddler-java/src/main/java/com/chimerapps/niddler/core/JavaNiddler.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import com.chimerapps.niddler.util.LogUtil; 4 | import com.chimerapps.niddler.utils.JavaLogUtil; 5 | 6 | /** 7 | * @author Nicola Verbeeck 8 | * @version 1 9 | */ 10 | public class JavaNiddler extends Niddler implements Niddler.PlatformNiddler { 11 | 12 | JavaNiddler(final String password, final int port, final long cacheSize, 13 | final NiddlerServerInfo niddlerServerInfo, final int maxStackTraceSize) { 14 | super(password, port, cacheSize, niddlerServerInfo, maxStackTraceSize, -1); 15 | mNiddlerImpl.setPlatform(this); 16 | } 17 | 18 | @Override 19 | public void closePlatform() { 20 | } 21 | 22 | public static class Builder extends Niddler.Builder { 23 | 24 | public Builder() { 25 | LogUtil.instance = new JavaLogUtil(); 26 | } 27 | 28 | @Override 29 | public JavaNiddler build() { 30 | return new JavaNiddler(mPassword, mPort, mCacheSize, mNiddlerServerInfo, mMaxStackTraceSize); 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /niddler/src/main/java/com/chimerapps/niddler/util/AndroidLogUtil.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.util; 2 | 3 | import androidx.annotation.RestrictTo; 4 | import android.util.Log; 5 | 6 | /** 7 | * @author Nicola Verbeeck 8 | * @version 1 9 | */ 10 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 11 | public class AndroidLogUtil extends LogUtil { 12 | 13 | @Override 14 | protected void doLog(final int level, final String tag, final String message, final Throwable error) { 15 | switch (level) { 16 | case VERBOSE: 17 | Log.v(tag, message, error); 18 | break; 19 | case DEBUG: 20 | Log.d(tag, message, error); 21 | break; 22 | case INFO: 23 | Log.i(tag, message, error); 24 | break; 25 | case WARN: 26 | Log.w(tag, message, error); 27 | break; 28 | case ERROR: 29 | Log.e(tag, message, error); 30 | break; 31 | } 32 | } 33 | 34 | @Override 35 | protected boolean doIsLoggable(final String tag, final int level) { 36 | return Log.isLoggable(tag, level); 37 | } 38 | 39 | @Override 40 | protected void doLogStartup(String message) { 41 | Log.i("Niddler", message); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /niddler-urlconnection/src/main/java/com/chimerapps/niddler/urlconnection/DelayedHttpUrlConnection.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.urlconnection; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.HttpURLConnection; 7 | import java.net.ProtocolException; 8 | import java.net.URL; 9 | import java.net.UnknownServiceException; 10 | import java.security.Permission; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author Nicola Verbeeck 16 | */ 17 | class DelayedHttpUrlConnection extends HttpURLConnection { 18 | 19 | protected DelayedHttpUrlConnection(final URL url) { 20 | super(url); 21 | } 22 | 23 | public InputStream getInputStream() throws IOException { 24 | throw new UnknownServiceException("protocol doesn't support input"); 25 | } 26 | 27 | public OutputStream getOutputStream() throws IOException { 28 | throw new UnknownServiceException("protocol doesn't support output"); 29 | } 30 | 31 | @Override 32 | public void disconnect() { 33 | 34 | } 35 | 36 | @Override 37 | public boolean usingProxy() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public void connect() throws IOException { 43 | connected = true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /niddler-java/src/main/java/com/chimerapps/niddler/utils/JavaLogUtil.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.utils; 2 | 3 | import com.chimerapps.niddler.util.LogUtil; 4 | 5 | import java.util.logging.Level; 6 | import java.util.logging.LogRecord; 7 | import java.util.logging.Logger; 8 | 9 | /** 10 | * @author Nicola Verbeeck 11 | * @version 1 12 | */ 13 | public class JavaLogUtil extends LogUtil { 14 | 15 | @Override 16 | protected void doLog(final int level, final String tag, final String message, final Throwable error) { 17 | final LogRecord record = new LogRecord(mapLevel(level), message); 18 | record.setThrown(error); 19 | Logger.getLogger(tag).log(record); 20 | } 21 | 22 | @Override 23 | protected void doLogStartup(String message) { 24 | System.out.println(message); 25 | } 26 | 27 | @Override 28 | protected boolean doIsLoggable(final String tag, final int level) { 29 | return Logger.getLogger(tag).isLoggable(mapLevel(level)); 30 | } 31 | 32 | private static Level mapLevel(final int level) { 33 | switch (level) { 34 | case VERBOSE: 35 | return Level.FINEST; 36 | case DEBUG: 37 | return Level.FINE; 38 | case INFO: 39 | return Level.INFO; 40 | case WARN: 41 | return Level.WARNING; 42 | case ERROR: 43 | default: 44 | return Level.SEVERE; 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /niddler-example-android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | signingConfigs { 6 | config { 7 | keyAlias 'exampleKey' 8 | storeFile file('../examplekeystore.keystore') 9 | storePassword 'keystore' 10 | keyPassword 'exampleKey' 11 | } 12 | } 13 | compileSdkVersion 31 14 | buildToolsVersion '28.0.3' 15 | defaultConfig { 16 | applicationId "com.icapps.sampleapplication" 17 | minSdkVersion 21 18 | targetSdkVersion 31 19 | versionCode 1 20 | versionName "1.0" 21 | signingConfig signingConfigs.config 22 | } 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | applicationIdSuffix '.release' 27 | signingConfig signingConfigs.config 28 | } 29 | debug { 30 | minifyEnabled false 31 | debuggable true 32 | } 33 | } 34 | productFlavors { 35 | } 36 | } 37 | 38 | dependencies { 39 | debugImplementation project(':niddler') 40 | debugImplementation project(':niddler-urlconnection') 41 | releaseImplementation project(':niddler-noop') 42 | implementation 'androidx.appcompat:appcompat:1.1.0' 43 | implementation 'com.squareup.retrofit2:retrofit:2.6.1' 44 | implementation 'com.squareup.retrofit2:converter-gson:2.3.0' 45 | implementation 'com.google.code.gson:gson:2.8.5' 46 | implementation 'com.squareup.okhttp3:okhttp:4.2.0' 47 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50" 48 | } 49 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/MessagesCache.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import com.chimerapps.niddler.util.StringUtil; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author Nicola Verbeeck 12 | * Date 22/11/16. 13 | */ 14 | final class MessagesCache { 15 | 16 | private final List mMessages; 17 | private final long mMaxCacheSize; 18 | private long mCacheSize; 19 | 20 | MessagesCache(final long maxCacheSize) { 21 | mMessages = new LinkedList<>(); 22 | mMaxCacheSize = maxCacheSize; 23 | } 24 | 25 | void clear() { 26 | synchronized (mMessages) { 27 | mMessages.clear(); 28 | mCacheSize = 0; 29 | } 30 | } 31 | 32 | void put(final String message) { 33 | if (mMaxCacheSize <= 0) { 34 | return; 35 | } 36 | 37 | final long size = StringUtil.calculateMemoryUsage(message); 38 | 39 | synchronized (mMessages) { 40 | while ((size + mCacheSize) > mMaxCacheSize) { 41 | if (!evictOld()) { //No more messages to remove, the message is too large for the cache -> do not add 42 | return; 43 | } 44 | } 45 | mCacheSize += size; 46 | mMessages.add(message); 47 | } 48 | } 49 | 50 | Collection get() { 51 | synchronized (mMessages) { 52 | return new ArrayList<>(mMessages); 53 | } 54 | } 55 | 56 | private boolean evictOld() { 57 | if (mMessages.isEmpty()) { 58 | return false; 59 | } 60 | final String message = mMessages.remove(0); 61 | mCacheSize -= StringUtil.calculateMemoryUsage(message); 62 | return true; 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/core/NiddlerMessageBase.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import androidx.annotation.NonNull; 9 | 10 | /** 11 | * @author Nicola Verbeeck 12 | * Date 10/11/16. 13 | */ 14 | public interface NiddlerMessageBase { 15 | 16 | /** 17 | * @return The id of the message. MUST BE unique for every message 18 | */ 19 | @NonNull 20 | String getMessageId(); 21 | 22 | /** 23 | * @return The request id of the message. Should be the same for all (logically) linked messages. Eg: requests and responses must share the same request tid 24 | */ 25 | @NonNull 26 | String getRequestId(); 27 | 28 | /** 29 | * @return The system timestamp in milliseconds since epoch when the message was sent/created 30 | */ 31 | long getTimestamp(); 32 | 33 | /** 34 | * @return The headers involved in the message 35 | */ 36 | @NonNull 37 | Map> getHeaders(); 38 | 39 | /** 40 | * @return Key-value meta-data to include in the message. Protocol specific meta-data keys start with 'X-Niddler-'. This prefix MUST NOT be used in client code as it will 41 | * be stripped before showing in the UI. Null keys or values are NOT supported 42 | */ 43 | @NonNull 44 | Map getMetadata(); 45 | 46 | /** 47 | * Write the message body to the given stream 48 | * 49 | * @param stream The stream to write to 50 | * @throws IOException Can be thrown if writing fails 51 | */ 52 | void writeBody(@NonNull final OutputStream stream) throws IOException; 53 | 54 | } -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/NiddlerMessageBase.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import androidx.annotation.NonNull; 9 | 10 | /** 11 | * @author Nicola Verbeeck 12 | * Date 10/11/16. 13 | */ 14 | public interface NiddlerMessageBase { 15 | 16 | /** 17 | * @return The id of the message. MUST BE unique for every message 18 | */ 19 | @NonNull 20 | String getMessageId(); 21 | 22 | /** 23 | * @return The request id of the message. Should be the same for all (logically) linked messages. Eg: requests and responses must share the same request tid 24 | */ 25 | @NonNull 26 | String getRequestId(); 27 | 28 | /** 29 | * @return The system timestamp in milliseconds since epoch when the message was sent/created 30 | */ 31 | long getTimestamp(); 32 | 33 | /** 34 | * @return The headers involved in the message 35 | */ 36 | @NonNull 37 | Map> getHeaders(); 38 | 39 | /** 40 | * @return Key-value meta-data to include in the message. Protocol specific meta-data keys start with 'X-Niddler-'. This prefix MUST NOT be used in client code as it will 41 | * be stripped before showing in the UI. Null keys or values are NOT supported 42 | */ 43 | @NonNull 44 | Map getMetadata(); 45 | 46 | /** 47 | * Write the message body to the given stream 48 | * 49 | * @param stream The stream to write to 50 | * @throws IOException Can be thrown if writing fails 51 | */ 52 | void writeBody(@NonNull final OutputStream stream) throws IOException; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/core/FakeNiddlerDebugger.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.chimerapps.niddler.core.debug.NiddlerDebugger; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author Nicola Verbeeck 12 | * @version 1 13 | */ 14 | class FakeNiddlerDebugger implements NiddlerDebugger { 15 | 16 | @Override 17 | public boolean isActive() { 18 | return false; 19 | } 20 | 21 | @Override 22 | public boolean isBlacklisted(@NonNull final CharSequence url) { 23 | return false; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public DebugRequest overrideRequest(@NonNull final NiddlerRequest request) { 29 | return null; 30 | } 31 | 32 | @Nullable 33 | @Override 34 | public DebugResponse handleRequest(@NonNull final NiddlerRequest request) { 35 | return null; 36 | } 37 | 38 | @Nullable 39 | @Override 40 | public DebugResponse handleResponse(@NonNull final NiddlerRequest request, @NonNull final NiddlerResponse response) { 41 | return null; 42 | } 43 | 44 | @Override 45 | public boolean applyDelayBeforeBlacklist() throws IOException { 46 | return false; 47 | } 48 | 49 | @Override 50 | public boolean applyDelayAfterBlacklist() throws IOException { 51 | return false; 52 | } 53 | 54 | @Override 55 | public boolean ensureCallTime(final long startTime) throws IOException { 56 | return false; 57 | } 58 | 59 | @Override 60 | public boolean waitForConnection(@NonNull final Runnable onDebuggerConnected) { 61 | return false; 62 | } 63 | 64 | @Override 65 | public boolean isWaitingForConnection() { 66 | return false; 67 | } 68 | 69 | @Override 70 | public void cancelWaitForConnection() { 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /niddler/src/main/java/com/chimerapps/niddler/service/OreoCompatHelper.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.service; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Notification; 5 | import android.app.NotificationChannel; 6 | import android.app.NotificationManager; 7 | import android.content.Context; 8 | import android.os.Build; 9 | import androidx.annotation.NonNull; 10 | 11 | /** 12 | * @author Nicola Verbeeck 13 | * @version 1 14 | */ 15 | @TargetApi(Build.VERSION_CODES.O) 16 | final class OreoCompatHelper { 17 | 18 | private static final String CHANNEL_ID = "Niddler-Channel-Id"; 19 | private static final String CHANNEL_NAME = "Niddler Channel"; 20 | private static final String CHANNEL_DESCRIPTION = "Channel for Niddler. Niddler uses a notification to keep it running and to notify the user that niddler is running"; 21 | 22 | @NonNull 23 | private static String createNotificationChannel(@NonNull final Context context) { 24 | final NotificationManager notificationManager = context.getSystemService(NotificationManager.class); 25 | if (notificationManager == null) { 26 | return ""; 27 | } 28 | 29 | final NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW); 30 | channel.setDescription(CHANNEL_DESCRIPTION); 31 | channel.enableLights(false); 32 | channel.enableVibration(false); 33 | channel.setBypassDnd(false); 34 | channel.setShowBadge(false); 35 | channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); 36 | 37 | notificationManager.createNotificationChannel(channel); 38 | return CHANNEL_ID; 39 | } 40 | 41 | @NonNull 42 | static Notification.Builder createNotificationBuilder(@NonNull final Context context) { 43 | return new Notification.Builder(context, createNotificationChannel(context)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/NiddlerResponse.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | /** 7 | * @author Nicola Verbeeck 8 | * Date 10/11/16. 9 | */ 10 | public interface NiddlerResponse extends NiddlerMessageBase { 11 | 12 | /** 13 | * @return The status code of the response. Eg: For HTTP this is the HTTP response code 14 | */ 15 | @NonNull 16 | Integer getStatusCode(); 17 | 18 | /** 19 | * @return The status line (message) of the response. Eg: For HTTP this is the HTTP response message 20 | */ 21 | @NonNull 22 | String getStatusLine(); 23 | 24 | /** 25 | * @return The http version used to handle the request. Can be empty if the protocol is not using http 26 | */ 27 | @NonNull 28 | String getHttpVersion(); 29 | 30 | /** 31 | * @return If set, the actual request that was sent over the network 32 | */ 33 | @Nullable 34 | NiddlerRequest actualNetworkRequest(); 35 | 36 | /** 37 | * @return If set, the actual response that was sent over the network 38 | */ 39 | @Nullable 40 | NiddlerResponse actualNetworkReply(); 41 | 42 | /** 43 | * @return If set, the stacktrace of an exception that was thrown during the execution of the request 44 | */ 45 | @Nullable 46 | StackTraceElement[] getErrorStackTrace(); 47 | 48 | /** 49 | * @return The time, in milliseconds, it took for the request to write to the network. Use -1 if unknown 50 | */ 51 | int getWriteTime(); 52 | 53 | /** 54 | * @return The time, in milliseconds, it took for the response to read from the network. Use -1 if unknown 55 | */ 56 | int getReadTime(); 57 | 58 | /** 59 | * @return The time, in milliseconds, it took for the response to arrive after it was written to the network. Use -1 if unknown 60 | */ 61 | int getWaitTime(); 62 | } 63 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/core/NiddlerResponse.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | /** 7 | * @author Nicola Verbeeck 8 | * Date 10/11/16. 9 | */ 10 | public interface NiddlerResponse extends NiddlerMessageBase { 11 | 12 | /** 13 | * @return The status code of the response. Eg: For HTTP this is the HTTP response code 14 | */ 15 | @NonNull 16 | Integer getStatusCode(); 17 | 18 | /** 19 | * @return The status line (message) of the response. Eg: For HTTP this is the HTTP response message 20 | */ 21 | @NonNull 22 | String getStatusLine(); 23 | 24 | /** 25 | * @return The http version used to handle the request. Can be empty if the protocol is not using http 26 | */ 27 | @NonNull 28 | String getHttpVersion(); 29 | 30 | /** 31 | * @return If set, the actual request that was sent over the network 32 | */ 33 | @Nullable 34 | NiddlerRequest actualNetworkRequest(); 35 | 36 | /** 37 | * @return If set, the actual response that was sent over the network 38 | */ 39 | @Nullable 40 | NiddlerResponse actualNetworkReply(); 41 | 42 | /** 43 | * @return If set, the stacktrace of an exception that was thrown during the execution of the request 44 | */ 45 | @Nullable 46 | StackTraceElement[] getErrorStackTrace(); 47 | 48 | /** 49 | * @return The time, in milliseconds, it took for the request to write to the network. Use -1 if unknown 50 | */ 51 | int getWriteTime(); 52 | 53 | /** 54 | * @return The time, in milliseconds, it took for the response to read from the network. Use -1 if unknown 55 | */ 56 | int getReadTime(); 57 | 58 | /** 59 | * @return The time, in milliseconds, it took for the response to arrive after it was written to the network. Use -1 if unknown 60 | */ 61 | int getWaitTime(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/retrofit/NiddlerRetrofitCallInjector.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.retrofit; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.chimerapps.niddler.core.Niddler; 6 | 7 | import okhttp3.Call; 8 | import retrofit2.Retrofit; 9 | 10 | /** 11 | * Helper utility class that injects the call-site stack trace for {@link com.chimerapps.niddler.interceptor.okhttp.NiddlerOkHttpInterceptor} for retrofit 12 | */ 13 | public final class NiddlerRetrofitCallInjector { 14 | 15 | private static final int DEFAULT_SKIP = 4; 16 | 17 | private NiddlerRetrofitCallInjector() { 18 | //Utility class 19 | } 20 | 21 | /** 22 | * Modified the retrofit builder to allow including stack traces into requests. Uses the default skip stack size (4) to declutter the request 23 | * 24 | * @param builder The builder to update 25 | * @param niddler The niddler instance 26 | * @param callFactory The actual factory for creating calls 27 | * @return The builder itself 28 | */ 29 | @NonNull 30 | public static Retrofit.Builder inject(@NonNull final Retrofit.Builder builder, @NonNull final Niddler niddler, @NonNull final Call.Factory callFactory) { 31 | return builder.callFactory(callFactory); 32 | } 33 | 34 | /** 35 | * Modified the retrofit builder to allow including stack traces into requests. 36 | * 37 | * @param builder The builder to update 38 | * @param niddler The niddler instance 39 | * @param callFactory The actual factory for creating calls 40 | * @param skipPast The number of stack trace entries to skip past 41 | * @return The builder itself 42 | */ 43 | @NonNull 44 | public static Retrofit.Builder inject(@NonNull final Retrofit.Builder builder, @NonNull final Niddler niddler, @NonNull final Call.Factory callFactory, final int skipPast) { 45 | return builder.callFactory(callFactory); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /RELEASENOTES.md: -------------------------------------------------------------------------------- 1 | ### 1.6.1 ### 2 | 3 | * Include process id 4 | 5 | ### 1.5.4 ### 6 | 7 | * Ensure we catch WebSocket errors. Fixes #26 8 | 9 | ### 1.5.3 ### 10 | 11 | * Don't retain links to destroyed service. Fixes #25 12 | 13 | ### 1.5.2 ### 14 | 15 | * Don't retain links to destroyed service. Fixes #25 16 | 17 | ### 1.5.1 ### 18 | 19 | * Fixed broken package references 20 | 21 | ### 1.5.0 ### 22 | 23 | * First package release on maven central 24 | 25 | #### BREAKING CHANGE 26 | 27 | * Niddler now resides under `com.chimerapps` instead of `com.icapps`. Please update your dependency AND package names accordingly. Sorry 28 | 29 | 30 | ### 1.4.0 ### 31 | 32 | * Don't crash cache if we serve a debug response in network-interceptor mode. Fixes #20 33 | * Add metadata to protocol to send agnostic metadata to the plugin. Replaces injected headers. 34 | * Check if a response was served purely from cache and mark it as such in the metadata. Fixes #19 35 | 36 | ### 1.3.x ### 37 | 38 | * Minor enhancements 39 | 40 | ### 1.2.0 ### 41 | 42 | * Added an option to the okhttp interceptor to also report downstream exceptions 43 | * Don't crash when android does not allow us to start the service 44 | 45 | 46 | ### 1.1.0 ### 47 | 48 | * Support for session icons and tag reporting (for automatic connection in IDE) 49 | * Support loading session icon from AndroidManifest 50 | 51 | 52 | ### 1.0.0-alpha10 ### 53 | 54 | * Breaking change! 55 | * Split up library in android and java versions 56 | * Android dependency: `com.chimerapps.niddler:niddler:1.0.0-alpha10` 57 | * Android no-op dependency: `com.chimerapps.niddler:niddler-noop:1.0.0-alpha10` 58 | * Java dependency: `com.chimerapps.niddler:niddler-java:1.0.0-alpha10` 59 | * Java no-op dependency: `com.chimerapps.niddler:niddler-java-noop:1.0.0-alpha10` 60 | * Initialize niddler using: 61 | * `new AndroidNiddler.Builder()...` 62 | * `new JavaNiddler.Builder()...` 63 | * Java-only version of niddler 64 | * No android dependencies 65 | * Initialize using `new JavaNiddler.Builder()` 66 | -------------------------------------------------------------------------------- /niddler-noop-base/src/main/java/com/chimerapps/niddler/interceptor/okhttp/NiddlerOkHttpInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.interceptor.okhttp; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.chimerapps.niddler.core.Niddler; 6 | 7 | import java.io.IOException; 8 | 9 | import okhttp3.Interceptor; 10 | import okhttp3.Request; 11 | import okhttp3.Response; 12 | 13 | /** 14 | * @author Nicola Verbeeck 15 | */ 16 | @SuppressWarnings("DesignForExtension") 17 | public class NiddlerOkHttpInterceptor implements Interceptor { 18 | 19 | @Deprecated 20 | public NiddlerOkHttpInterceptor(@NonNull final Niddler niddler) { 21 | // Dummy implementation 22 | } 23 | 24 | /** 25 | * Creates the authenticator that will report messages to the provided niddler. The name is only 26 | * used for identification purposes on the client 27 | * 28 | * @param niddler The niddler instance to report to 29 | * @param name A name for this interceptor 30 | */ 31 | public NiddlerOkHttpInterceptor(@NonNull final Niddler niddler, @NonNull final String name) { 32 | // Dummy implementation 33 | } 34 | 35 | /** 36 | * Creates the authenticator that will report messages to the provided niddler. The name is only 37 | * used for identification purposes on the client 38 | * 39 | * @param niddler The niddler instance to report to 40 | * @param name A name for this interceptor 41 | * @param reportErrors Report exceptions thrown by deeper layers and log them as responses with code 0 42 | */ 43 | public NiddlerOkHttpInterceptor(@NonNull final Niddler niddler, @NonNull final String name, final boolean reportErrors) { 44 | // Dummy implementation 45 | } 46 | 47 | public NiddlerOkHttpInterceptor blacklist(@NonNull final String urlPattern) { 48 | //Dummy implementation 49 | return this; 50 | } 51 | 52 | @Override 53 | public Response intercept(final Chain chain) throws IOException { 54 | return chain.proceed(chain.request()); 55 | } 56 | 57 | @NonNull 58 | public static Request appendContext(@NonNull final Request request, @NonNull final String context) { 59 | return request; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/ServerAuth.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.chimerapps.niddler.util.LogUtil; 6 | import com.chimerapps.niddler.util.StringUtil; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.security.MessageDigest; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.security.SecureRandom; 12 | 13 | /** 14 | * @author Nicola Verbeeck 15 | * Date 22/11/16. 16 | */ 17 | final class ServerAuth { 18 | 19 | private ServerAuth() { 20 | //Utility class 21 | } 22 | 23 | private static SecureRandom mRandom; 24 | 25 | private static void init() { 26 | if (mRandom != null) { 27 | return; 28 | } 29 | 30 | mRandom = new SecureRandom(); 31 | } 32 | 33 | static AuthRequest generateAuthenticationRequest(@Nullable final String packageName) { 34 | init(); 35 | final byte[] randomBytes = new byte[512]; 36 | mRandom.nextBytes(randomBytes); 37 | return new AuthRequest(StringUtil.toString(randomBytes), packageName); 38 | } 39 | 40 | static boolean checkAuthReply(final AuthRequest request, final AuthReply reply, final String password) { 41 | if (reply == null || reply.hashKey == null || request == null) { 42 | return false; 43 | } 44 | try { 45 | final String mustBe = StringUtil.toString(MessageDigest.getInstance("SHA-512").digest((request.hashKey + password).getBytes("UTF-8"))); 46 | return reply.hashKey.equals(mustBe); 47 | } catch (final NoSuchAlgorithmException e) { 48 | LogUtil.niddlerLogError("ServerAuth", "SHA-512 not found", e); 49 | 50 | return false; 51 | } catch (final UnsupportedEncodingException e) { 52 | throw new IllegalStateException("UTF-8 not found, BAIL", e); 53 | } 54 | } 55 | 56 | static class AuthRequest { 57 | final String hashKey; 58 | @Nullable 59 | final String packageName; 60 | 61 | AuthRequest(final String hashKey, @Nullable final String packageName) { 62 | this.hashKey = hashKey; 63 | this.packageName = packageName; 64 | } 65 | } 66 | 67 | static class AuthReply { 68 | final String hashKey; 69 | 70 | AuthReply(final String hashKey) { 71 | this.hashKey = hashKey; 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /niddler-noop/src/main/java/com/chimerapps/niddler/core/AndroidNiddler.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * @author Nicola Verbeeck 7 | * @version 1 8 | */ 9 | public final class AndroidNiddler extends Niddler implements Niddler.PlatformNiddler { 10 | 11 | private AndroidNiddler() { 12 | super(); 13 | } 14 | 15 | /** 16 | * Attaches the Niddler instance to the application's activity lifecycle callbacks, thus starting and stopping a NiddlerService 17 | * when activities start and stop. This will show a notification with which you can stop Niddler at any time. 18 | * 19 | * @param application the application to attach the Niddler instance to 20 | */ 21 | @SuppressWarnings("WeakerAccess") 22 | public void attachToApplication(final Application application) { 23 | } 24 | 25 | /** 26 | * Attaches the Niddler instance to the application's activity lifecycle callbacks, thus starting and stopping a NiddlerService 27 | * when activities start and stop. This will show a notification with which you can stop Niddler at any time. 28 | * 29 | * @param application the application to attach the Niddler instance to 30 | * @param autoStopAfter Automatically stop the niddler background service after x milliseconds. Use -1 to keep the service running and use 0 to stop the service immediately 31 | */ 32 | @SuppressWarnings("WeakerAccess") 33 | public void attachToApplication(final Application application, final long autoStopAfter) { 34 | } 35 | 36 | @Override 37 | public void closePlatform() { 38 | } 39 | 40 | /** 41 | * Creates a server info based on the application's package name and some device fields. 42 | * To provide a session icon, you can use meta data in the AndroidManifest. Eg: {@code } 43 | * 44 | * @param application The application niddler is instrumenting 45 | * @return A server info document to use in the {@link Niddler.Builder} 46 | */ 47 | public static NiddlerServerInfo fromApplication(final Application application) { 48 | return new NiddlerServerInfo("", ""); 49 | } 50 | 51 | public static class Builder extends Niddler.Builder { 52 | 53 | public Builder() { 54 | } 55 | 56 | @Override 57 | public AndroidNiddler build() { 58 | return new AndroidNiddler(); 59 | } 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/core/ServerConnection.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.core; 2 | 3 | import com.chimerapps.niddler.util.LogUtil; 4 | 5 | import org.java_websocket.WebSocket; 6 | 7 | import androidx.annotation.Nullable; 8 | 9 | /** 10 | * @author Nicola Verbeeck 11 | * Date 22/11/16. 12 | */ 13 | final class ServerConnection { 14 | 15 | private static final int STATE_NEW = 0; 16 | private static final int STATE_AUTH_REQ_SENT = 1; 17 | private static final int STATE_READY = 2; 18 | private static final int STATE_CLOSED = 3; 19 | 20 | private final WebSocket mSocket; 21 | private int mState = STATE_NEW; 22 | private ServerAuth.AuthRequest mAuthRequest; 23 | 24 | ServerConnection(final WebSocket socket) { 25 | mSocket = socket; 26 | sendProtocolInfo(); 27 | } 28 | 29 | boolean canReceiveData() { 30 | return mState == STATE_READY; 31 | } 32 | 33 | void noAuth() { 34 | if (mState == STATE_NEW) { 35 | mState = STATE_READY; 36 | } 37 | } 38 | 39 | void closed() { 40 | mState = STATE_CLOSED; 41 | } 42 | 43 | void sendAuthRequest(@Nullable final String packageName) { 44 | mState = STATE_AUTH_REQ_SENT; 45 | mAuthRequest = ServerAuth.generateAuthenticationRequest(packageName); 46 | try { 47 | mSocket.send(MessageBuilder.buildMessage(mAuthRequest)); 48 | } catch (Throwable e) { 49 | LogUtil.niddlerLogError("ServerConnection", "Failed to send auth request:", e); 50 | } 51 | } 52 | 53 | boolean checkAuthReply(final ServerAuth.AuthReply authReply, final String password) { 54 | if ((mState != STATE_AUTH_REQ_SENT) || !ServerAuth.checkAuthReply(mAuthRequest, authReply, password)) { 55 | mState = STATE_CLOSED; 56 | mSocket.close(401); 57 | return false; 58 | } 59 | sendAuthSuccess(); 60 | mState = STATE_READY; 61 | return true; 62 | } 63 | 64 | boolean isFor(final WebSocket socket) { 65 | return this.mSocket == socket; 66 | } 67 | 68 | void send(final String message) { 69 | try { 70 | mSocket.send(message); 71 | } catch (Throwable e) { 72 | LogUtil.niddlerLogError("ServerConnection", "Failed to send message:", e); 73 | } 74 | } 75 | 76 | private void sendProtocolInfo() { 77 | try { 78 | mSocket.send(MessageBuilder.buildProtocolVersionMessage()); 79 | } catch (Throwable e) { 80 | LogUtil.niddlerLogError("ServerConnection", "Failed to protocol info message:", e); 81 | } 82 | } 83 | 84 | private void sendAuthSuccess() { 85 | try { 86 | mSocket.send(MessageBuilder.buildAuthSuccess()); 87 | } catch (Throwable e) { 88 | LogUtil.niddlerLogError("ServerConnection", "Failed to send auth success message:", e); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /niddler-base/src/main/java/com/chimerapps/niddler/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.chimerapps.niddler.util; 2 | 3 | import androidx.annotation.RestrictTo; 4 | 5 | /** 6 | * @author Nicola Verbeeck 7 | * @version 1 8 | */ 9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 10 | public abstract class LogUtil { 11 | 12 | public static final int VERBOSE = 2; 13 | public static final int DEBUG = 3; 14 | public static final int INFO = 4; 15 | public static final int WARN = 5; 16 | public static final int ERROR = 6; 17 | 18 | public static LogUtil instance; 19 | 20 | public static boolean isLoggable(final String tag, final int level) { 21 | final LogUtil current = instance; 22 | return current != null && current.doIsLoggable(tag, level); 23 | } 24 | 25 | public static void niddlerLogDebug(final String tag, final String message) { 26 | final LogUtil current = instance; 27 | if (current != null) { 28 | current.doLog(DEBUG, tag, message, null); 29 | } 30 | } 31 | 32 | public static void niddlerLogInfo(final String tag, final String message) { 33 | final LogUtil current = instance; 34 | if (current != null) { 35 | current.doLog(INFO, tag, message, null); 36 | } 37 | } 38 | 39 | public static void niddlerLogWarning(final String tag, final String message) { 40 | niddlerLogWarning(tag, message, null); 41 | } 42 | 43 | public static void niddlerLogWarning(final String tag, final String message, final Throwable error) { 44 | final LogUtil current = instance; 45 | if (current != null) { 46 | current.doLog(WARN, tag, message, error); 47 | } 48 | } 49 | 50 | public static void niddlerLogError(final String tag, final String message) { 51 | niddlerLogError(tag, message, null); 52 | } 53 | 54 | public static void niddlerLogError(final String tag, final String message, final Throwable error) { 55 | final LogUtil current = instance; 56 | if (current != null) { 57 | current.doLog(ERROR, tag, message, error); 58 | } 59 | } 60 | 61 | public static void niddlerLogVerbose(final String tag, final String message) { 62 | final LogUtil current = instance; 63 | if (current != null) { 64 | current.doLog(VERBOSE, tag, message, null); 65 | } 66 | } 67 | 68 | public static void niddlerLogStartup(String message) { 69 | final LogUtil current = instance; 70 | if (current != null) { 71 | current.doLogStartup(message); 72 | } else { 73 | System.out.println(message); 74 | } 75 | } 76 | 77 | protected abstract void doLogStartup(String message); 78 | 79 | protected abstract void doLog(final int level, final String tag, final String message, final Throwable error); 80 | 81 | protected abstract boolean doIsLoggable(final String tag, final int level); 82 | } 83 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows 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 | -------------------------------------------------------------------------------- /niddler-example-android/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 20 | 21 |