diff --git a/NucuHub.Android/.gitignore b/NucuHub.Android/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/NucuHub.Android/.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 +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/NucuHub.Android/app/.gitignore b/NucuHub.Android/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/NucuHub.Android/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/NucuHub.Android/app/build.gradle b/NucuHub.Android/app/build.gradle new file mode 100644 index 0000000..6d6215a --- /dev/null +++ b/NucuHub.Android/app/build.gradle @@ -0,0 +1,63 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.google.protobuf' + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.2" + + defaultConfig { + applicationId "dev.nuculabs.nucuhub" + minSdkVersion 29 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +protobuf { + protoc { artifact = 'com.google.protobuf:protoc:3.12.0' } + plugins { + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.33.1' // CURRENT_GRPC_VERSION + } + } + generateProtoTasks { + all().each { task -> + task.builtins { + java { option 'lite' } + } + task.plugins { + grpc { // Options added to --grpc_out + option 'lite' } + } + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.navigation:navigation-fragment:2.1.0' + implementation 'androidx.navigation:navigation-ui:2.1.0' + implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + // You need to build grpc-java to obtain these libraries below. + implementation 'io.grpc:grpc-okhttp:1.33.1' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.33.1' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.33.1' // CURRENT_GRPC_VERSION + compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ + +} \ No newline at end of file diff --git a/NucuHub.Android/app/proguard-rules.pro b/NucuHub.Android/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/NucuHub.Android/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 \ No newline at end of file diff --git a/NucuHub.Android/app/src/androidTest/java/dev/nuculabs/nucuhub/ExampleInstrumentedTest.java b/NucuHub.Android/app/src/androidTest/java/dev/nuculabs/nucuhub/ExampleInstrumentedTest.java new file mode 100644 index 0000000..5b2dc96 --- /dev/null +++ b/NucuHub.Android/app/src/androidTest/java/dev/nuculabs/nucuhub/ExampleInstrumentedTest.java @@ -0,0 +1,25 @@ +package dev.nuculabs.nucuhub; + +import android.content.Context; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("dev.nuculabs.nucuhub", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/AndroidManifest.xml b/NucuHub.Android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0979990 --- /dev/null +++ b/NucuHub.Android/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorData.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorData.java new file mode 100644 index 0000000..e63704f --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorData.java @@ -0,0 +1,54 @@ +package dev.nuculabs.grpc; + +import NucuCarSensorsProto.NucuCarSensors; +import android.util.Log; +import org.json.JSONException; +import org.json.JSONObject; + +public class EnvironmentSensorData { + @SuppressWarnings("FieldCanBeLocal") + private final String TAG = EnvironmentSensorData.class.getName(); + private double temperature; + private double humidity; + private double pressure; + private double volatileOrganicCompounds; + private NucuCarSensors.SensorStateEnum sensorState; + + public EnvironmentSensorData(String data, NucuCarSensors.SensorStateEnum state) { + try { + JSONObject json = new JSONObject(data); + temperature = json.getDouble("Temperature"); + humidity = json.getDouble("Humidity"); + pressure = json.getDouble("Pressure"); + volatileOrganicCompounds = json.getDouble("VolatileOrganicCompounds"); + sensorState = state; + } catch (JSONException e) { + Log.e(TAG, e.getLocalizedMessage()); + temperature = -1; + humidity = -1; + pressure = -1; + volatileOrganicCompounds = -1; + sensorState = NucuCarSensors.SensorStateEnum.Error; + } + } + + public NucuCarSensors.SensorStateEnum getSensorState() { + return sensorState; + } + + public double getTemperature() { + return temperature; + } + + public double getHumidity() { + return humidity; + } + + public double getPressure() { + return pressure; + } + + public double getVolatileOrganicCompounds() { + return volatileOrganicCompounds; + } +} diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorService.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorService.java new file mode 100644 index 0000000..91208d4 --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/grpc/EnvironmentSensorService.java @@ -0,0 +1,64 @@ +package dev.nuculabs.grpc; + +import NucuCarSensorsProto.EnvironmentSensorGrpcServiceGrpc; +import NucuCarSensorsProto.NucuCarSensors; +import android.util.Log; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; + +import java.util.Locale; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; + +import static java.util.concurrent.TimeUnit.SECONDS; + + +public class EnvironmentSensorService { + private final String TAG = EnvironmentSensorService.class.getName(); + private final ManagedChannel channel; + private final EnvironmentSensorGrpcServiceGrpc.EnvironmentSensorGrpcServiceBlockingStub blockingStub; + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + private ScheduledFuture periodicGrpcRequestHandle = null; + private EnvironmentSensorData lastMeasurementData = new EnvironmentSensorData("{}", NucuCarSensors.SensorStateEnum.Uninitialized); + + public EnvironmentSensorService(String host, int port) { + this(ManagedChannelBuilder.forAddress(host, port).usePlaintext()); + Log.i(TAG, String.format(Locale.ENGLISH, "Initializing channel host=%s port=%d", host, port)); + } + + public EnvironmentSensorService(ManagedChannelBuilder channelBuilder) { + channel = channelBuilder.build(); + blockingStub = EnvironmentSensorGrpcServiceGrpc.newBlockingStub(channel); + } + + public void start() { + final Runnable grpcPoolingTask = new Runnable() { + public void run() { + lastMeasurementData = getMeasurement(); + } + }; + periodicGrpcRequestHandle = scheduler.scheduleAtFixedRate(grpcPoolingTask, 5, 10, SECONDS); + } + + public void stop() { + periodicGrpcRequestHandle.cancel(true); + } + + public EnvironmentSensorData getLastMeasurementData() { + return lastMeasurementData; + } + + private EnvironmentSensorData getMeasurement() { + try { + NucuCarSensors.NucuCarSensorResponse response = null; + response = blockingStub.getMeasurement(null); + Log.d(TAG, "getMeasurement " + response.getJsonData()); + return new EnvironmentSensorData(response.getJsonData(), response.getState()); + } catch (StatusRuntimeException e) { + Log.e(TAG, e.getLocalizedMessage()); + return new EnvironmentSensorData("{}", NucuCarSensors.SensorStateEnum.Error); + } + } +} diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/MainActivity.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/MainActivity.java new file mode 100644 index 0000000..9fc78c3 --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/MainActivity.java @@ -0,0 +1,53 @@ +package dev.nuculabs.nucuhub; + +import android.os.Bundle; +import android.view.Menu; +import com.google.android.material.navigation.NavigationView; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; +import androidx.navigation.ui.AppBarConfiguration; +import androidx.navigation.ui.NavigationUI; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +public class MainActivity extends AppCompatActivity { + + private AppBarConfiguration mAppBarConfiguration; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + DrawerLayout drawer = findViewById(R.id.drawer_layout); + NavigationView navigationView = findViewById(R.id.nav_view); + // Passing each menu ID as a set of Ids because each + // menu should be considered as top level destinations. + mAppBarConfiguration = new AppBarConfiguration.Builder( + R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow) + .setDrawerLayout(drawer) + .build(); + + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); + NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); + NavigationUI.setupWithNavController(navigationView, navController); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onSupportNavigateUp() { + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); + return NavigationUI.navigateUp(navController, mAppBarConfiguration) + || super.onSupportNavigateUp(); + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryFragment.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryFragment.java new file mode 100644 index 0000000..091532c --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryFragment.java @@ -0,0 +1,33 @@ +package dev.nuculabs.nucuhub.ui.gallery; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import dev.nuculabs.nucuhub.R; + +public class GalleryFragment extends Fragment { + + private GalleryViewModel galleryViewModel; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + galleryViewModel = + ViewModelProviders.of(this).get(GalleryViewModel.class); + View root = inflater.inflate(R.layout.fragment_gallery, container, false); + final TextView textView = root.findViewById(R.id.text_gallery); + galleryViewModel.getText().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(@Nullable String s) { + textView.setText(s); + } + }); + return root; + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryViewModel.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryViewModel.java new file mode 100644 index 0000000..3cd51c5 --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/gallery/GalleryViewModel.java @@ -0,0 +1,19 @@ +package dev.nuculabs.nucuhub.ui.gallery; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class GalleryViewModel extends ViewModel { + + private MutableLiveData mText; + + public GalleryViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is gallery fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/EnvironmentSensorViewModel.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/EnvironmentSensorViewModel.java new file mode 100644 index 0000000..fc9b8b4 --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/EnvironmentSensorViewModel.java @@ -0,0 +1,43 @@ +package dev.nuculabs.nucuhub.ui.sensors; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import dev.nuculabs.nucuhub.R; + +public class EnvironmentSensorViewModel extends ViewModel { + + private MutableLiveData sensorStatusImageTooltip; + private MutableLiveData sensorStatusImageResourceId; + + public EnvironmentSensorViewModel() { + sensorStatusImageResourceId = new MutableLiveData<>(); + sensorStatusImageResourceId.setValue(R.drawable.no_signal); + sensorStatusImageTooltip = new MutableLiveData<>(); + } + + public LiveData getSensorStatusImageResourceId() { + return sensorStatusImageResourceId; + } + + public LiveData getSensorStatusImageTooltip() { + Integer sensorStatusImageResourceId = this.sensorStatusImageResourceId.getValue(); + if (sensorStatusImageResourceId == null) { + sensorStatusImageResourceId = -1; + } + + switch (sensorStatusImageResourceId) { + case R.drawable.status_good: + sensorStatusImageTooltip.setValue("The air quality is good."); + case R.drawable.status_netural: + sensorStatusImageTooltip.setValue("The air quality is not great, not terrible."); + case R.drawable.status_bad: + sensorStatusImageTooltip.setValue("The air quality is bad."); + case R.drawable.no_signal: + default: + sensorStatusImageTooltip.setValue("No signal. Please ensure device is connected!"); + break; + } + return sensorStatusImageTooltip; + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/SensorsFragment.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/SensorsFragment.java new file mode 100644 index 0000000..a8cd871 --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/sensors/SensorsFragment.java @@ -0,0 +1,59 @@ +package dev.nuculabs.nucuhub.ui.sensors; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import dev.nuculabs.grpc.EnvironmentSensorService; +import dev.nuculabs.nucuhub.R; + +import java.util.logging.Logger; + +public class SensorsFragment extends Fragment { + private static final Logger logger = Logger.getLogger(SensorsFragment.class.getName()); + private View root; + private EnvironmentSensorViewModel environmentSensorViewModel; + + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + environmentSensorViewModel = ViewModelProviders.of(this).get(EnvironmentSensorViewModel.class); + root = inflater.inflate(R.layout.fragment_environment_sensor, container, false); + + // test button TODO: Investigate lifecycle methods and stop/start the scheduler accordingly. + Button testButton = root.findViewById(R.id.grpc_test_button); + final EnvironmentSensorService client = new EnvironmentSensorService("192.168.0.101", 8000); + client.start(); + testButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + logger.info("test button clicked!"); + client.stop(); + } + }); + + setupSensorStatusImage(); + return root; + } + + + private void setupSensorStatusImage() { + // Dynamically observe the image of the sensor status image view. + final ImageView sensorStatusImageView = root.findViewById(R.id.sensorStatusImageView); + environmentSensorViewModel.getSensorStatusImageResourceId().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Integer resourceId) { + sensorStatusImageView.setImageResource(resourceId); + } + }); + environmentSensorViewModel.getSensorStatusImageTooltip().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(String tooltip) { + sensorStatusImageView.setTooltipText(tooltip); + } + }); + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowFragment.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowFragment.java new file mode 100644 index 0000000..f59d10c --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowFragment.java @@ -0,0 +1,33 @@ +package dev.nuculabs.nucuhub.ui.slideshow; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import dev.nuculabs.nucuhub.R; + +public class SlideshowFragment extends Fragment { + + private SlideshowViewModel slideshowViewModel; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + slideshowViewModel = + ViewModelProviders.of(this).get(SlideshowViewModel.class); + View root = inflater.inflate(R.layout.fragment_slideshow, container, false); + final TextView textView = root.findViewById(R.id.text_slideshow); + slideshowViewModel.getText().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(@Nullable String s) { + textView.setText(s); + } + }); + return root; + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowViewModel.java b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowViewModel.java new file mode 100644 index 0000000..633af2c --- /dev/null +++ b/NucuHub.Android/app/src/main/java/dev/nuculabs/nucuhub/ui/slideshow/SlideshowViewModel.java @@ -0,0 +1,19 @@ +package dev.nuculabs.nucuhub.ui.slideshow; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class SlideshowViewModel extends ViewModel { + + private MutableLiveData mText; + + public SlideshowViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is slideshow fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/proto/NucuCarSensors.proto b/NucuHub.Android/app/src/main/proto/NucuCarSensors.proto new file mode 100644 index 0000000..55ec222 --- /dev/null +++ b/NucuHub.Android/app/src/main/proto/NucuCarSensors.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +import "google/protobuf/empty.proto"; + +package NucuCarSensorsProto; + +// General +enum SensorStateEnum { + Error = 0; + Uninitialized = 1; + Initialized = 2; + Disabled = 3; + GrpcDisabled = 4; +} + +// Environment Sensor +service EnvironmentSensorGrpcService { + rpc GetMeasurement(google.protobuf.Empty) returns (NucuCarSensorResponse) {} +} + +// Health Sensor +service HealthSensorGrpcService { + rpc GetCpuTemperature(google.protobuf.Empty) returns (NucuCarSensorResponse) {} +} + +// Responses +message NucuCarSensorResponse { + SensorStateEnum State = 1; + string JsonData = 2; +} \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/NucuHub.Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1ee1493 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/drawable/ic_launcher_background.xml b/NucuHub.Android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..956b344 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NucuHub.Android/app/src/main/res/drawable/ic_menu_camera.xml b/NucuHub.Android/app/src/main/res/drawable/ic_menu_camera.xml new file mode 100644 index 0000000..41688d5 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable/ic_menu_camera.xml @@ -0,0 +1,12 @@ + + + + diff --git a/NucuHub.Android/app/src/main/res/drawable/ic_menu_gallery.xml b/NucuHub.Android/app/src/main/res/drawable/ic_menu_gallery.xml new file mode 100644 index 0000000..ff8ce52 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable/ic_menu_gallery.xml @@ -0,0 +1,9 @@ + + + diff --git a/NucuHub.Android/app/src/main/res/drawable/ic_menu_slideshow.xml b/NucuHub.Android/app/src/main/res/drawable/ic_menu_slideshow.xml new file mode 100644 index 0000000..ae51e49 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable/ic_menu_slideshow.xml @@ -0,0 +1,9 @@ + + + diff --git a/NucuHub.Android/app/src/main/res/drawable/no_signal.png b/NucuHub.Android/app/src/main/res/drawable/no_signal.png new file mode 100644 index 0000000..c4b7423 Binary files /dev/null and b/NucuHub.Android/app/src/main/res/drawable/no_signal.png differ diff --git a/NucuHub.Android/app/src/main/res/drawable/side_nav_bar.xml b/NucuHub.Android/app/src/main/res/drawable/side_nav_bar.xml new file mode 100644 index 0000000..a33798b --- /dev/null +++ b/NucuHub.Android/app/src/main/res/drawable/side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/drawable/status_bad.png b/NucuHub.Android/app/src/main/res/drawable/status_bad.png new file mode 100644 index 0000000..e6f489c Binary files /dev/null and b/NucuHub.Android/app/src/main/res/drawable/status_bad.png differ diff --git a/NucuHub.Android/app/src/main/res/drawable/status_good.png b/NucuHub.Android/app/src/main/res/drawable/status_good.png new file mode 100644 index 0000000..7e047eb Binary files /dev/null and b/NucuHub.Android/app/src/main/res/drawable/status_good.png differ diff --git a/NucuHub.Android/app/src/main/res/drawable/status_netural.png b/NucuHub.Android/app/src/main/res/drawable/status_netural.png new file mode 100644 index 0000000..2098f0c Binary files /dev/null and b/NucuHub.Android/app/src/main/res/drawable/status_netural.png differ diff --git a/NucuHub.Android/app/src/main/res/layout/activity_main.xml b/NucuHub.Android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..e572953 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/layout/app_bar_main.xml b/NucuHub.Android/app/src/main/res/layout/app_bar_main.xml new file mode 100644 index 0000000..e87580d --- /dev/null +++ b/NucuHub.Android/app/src/main/res/layout/app_bar_main.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/layout/content_main.xml b/NucuHub.Android/app/src/main/res/layout/content_main.xml new file mode 100644 index 0000000..e1e04b1 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/layout/content_main.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/NucuHub.Android/app/src/main/res/layout/fragment_environment_sensor.xml b/NucuHub.Android/app/src/main/res/layout/fragment_environment_sensor.xml new file mode 100644 index 0000000..2cc9746 --- /dev/null +++ b/NucuHub.Android/app/src/main/res/layout/fragment_environment_sensor.xml @@ -0,0 +1,30 @@ + + + +