diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..95a973d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0f4d568
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+A Lifecycle aware network state change listener library for Android
+
+Supports SDK
+
+
+[x] SDK >=19
+
+Usage
+
+```java
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+
+import androidx.appcompat.app.AppCompatActivity;
+import lib.gintec_rdl.network_state.network.NetworkSpecs;
+import lib.gintec_rdl.network_state.network.NetworkState;
+
+public class ExampleActivity extends AppCompatActivity {
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_example);
+
+ ArrayList loglist = new ArrayList<>();
+
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_list_item_1, android.R.id.text1, loglist);
+
+ ((ListView) findViewById(R.id.listView)).setAdapter(adapter);
+
+ NetworkState.of(NetworkSpecs.WIFI_SPEC, this)
+ .v21()
+ .ifSupported(networkSpec -> adapter.add("Network is supported"))
+ .ifNotSupported(networkSpec -> adapter.add("Network not supported"))
+ .whenLosing(networkSpec -> adapter.add("Losing network..."))
+ .whenNotAvailable(networkSpec -> adapter.add("Network not available"))
+ .whenLost(networkSpec -> adapter.add("Network lost"))
+ .whenAvailable(networkSpec -> adapter.add("Network available"))
+ .ifFailed(networkSpec -> adapter.add("Connection failed"))
+ .whenAuthenticating(networkSpec -> adapter.add("Authenticating"))
+ .whenCheckingCaptivePortal(networkSpec -> adapter.add("Checking captive portal..."))
+ .whenObtainingIpAddress(networkSpec -> adapter.add("Obtaining IP..."))
+ .ifBlocked(networkSpec -> adapter.add("Blocked"))
+ .ifSuspended(networkSpec -> adapter.add("Suspended"))
+ .whenConnecting(networkSpec -> adapter.add("Connecting..."))
+ .whenIdle(networkSpec -> adapter.add("Idle"))
+ .whenScanning(networkSpec -> adapter.add("Scanning..."))
+ .whenVerifyingPoorLink(networkSpec -> adapter.add("Verifying poor link..."))
+ .create()
+ .attachTo(this);
+
+ }
+}
+```
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..e263177
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ buildToolsVersion = '28.0.3'
+}
+
+dependencies {
+ def lifecycle_version = "2.1.0"
+
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ testImplementation 'junit:junit:4.13-beta-3'
+ androidTestImplementation 'androidx.test:runner:1.3.0-alpha02'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02'
+
+ implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
+ implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/lib/gintec_rdl/network_state/ExampleInstrumentedTest.java b/app/src/androidTest/java/lib/gintec_rdl/network_state/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..bd78abd
--- /dev/null
+++ b/app/src/androidTest/java/lib/gintec_rdl/network_state/ExampleInstrumentedTest.java
@@ -0,0 +1,38 @@
+package lib.gintec_rdl.network_state;
+
+import android.content.Context;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import lib.gintec_rdl.network_state.network.NetworkSpecs;
+import lib.gintec_rdl.network_state.network.NetworkState;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("app.gintec_rdl.network_state", appContext.getPackageName());
+
+ NetworkState.of(NetworkSpecs.VPN_SPEC, appContext)
+ .whenConnected(networkSpec -> {
+ })
+ .whenLost(networkSpec -> {
+
+ })
+ .create()
+ .observe(null);
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ea9972a
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/ExampleActivity.java b/app/src/main/java/lib/gintec_rdl/network_state/ExampleActivity.java
new file mode 100644
index 0000000..6b04d4a
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/ExampleActivity.java
@@ -0,0 +1,40 @@
+package lib.gintec_rdl.network_state;
+
+public class ExampleActivity /*extends AppCompatActivity*/ {
+/*
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_example);
+
+ ArrayList loglist = new ArrayList<>();
+
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_list_item_1, android.R.id.text1, loglist);
+
+ ((ListView) findViewById(R.id.listView)).setAdapter(adapter);
+
+ NetworkState.of(NetworkSpecs.ETHERNET_SPEC, this)
+ .v21()
+ .ifSupported(networkSpec -> adapter.add("Network is supported"))
+ .ifNotSupported(networkSpec -> adapter.add("Network not supported"))
+ .whenLosing(networkSpec -> adapter.add("Losing network..."))
+ .whenNotAvailable(networkSpec -> adapter.add("Network not available"))
+ .whenLost(networkSpec -> adapter.add("Network lost"))
+ .whenAvailable(networkSpec -> adapter.add("Network available"))
+ .ifFailed(networkSpec -> adapter.add("Connection failed"))
+ .whenAuthenticating(networkSpec -> adapter.add("Authenticating"))
+ .whenCheckingCaptivePortal(networkSpec -> adapter.add("Checking captive portal..."))
+ .whenObtainingIpAddress(networkSpec -> adapter.add("Obtaining IP..."))
+ .ifBlocked(networkSpec -> adapter.add("Blocked"))
+ .ifSuspended(networkSpec -> adapter.add("Suspended"))
+ .whenConnecting(networkSpec -> adapter.add("Connecting..."))
+ .whenIdle(networkSpec -> adapter.add("Idle"))
+ .whenScanning(networkSpec -> adapter.add("Scanning..."))
+ .whenVerifyingPoorLink(networkSpec -> adapter.add("Verifying poor link..."))
+ .create()
+ .attachTo(this);
+
+ }*/
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateCallback.java b/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateCallback.java
new file mode 100644
index 0000000..7589a9f
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateCallback.java
@@ -0,0 +1,7 @@
+package lib.gintec_rdl.network_state;
+
+import lib.gintec_rdl.network_state.network.NetworkSpec;
+
+public interface NetworkStateCallback {
+ void action(NetworkSpec networkSpec);
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateException.java b/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateException.java
new file mode 100644
index 0000000..dc05a09
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/NetworkStateException.java
@@ -0,0 +1,7 @@
+package lib.gintec_rdl.network_state;
+
+public class NetworkStateException extends RuntimeException {
+ public NetworkStateException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/LegacyNetworkChangeListener.java b/app/src/main/java/lib/gintec_rdl/network_state/network/LegacyNetworkChangeListener.java
new file mode 100644
index 0000000..ccb09a5
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/LegacyNetworkChangeListener.java
@@ -0,0 +1,128 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.util.Log;
+
+import lib.gintec_rdl.network_state.utils.PlatformUtils;
+
+final class LegacyNetworkChangeListener extends BroadcastReceiver implements NetworkChangeListener {
+ private static final String TAG = "LegacyListener";
+ private final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+
+ private final NetworkSpec networkSpec;
+
+ private boolean registered;
+
+ public LegacyNetworkChangeListener(NetworkSpec networkSpec) {
+ this.networkSpec = networkSpec;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ final ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = mgr.getActiveNetworkInfo();
+ if (networkInfo != null) {
+ boolean isTargetNetwork = networkInfo.getType() == networkSpec.builder.legacyNetworkType;
+
+ if (!isTargetNetwork) {
+ if (networkSpec.builder.legacyNetworkType == ConnectivityManager.TYPE_BLUETOOTH) {
+ networkInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH);
+ isTargetNetwork = true;
+ }
+ if (networkSpec.builder.legacyNetworkType == ConnectivityManager.TYPE_ETHERNET) {
+ networkInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
+ isTargetNetwork = true;
+ } else if (networkSpec.builder.legacyNetworkType == ConnectivityManager.TYPE_VPN) {
+ if (PlatformUtils.isLollipop()) {
+ networkInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_VPN);
+ isTargetNetwork = true;
+ }
+ }
+ }
+
+ // Type all
+ if (!isTargetNetwork && networkSpec.builder.legacyNetworkType == NetworkSpecs.ANY_SPEC.legacyType) {
+ isTargetNetwork = true;
+ }
+
+ if (isTargetNetwork) {
+ final NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();
+ switch (detailedState) {
+ case IDLE:
+ callback(networkSpec.builder.whenIdle, networkSpec);
+ break;
+ case FAILED:
+ callback(networkSpec.builder.ifFailed, networkSpec);
+ break;
+ case BLOCKED:
+ callback(networkSpec.builder.ifBlocked, networkSpec);
+ break;
+ case SCANNING:
+ callback(networkSpec.builder.whenScanning, networkSpec);
+ break;
+ case CONNECTED:
+ callback(networkSpec.builder.whenAvailable, networkSpec);
+ break;
+ case SUSPENDED:
+ callback(networkSpec.builder.ifSuspended, networkSpec);
+ break;
+ case CONNECTING:
+ callback(networkSpec.builder.whenConnecting, networkSpec);
+ break;
+ case AUTHENTICATING:
+ callback(networkSpec.builder.whenAuthenticating, networkSpec);
+ break;
+ case DISCONNECTED:
+ callback(networkSpec.builder.whenLost, networkSpec);
+ break;
+ case DISCONNECTING:
+ callback(networkSpec.builder.whenLosing, networkSpec);
+ break;
+ case CAPTIVE_PORTAL_CHECK:
+ callback(networkSpec.builder.whenCheckingCaptivePortal, networkSpec);
+ break;
+ case OBTAINING_IPADDR:
+ callback(networkSpec.builder.whenObtainingIpAddress, networkSpec);
+ break;
+ case VERIFYING_POOR_LINK:
+ callback(networkSpec.builder.whenVerifyingPoorLink, networkSpec);
+ break;
+ }
+ } else {
+ Log.w(TAG, "NetworkSpec type not registered:" + networkInfo.getSubtype());
+ }
+ } else {
+ callback(networkSpec.builder.whenNotAvailable, networkSpec);
+ }
+ }
+ }
+
+ @Override
+ public void registerSelf(Context context) {
+ synchronized (this) {
+ context.registerReceiver(this, intentFilter);
+ registered = true;
+ }
+ }
+
+ @Override
+ public void unregisterSelf(Context context) {
+ synchronized (this) {
+ context.unregisterReceiver(this);
+ registered = false;
+ }
+ }
+
+ @Override
+ public boolean isRegistered() {
+ synchronized (this) {
+ return registered;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkChangeListener.java b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkChangeListener.java
new file mode 100644
index 0000000..b76df34
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkChangeListener.java
@@ -0,0 +1,37 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.content.Context;
+
+import lib.gintec_rdl.network_state.NetworkStateCallback;
+import lib.gintec_rdl.network_state.utils.LangUtils;
+
+/**
+ * Callback interface for receiving connection state change events
+ */
+interface NetworkChangeListener {
+ NetworkStateCallback NOP_CALLBACK = network -> {
+ };
+
+ default void callback(NetworkStateCallback callback, NetworkSpec spec) {
+ spec.handler.post(() -> LangUtils.Optional.of(callback).orElse(NOP_CALLBACK).action(spec));
+ }
+
+ /**
+ * Instructs this listener to register itself.
+ *
+ * @param context .
+ */
+ void registerSelf(Context context);
+
+ /**
+ * Instructs this listener to unregister itself.
+ *
+ * @param context .
+ */
+ void unregisterSelf(Context context);
+
+ /**
+ * @return Whether registered or not
+ */
+ boolean isRegistered();
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpec.java b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpec.java
new file mode 100644
index 0000000..f0ceb73
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpec.java
@@ -0,0 +1,346 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import lib.gintec_rdl.network_state.NetworkStateCallback;
+import lib.gintec_rdl.network_state.utils.PlatformUtils;
+
+/**
+ * This class specifies the properties of which network connection to listen changes for
+ * Depending on the API use (legacy or v21), some methods may not be called at all.
+ *
+ * The corresponding callbacks for following methods are guaranteed to be called:
+ *
+ * - {@link Builder#ifSupported(NetworkStateCallback)}
+ * - {@link Builder#ifNotSupported(NetworkStateCallback)}
+ * - {@link Builder#whenAvailable(NetworkStateCallback)}
+ * - {@link Builder#whenNotAvailable(NetworkStateCallback)}
+ *
+ *
+ */
+public final class NetworkSpec {
+ private final DefaultLifecycleObserver lifecycleObserver;
+ final Builder builder;
+ final Handler handler;
+ private final NetworkChangeListener listener;
+
+ private NetworkSpec(Builder builder) {
+ this.builder = builder;
+ this.handler = new Handler(Looper.getMainLooper());
+ if (PlatformUtils.isLollipop()) {
+ if (builder.legacy) {
+ listener = new LegacyNetworkChangeListener(this);
+ } else {
+ listener = new V21NetworkChangeListener(this);
+ }
+ } else {
+ listener = new LegacyNetworkChangeListener(this);
+ }
+ this.lifecycleObserver = new DefaultLifecycleObserver() {
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ listener.registerSelf(builder.context);
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ listener.unregisterSelf(builder.context);
+ }
+ };
+ }
+
+ /**
+ * Attaches the listener lifecycle owner
+ *
+ * @param lifecycleOwner Lifecycle owner to attach to
+ */
+ public void attachTo(@NonNull LifecycleOwner lifecycleOwner) {
+ if (!builder.networkSupported) {
+ listener.callback(builder.ifNotSupported, this);
+ // Nothing to observe
+ } else {
+ listener.callback(builder.ifSupported, this);
+ lifecycleOwner.getLifecycle().addObserver(lifecycleObserver);
+ }
+ }
+
+ /**
+ * Detach the network state change listener from the given lifecycle owner
+ *
+ * @param lifecycleOwner The lifecycle owner to detach from
+ */
+ public void detachFrom(LifecycleOwner lifecycleOwner) {
+ if (lifecycleOwner != null) {
+ lifecycleOwner.getLifecycle().removeObserver(lifecycleObserver);
+
+ // No need to keep the listener active
+ if (listener.isRegistered()) {
+ listener.unregisterSelf(builder.context);
+ }
+ }
+ }
+
+ /**
+ * Listener builder class.
+ * Note that callback methods specified here will be called on the U.I thread
+ */
+ public static final class Builder {
+ NetworkStateCallback whenIdle;
+ NetworkStateCallback ifFailed;
+ NetworkStateCallback ifBlocked;
+ NetworkStateCallback whenScanning;
+ NetworkStateCallback ifSuspended;
+ NetworkStateCallback whenConnecting;
+ NetworkStateCallback whenAuthenticating;
+ NetworkStateCallback whenVerifyingPoorLink;
+ NetworkStateCallback whenCheckingCaptivePortal;
+ NetworkStateCallback whenObtainingIpAddress;
+ NetworkStateCallback whenLosing;
+ NetworkStateCallback whenLost;
+ NetworkStateCallback whenNotAvailable;
+ NetworkStateCallback whenAvailable;
+ NetworkStateCallback ifSupported;
+ NetworkStateCallback ifNotSupported;
+
+ final int legacyNetworkType;
+ final int v21NetworkType;
+ private boolean legacy;
+ private boolean networkSupported;
+ private final Context context;
+
+ private boolean mutable;
+
+ /**
+ * @param context Application context
+ * @param specs Network specification
+ */
+ public Builder(Context context, NetworkSpecs specs) {
+ this.context = context;
+ this.legacyNetworkType = specs.legacyType;
+ this.v21NetworkType = specs.v21Type;
+ mutable = true;
+ }
+
+ private void assertMutable() {
+ if (!mutable) {
+ throw new IllegalStateException("You can no longer modify this builder");
+ }
+ }
+
+ /**
+ * Use pre-Lollipop API for older devices
+ *
+ * @return .
+ */
+ public Builder legacy() {
+ this.legacy = true;
+ return this;
+ }
+
+ /**
+ * Use APIs available since Lollipop
+ *
+ * @return .
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ public Builder v21() {
+ this.legacy = false;
+ return this;
+ }
+
+ /**
+ * Set callback when network is idle
+ * Call not guaranteed
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#IDLE
+ */
+ public Builder whenIdle(NetworkStateCallback callback) {
+ this.whenIdle = callback;
+ return this;
+ }
+
+ /**
+ * Callback if attempt to connect to network failed
+ * Call not guaranteed
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#FAILED
+ */
+ public Builder ifFailed(NetworkStateCallback callback) {
+ this.ifFailed = callback;
+ return this;
+ }
+
+ /**
+ * Callback when access to network is blocked
+ * Call not guaranteed
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#BLOCKED
+ */
+ public Builder ifBlocked(NetworkStateCallback callback) {
+ ifBlocked = callback;
+ return this;
+ }
+
+ /**
+ * Callback when searching for an available access point
+ * Call not guaranteed
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#SCANNING
+ */
+ public Builder whenScanning(NetworkStateCallback callback) {
+ whenScanning = callback;
+ return this;
+ }
+
+ /**
+ * Callback when IP traffic suspended
+ * Call not guaranteed
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#SUSPENDED
+ */
+ public Builder ifSuspended(NetworkStateCallback callback) {
+ ifSuspended = callback;
+ return this;
+ }
+
+ public Builder whenConnecting(NetworkStateCallback callback) {
+ whenConnecting = callback;
+ return this;
+ }
+
+ public Builder whenAuthenticating(NetworkStateCallback callback) {
+ whenAuthenticating = callback;
+ return this;
+ }
+
+ public Builder whenVerifyingPoorLink(NetworkStateCallback callback) {
+ whenVerifyingPoorLink = callback;
+ return this;
+ }
+
+ public Builder whenCheckingCaptivePortal(NetworkStateCallback callback) {
+ whenCheckingCaptivePortal = callback;
+ return this;
+ }
+
+ public Builder whenObtainingIpAddress(NetworkStateCallback callback) {
+ whenObtainingIpAddress = callback;
+ return this;
+ }
+
+ public Builder whenLosing(NetworkStateCallback callback) {
+ whenLosing = callback;
+ return this;
+ }
+
+ public Builder whenLost(NetworkStateCallback callback) {
+ whenLost = callback;
+ return this;
+ }
+
+ /**
+ * Callback when network connection is not available, i.e in a disconnected state
+ * This callback is guaranteed to be called. Use this callback to be notified when
+ * the specified network is not available.
+ *
+ * @param callback .
+ * @return .
+ */
+ public Builder whenNotAvailable(NetworkStateCallback callback) {
+ whenNotAvailable = callback;
+ return this;
+ }
+
+ /**
+ * Callback when network connection is available, i.e in a connected state
+ * This callback is guaranteed to be called when the specified network is connected
+ * and traffic can be exchanged with remote hosts
+ *
+ * @param callback .
+ * @return .
+ * @see android.net.NetworkInfo.DetailedState#CONNECTED
+ */
+ public Builder whenAvailable(NetworkStateCallback callback) {
+ whenAvailable = callback;
+ return this;
+ }
+
+ /**
+ * Callback if device supports networking as well as the specified network type
+ * This callback is guaranteed to be called and will be the first to be called if all
+ * the pre-conditions are met
+ *
+ * @param callback .
+ * @return .
+ * @see #ifNotSupported(NetworkStateCallback)
+ */
+ public Builder ifSupported(NetworkStateCallback callback) {
+ ifSupported = callback;
+ return this;
+ }
+
+ /**
+ * Callback if device does not support networking or the specified network type
+ * If the right conditions are not met, this will be the first and probably also
+ * the last callback to be called
+ *
+ * @param callback .
+ * @return .
+ * @see #ifSupported(NetworkStateCallback)
+ */
+ public Builder ifNotSupported(NetworkStateCallback callback) {
+ ifNotSupported = callback;
+ return this;
+ }
+
+ public NetworkSpec create() {
+ assertMutable();
+ ConnectivityManager mgr
+ = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mgr != null) {
+ if (PlatformUtils.isLollipop()) {
+ final Network[] networks = mgr.getAllNetworks();
+ for (Network network : networks) {
+ final NetworkInfo networkInfo = mgr.getNetworkInfo(network);
+ // because >= v21 doesn't have corresponding API
+ if (legacyNetworkType == networkInfo.getType()) {
+ networkSupported = true;
+ break;
+ }
+ }
+ // Fallback to legacy checks as well just to be sure
+ final NetworkInfo networkInfo = mgr.getNetworkInfo(legacyNetworkType);
+ networkSupported = networkInfo != null;
+ } else {
+ final NetworkInfo networkInfo = mgr.getNetworkInfo(legacyNetworkType);
+ networkSupported = networkInfo != null;
+ }
+ } else {
+ networkSupported = false;
+ }
+ mutable = false;
+ return new NetworkSpec(this);
+ }
+ }
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpecs.java b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpecs.java
new file mode 100644
index 0000000..e78df13
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkSpecs.java
@@ -0,0 +1,47 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.net.NetworkCapabilities;
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+
+
+/**
+ * Network connection specifications
+ */
+public enum NetworkSpecs {
+ /**
+ * Listen for mobile network state events
+ */
+ MOBILE_SPEC(0, 0),
+ /**
+ * Listen for wifi network state events
+ */
+ WIFI_SPEC(1, 1),
+ /**
+ * Listen for bluetooth (tethered pan) network events
+ */
+ BLUETOOTH_SPEC(7, 2),
+
+ /**
+ * Listen for VPN network events
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ VPN_SPEC(17, NetworkCapabilities.TRANSPORT_VPN),
+ /**
+ * Listen for ethernet network events
+ */
+ ETHERNET_SPEC(9, 3),
+
+ /**
+ * Listen for any network connection
+ */
+ ANY_SPEC(-1, -1);
+
+ NetworkSpecs(int legacy, int v21) {
+ legacyType = legacy;
+ v21Type = v21;
+ }
+
+ final int legacyType, v21Type;
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkState.java b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkState.java
new file mode 100644
index 0000000..f4aa4e3
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/NetworkState.java
@@ -0,0 +1,11 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.content.Context;
+
+import lib.gintec_rdl.network_state.NetworkStateException;
+
+public interface NetworkState {
+ static NetworkSpec.Builder of(NetworkSpecs specs, Context context) throws NetworkStateException {
+ return new NetworkSpec.Builder(context, specs);
+ }
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/network/V21NetworkChangeListener.java b/app/src/main/java/lib/gintec_rdl/network_state/network/V21NetworkChangeListener.java
new file mode 100644
index 0000000..819ace1
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/network/V21NetworkChangeListener.java
@@ -0,0 +1,95 @@
+package lib.gintec_rdl.network_state.network;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.os.Build;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+final class V21NetworkChangeListener extends ConnectivityManager.NetworkCallback implements NetworkChangeListener {
+ private final NetworkSpec networkSpec;
+ private final NetworkRequest networkRequest;
+
+ private boolean registered;
+
+ V21NetworkChangeListener(NetworkSpec networkSpec) {
+ this.networkSpec = networkSpec;
+ NetworkRequest.Builder builder;
+ if (networkSpec.builder.v21NetworkType == NetworkSpecs.ANY_SPEC.v21Type) {
+ builder = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ } else {
+ builder = new NetworkRequest.Builder()
+ .addTransportType(networkSpec.builder.v21NetworkType);
+ }
+
+ this.networkRequest = builder
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .build();
+ }
+
+ @Override
+ public void onAvailable(Network network) {
+ callback(networkSpec.builder.whenAvailable, networkSpec);
+ }
+
+ @Override
+ public void onLosing(Network network, int maxMsToLive) {
+ callback(networkSpec.builder.whenLosing, networkSpec);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ callback(networkSpec.builder.whenLost, networkSpec);
+ }
+
+ @Override
+ public void onUnavailable() {
+ callback(networkSpec.builder.whenNotAvailable, networkSpec);
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+ // TODO Dispatch caps change event
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
+ // TODO Dispatch link change event
+ }
+
+ @Override
+ public void registerSelf(Context context) {
+ synchronized (this) {
+ getConnectivityManager(context).requestNetwork(networkRequest, this);
+ registered = true;
+ }
+ }
+
+ @Override
+ public void unregisterSelf(Context context) {
+ synchronized (this) {
+ getConnectivityManager(context).unregisterNetworkCallback(this);
+ registered = false;
+ }
+ }
+
+ private ConnectivityManager getConnectivityManager(Context c) {
+ return (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ @Override
+ public boolean isRegistered() {
+ synchronized (this) {
+ return registered;
+ }
+ }
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/utils/LangUtils.java b/app/src/main/java/lib/gintec_rdl/network_state/utils/LangUtils.java
new file mode 100644
index 0000000..b92c0ed
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/utils/LangUtils.java
@@ -0,0 +1,24 @@
+package lib.gintec_rdl.network_state.utils;
+
+import androidx.annotation.Nullable;
+
+public final class LangUtils {
+ private LangUtils() {
+ }
+
+ public static class Optional {
+ private final T value;
+
+ private Optional(T value) {
+ this.value = value;
+ }
+
+ public T orElse(T ifNull) {
+ return value != null ? value : ifNull;
+ }
+
+ public static Optional of(@Nullable T value) {
+ return new Optional<>(value);
+ }
+ }
+}
diff --git a/app/src/main/java/lib/gintec_rdl/network_state/utils/PlatformUtils.java b/app/src/main/java/lib/gintec_rdl/network_state/utils/PlatformUtils.java
new file mode 100644
index 0000000..accbee0
--- /dev/null
+++ b/app/src/main/java/lib/gintec_rdl/network_state/utils/PlatformUtils.java
@@ -0,0 +1,12 @@
+package lib.gintec_rdl.network_state.utils;
+
+import android.os.Build;
+
+public final class PlatformUtils {
+ private PlatformUtils() {
+ }
+
+ public static boolean isLollipop() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..485bbd3
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..7ca0909
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_example.xml b/app/src/main/res/layout/activity_example.xml
new file mode 100644
index 0000000..8cab9d7
--- /dev/null
+++ b/app/src/main/res/layout/activity_example.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c77a1be
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ networkSpec-state
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/lib/gintec_rdl/network_state/ExampleUnitTest.java b/app/src/test/java/lib/gintec_rdl/network_state/ExampleUnitTest.java
new file mode 100644
index 0000000..4e68f3d
--- /dev/null
+++ b/app/src/test/java/lib/gintec_rdl/network_state/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package lib.gintec_rdl.network_state;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..458d06a
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.2'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..199d16e
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e20f54b
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Oct 20 05:22:36 CAT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'