commit 0dfa2a50cacbd269e3de311b4a5ddf161d49037a Author: Ramandeep Date: Fri Feb 25 16:33:45 2022 +0530 Reader App diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.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 +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b3405b3 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +My Application \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..5cd135a --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..958a5be --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6199cc2 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..e8fa30f --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +/build +*.iml diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f39a873 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,128 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' + + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + applicationId "no.Reader.android.iisc" + + minSdkVersion 18 + targetSdkVersion 29 + versionCode 78 + versionName "2.9.0" + resConfigs "en" + multiDexEnabled true + + + vectorDrawables.useSupportLibrary = true + } + buildTypes { + debug { + minifyEnabled false + shrinkResources false + + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + // nRF Toolbox is using Play Service 10.2.0 in order to make the app working in China: + // https://developer.android.com/training/wearables/apps/creating-app-china.html + //noinspection GradleDependency + implementation 'com.google.android.gms:play-services-wearable:10.2.0' + + implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' + implementation 'androidx.preference:preference:1.1.1' + implementation 'de.hdodenhof:circleimageview:3.1.0' + + implementation 'no.nordicsemi.android:log:2.2.0' + implementation 'no.nordicsemi.android.support.v18:scanner:1.4.3' + implementation 'org.apache.poi:poi:4.0.0' + implementation 'org.apache.poi:poi-ooxml:4.0.0' + implementation 'com.android.support:multidex:1.0.1' + + // The DFU Library is imported automatically from jcenter: + implementation 'no.nordicsemi.android:dfu:1.10.3' + implementation 'com.github.PhilJay:MPAndroidChart:v2.2.4' + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' + + + implementation 'com.hbb20:ccp:2.4.0' + implementation 'androidx.preference:preference:1.1.0-alpha04' + implementation 'com.google.android.material:material:1.1.0-alpha05' + implementation 'com.google.android.material:material:1.1.0' + + implementation 'com.google.firebase:firebase-database:16.0.4' + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' + + implementation 'com.google.firebase:firebase-auth:16.0.5' + + + implementation 'androidx.preference:preference:1.1.0-alpha04' + + implementation 'no.nordicsemi.android:log:2.2.0' + implementation 'com.chaos.view:pinview:1.4.3' + implementation "androidx.browser:browser:1.3.0" + + + implementation 'com.github.bumptech.glide:glide:4.11.0' + implementation 'com.firebaseui:firebase-ui-database:7.1.1' + implementation 'com.github.PhilJay:MPAndroidChart:v2.2.4' + + implementation 'com.google.firebase:firebase-crashlytics:17.1.1' + + implementation 'com.hbb20:ccp:2.4.0' + + implementation 'com.google.firebase:firebase-auth:20.0.1' + + implementation 'com.google.android.material:material:1.0.0' + + + + + + + + implementation 'com.google.firebase:firebase-storage:16.0.4' + + // if you desire to build the DFU Library, clone the + // https://github.com/NordicSemiconductor/Android-DFU-Library project into DFULibrary folder, + // add it as a module into the project structure and uncomment the following line + // (and also the according lines in the settings.gradle): + // implementation project(':dfu') + + // Gson is needed for DFU to work. The DFU library dependency to Gson is internal and would + // not be attached to APK. + // See: https://github.com/NordicSemiconductor/Android-nRF-Toolbox/issues/86 + + // Import the BLE Common Library. + // The BLE Common Library depends on BLE Library. It is enough to include the first one. + implementation 'no.nordicsemi.android:ble-common:2.1.1' + // The BLE Common Library may be included from jcenter. If you want to modify the code, + // clone both projects from GitHub and replace the line above with the following + // (and also the according lines in the settings.gradle): + // implementation project(':ble-common') + + implementation('org.simpleframework:simple-xml:2.7.1') { + exclude group: 'stax', module: 'stax-api' + exclude group: 'xpp3', module: 'xpp3' + } +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..264ee77 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,48 @@ +{ + "project_info": { + "project_number": "168819095878", + "firebase_url": "https://reader-app-43cb6-default-rtdb.firebaseio.com", + "project_id": "reader-app-43cb6", + "storage_bucket": "reader-app-43cb6.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:168819095878:android:9d4989cee1616d1a444d47", + "android_client_info": { + "package_name": "no.Reader.android.iisc" + } + }, + "oauth_client": [ + { + "client_id": "168819095878-f1d70oknl1g9l4sbrrlb6eniqchmtgb7.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "no.Reader.android.iisc", + "certificate_hash": "cd10342afabfcce43c9dc370cf20c4c2d6e1b1dd" + } + }, + { + "client_id": "168819095878-7a1tejv9lv3o144c9v5fj6bls8vi2soc.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCdG2nyJYp-71n67JtjsfKJCS00XUzKFQk" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "168819095878-7a1tejv9lv3o144c9v5fj6bls8vi2soc.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/libs/achartengine-1.2.0.jar b/app/libs/achartengine-1.2.0.jar new file mode 100644 index 0000000..21fe13d Binary files /dev/null and b/app/libs/achartengine-1.2.0.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..6f9aa2c --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,81 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontskipnonpubliclibraryclassmembers +-dontpreverify +-dontshrink +-verbose + +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keepattributes *Annotation* +-keepattributes Signature + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +# The AndroidX library contains references to newer platform versions. +# Don't warn about those in case this app is linking against an older platform version. +-dontwarn androidx.** + +-keep class com.google.android.gms.** +-dontwarn com.google.android.gms.** + +# Java +-keep class java.** { *; } +-dontnote java.** +-dontwarn java.** + +-keep class javax.** { *; } +-dontnote javax.** +-dontwarn javax.** + +-keep class sun.misc.Unsafe { *; } +-dontnote sun.misc.Unsafe + +-keep class javax.xml.stream.XMLOutputFactory { *; } + +# (the rt.jar has them) +-dontwarn com.bea.xml.stream.XMLWriterBase +-dontwarn javax.xml.stream.events.** +-dontwarn javax.xml.stream.** + +# Simple XML +-keep public class org.simpleframework.** { *; } +-keep class org.simpleframework.xml.** { *; } +-keep class org.simpleframework.xml.core.** { *; } +-keep class org.simpleframework.xml.util.** { *; } + +-keepattributes ElementList, Root, InnerClasses, LineNumberTable + +-keepclasseswithmembers class * { + @org.simpleframework.xml.* ; +} + +# Chart Engine +-keep class org.achartengine.** { *; } +-dontnote org.achartengine.** + +# HTTP (might require legacyLibraries) ? +-dontnote org.apache.http.params.** +-dontnote org.apache.http.conn.scheme.** +-dontnote org.apache.http.conn.** +-dontnote android.net.http.** + +# DFU Library +-keep class no.nordicsemi.android.dfu.** { *; } + diff --git a/app/src/androidTest/java/no/Reader/android/iisc/ApplicationTest.java b/app/src/androidTest/java/no/Reader/android/iisc/ApplicationTest.java new file mode 100644 index 0000000..dc90620 --- /dev/null +++ b/app/src/androidTest/java/no/Reader/android/iisc/ApplicationTest.java @@ -0,0 +1,13 @@ +package no.Reader.android.iisc; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5e3502 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fa-solid-900.ttf b/app/src/main/assets/fa-solid-900.ttf new file mode 100644 index 0000000..7c59512 Binary files /dev/null and b/app/src/main/assets/fa-solid-900.ttf differ diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..1c52cad Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/no/Reader/android/iisc/DebugLogger.java b/app/src/main/java/no/Reader/android/iisc/DebugLogger.java new file mode 100644 index 0000000..3438d5a --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/DebugLogger.java @@ -0,0 +1,50 @@ +package no.Reader.android.iisc; + +import android.util.Log; + + +public class DebugLogger { + public static void v(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.v(tag, text); + } + + public static void d(final String tag, final String text) { + if (BuildConfig.DEBUG) { + Log.d(tag, text); + } + } + + public static void i(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.i(tag, text); + } + + public static void w(final String tag, final String text) { + if (BuildConfig.DEBUG) { + Log.w(tag, text); + } + } + + public static void e(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.e(tag, text); + } + + public static void e(final String tag, final String text, final Throwable e) { + if (BuildConfig.DEBUG) + Log.e(tag, text, e); + } + + public static void wtf(final String tag, final String text) { + if (BuildConfig.DEBUG) { + Log.wtf(tag, text); + } + } + + public static void wtf(final String tag, final String text, final Throwable e) { + if (BuildConfig.DEBUG) { + Log.wtf(tag, text, e); + } + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/FeaturesActivity.java b/app/src/main/java/no/Reader/android/iisc/FeaturesActivity.java new file mode 100644 index 0000000..7b3754e --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/FeaturesActivity.java @@ -0,0 +1,169 @@ +package no.Reader.android.iisc; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.view.View; +import android.widget.GridView; +import android.widget.Toast; + +import no.Reader.android.iisc.adapter.AppAdapter; + +public class FeaturesActivity extends AppCompatActivity { + private static final String NRF_CONNECT_CATEGORY = "no.Reader.android.iisc.LAUNCHER"; + private static final String UTILS_CATEGORY = "no.Reader.android.iisc.UTILS"; + private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp"; + private static final String NRF_CONNECT_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity"; + private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp"; + + // Extras that can be passed from NFC (see SplashscreenActivity) + public static final String EXTRA_APP = "application/vnd.no.nordicsemi.type.app"; + public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address"; + + private DrawerLayout mDrawerLayout; + private ActionBarDrawerToggle mDrawerToggle; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_features); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + + // ensure that Bluetooth exists + if (!ensureBLEExists()) + finish(); + + final DrawerLayout drawer = mDrawerLayout = findViewById(R.id.drawer_layout); + drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + + // Set the drawer toggle as the DrawerListener + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) { + @Override + public void onDrawerSlide(final View drawerView, final float slideOffset) { + // Disable the Hamburger icon animation + super.onDrawerSlide(drawerView, 0); + } + }; + drawer.addDrawerListener(mDrawerToggle); + + // setup plug-ins in the drawer + //setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container)); + + // configure the app grid + final GridView grid = findViewById(R.id.grid); + grid.setAdapter(new AppAdapter(this)); + grid.setEmptyView(findViewById(android.R.id.empty)); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + final Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_APP) && intent.hasExtra(EXTRA_ADDRESS)) { + final String app = intent.getStringExtra(EXTRA_APP); + switch (app) { + /*case "HRM": + final Intent newIntent = new Intent(this, HRSActivity.class); + newIntent.putExtra(EXTRA_ADDRESS, intent.getByteArrayExtra(EXTRA_ADDRESS)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivity(newIntent); + break;*/ + default: + // other are not supported yet + break; + } + } + } + + + + @Override + protected void onPostCreate(final Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + // Sync the toggle state after onRestoreInstanceState has occurred. + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(@NonNull final Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDrawerToggle.onConfigurationChanged(newConfig); + } + + + + /* + private void setupPluginsInDrawer(final ViewGroup container) { + final LayoutInflater inflater = LayoutInflater.from(this); + final PackageManager pm = getPackageManager(); + + // look for nRF Connect + final Intent nrfConnectIntent = new Intent(Intent.ACTION_MAIN); + nrfConnectIntent.addCategory(NRF_CONNECT_CATEGORY); + nrfConnectIntent.setClassName(NRF_CONNECT_PACKAGE, NRF_CONNECT_CLASS); + final ResolveInfo nrfConnectInfo = pm.resolveActivity(nrfConnectIntent, 0); + + // configure link to nRF Connect + final TextView nrfConnectItem = container.findViewById(R.id.link_mcp); + if (nrfConnectInfo == null) { + nrfConnectItem.setTextColor(Color.GRAY); + final ColorMatrix grayscale = new ColorMatrix(); + grayscale.setSaturation(0.0f); + nrfConnectItem.getCompoundDrawables()[0].mutate().setColorFilter(new ColorMatrixColorFilter(grayscale)); + } + nrfConnectItem.setOnClickListener(v -> { + Intent action = nrfConnectIntent; + if (nrfConnectInfo == null) + action = new Intent(Intent.ACTION_VIEW, Uri.parse(NRF_CONNECT_MARKET_URI)); + action.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + startActivity(action); + } catch (final ActivityNotFoundException e) { + Toast.makeText(FeaturesActivity.this, R.string.no_application_play, Toast.LENGTH_SHORT).show(); + } + mDrawerLayout.closeDrawers(); + }); + + // look for other plug-ins + final Intent utilsIntent = new Intent(Intent.ACTION_MAIN); + utilsIntent.addCategory(UTILS_CATEGORY); + + final List appList = pm.queryIntentActivities(utilsIntent, 0); + for (final ResolveInfo info : appList) { + final View item = inflater.inflate(R.layout.drawer_plugin, container, false); + final ImageView icon = item.findViewById(android.R.id.icon); + final TextView label = item.findViewById(android.R.id.text1); + + label.setText(info.loadLabel(pm)); + icon.setImageDrawable(info.loadIcon(pm)); + item.setOnClickListener(v -> { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + mDrawerLayout.closeDrawers(); + }); + container.addView(item); + } + } + */ + + private boolean ensureBLEExists() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + return false; + } + return true; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/FontAwesome.java b/app/src/main/java/no/Reader/android/iisc/FontAwesome.java new file mode 100644 index 0000000..b6d9cb7 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/FontAwesome.java @@ -0,0 +1,35 @@ +package no.Reader.android.iisc; + + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +public class FontAwesome extends AppCompatTextView { + + + public FontAwesome(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public FontAwesome(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FontAwesome(Context context) { + super(context); + init(); + } + + private void init() { + + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), + "fa-solid-900.ttf"); + setTypeface(tf); + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/NotificationData.java b/app/src/main/java/no/Reader/android/iisc/NotificationData.java new file mode 100644 index 0000000..ab0c4e1 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/NotificationData.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.Reader.android.iisc; + +import android.app.Application; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +import no.nordicsemi.android.dfu.DfuServiceInitiator; + +public class NotificationData extends Application { + public static final String CONNECTED_DEVICE_CHANNEL = "connected_device_channel"; + public static final String FILE_SAVED_CHANNEL = "file_saved_channel"; + public static final String PROXIMITY_WARNINGS_CHANNEL = "proximity_warnings_channel"; + + @Override + + + public void onCreate() { + super.onCreate(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + DfuServiceInitiator.createDfuNotificationChannel(this); + + final NotificationChannel channel = new NotificationChannel(CONNECTED_DEVICE_CHANNEL, getString(R.string.channel_connected_devices_title), NotificationManager.IMPORTANCE_LOW); + channel.setDescription(getString(R.string.channel_connected_devices_description)); + channel.setShowBadge(false); + channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); + + final NotificationChannel fileChannel = new NotificationChannel(FILE_SAVED_CHANNEL, getString(R.string.channel_files_title), NotificationManager.IMPORTANCE_LOW); + fileChannel.setDescription(getString(R.string.channel_files_description)); + fileChannel.setShowBadge(false); + fileChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); + + final NotificationChannel proximityChannel = new NotificationChannel(PROXIMITY_WARNINGS_CHANNEL, getString(R.string.channel_proximity_warnings_title), NotificationManager.IMPORTANCE_LOW); + proximityChannel.setDescription(getString(R.string.channel_proximity_warnings_description)); + proximityChannel.setShowBadge(false); + proximityChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); + + final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.createNotificationChannel(channel); + notificationManager.createNotificationChannel(fileChannel); + notificationManager.createNotificationChannel(proximityChannel); + } + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/PermissionRationaleFragment.java b/app/src/main/java/no/Reader/android/iisc/PermissionRationaleFragment.java new file mode 100644 index 0000000..c74aabb --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/PermissionRationaleFragment.java @@ -0,0 +1,58 @@ +package no.Reader.android.iisc; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.appcompat.app.AlertDialog; + + +public class PermissionRationaleFragment extends DialogFragment { + private static final String ARG_PERMISSION = "ARG_PERMISSION"; + private static final String ARG_TEXT = "ARG_TEXT"; + + private PermissionDialogListener mListener; + + public interface PermissionDialogListener { + void onRequestPermission(final String permission); + } + + @Override + public void onAttach(final Context context) { + super.onAttach(context); + + if (context instanceof PermissionDialogListener) { + mListener = (PermissionDialogListener) context; + } else { + throw new IllegalArgumentException("The parent activity must impelemnt PermissionDialogListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + public static PermissionRationaleFragment getInstance(final int aboutResId, final String permission) { + final PermissionRationaleFragment fragment = new PermissionRationaleFragment(); + + final Bundle args = new Bundle(); + args.putInt(ARG_TEXT, aboutResId); + args.putString(ARG_PERMISSION, permission); + fragment.setArguments(args); + + return fragment; + } + + @Override + @NonNull + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final Bundle args = getArguments(); + final StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT))); + return new AlertDialog.Builder(getActivity()).setTitle(R.string.permission_title).setMessage(text) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.ok, (dialog, which) -> mListener.onRequestPermission(args.getString(ARG_PERMISSION))).create(); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/About.java b/app/src/main/java/no/Reader/android/iisc/Reader/About.java new file mode 100644 index 0000000..dbf02f8 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/About.java @@ -0,0 +1,24 @@ +package no.Reader.android.iisc.Reader; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import no.Reader.android.iisc.R; + + +public class About extends NavigationTop { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_about, null, false); + draw.addView(contentView, 0); + /* LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_about, null, false); + */ + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/CreatePassword.java b/app/src/main/java/no/Reader/android/iisc/Reader/CreatePassword.java new file mode 100644 index 0000000..fb8d2b8 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/CreatePassword.java @@ -0,0 +1,110 @@ +package no.Reader.android.iisc.Reader; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.Model.RegisterHelper; + + +public class CreatePassword extends AppCompatActivity { + private Button next; + + String name,phonenumber,num1,num2; + private EditText passworddata; + private EditText ConfirmPassword; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create__password); + passworddata=findViewById(R.id.password); + ConfirmPassword=findViewById(R.id.confirmpassword); + next=findViewById(R.id.next); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + num1 = ConfirmPassword.getText().toString(); + num2 = passworddata.getText().toString(); + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(CreatePassword.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + + if (num1.equals(num2)) { + Intent intent = new Intent(CreatePassword.this, LoginScreen.class); + name = getIntent().getStringExtra("username"); + + String phonenumberk = getIntent().getStringExtra("mobile"); + phonenumber = phonenumberk; + + FirebaseDatabase rootNode = FirebaseDatabase.getInstance(); + DatabaseReference reference = rootNode.getReference("USERS"); + RegisterHelper addNewUser = new RegisterHelper(name, phonenumber, num1); + + reference.child(phonenumber).setValue(addNewUser); + intent.putExtra("mobile", phonenumber); + intent.putExtra("username", name); + + Toast.makeText(CreatePassword.this, "You are Registered Successfully ", Toast.LENGTH_SHORT).show(); + startActivity(intent); + + + } else { + ConfirmPassword.setError("Password does not match"); + } + } + } + + }); + + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Datashow.java b/app/src/main/java/no/Reader/android/iisc/Reader/Datashow.java new file mode 100644 index 0000000..4b94c7a --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Datashow.java @@ -0,0 +1,103 @@ +package no.Reader.android.iisc.Reader; + +import android.os.Bundle; + + +import android.content.SharedPreferences; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import no.Reader.android.iisc.Reader.Model.Tests; +import no.Reader.android.iisc.R; + + +public class Datashow extends NavigationTop { + private ImageView Imageview1; + TextView patient_id,patient_dob,patientnikshayid,agepatient,patientgender,patientsample,validatyd,spintubeid,nirtlab,dated,timed,resultd; + + String date,time,number; + + private String TestID = ""; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_datashow, null, false); + draw.addView(contentView, 0); + + patient_id=findViewById(R.id.patient_idr); + patient_dob=findViewById(R.id.patien_dobr); + patientnikshayid=findViewById(R.id.patient_nikshayidr); + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + + agepatient=findViewById(R.id.patient_ager); + date = String.valueOf(android.text.format.DateFormat.format("dd-MM-yyyy", new java.util.Date())); + DateFormat df = new SimpleDateFormat("h:mm a"); + time = df.format(Calendar.getInstance().getTime()); + + patientgender=findViewById(R.id.patient_genderr); + patientsample=findViewById(R.id.patient_typesampler); + validatyd=findViewById(R.id.patient_tubevisibler); + spintubeid=findViewById(R.id.patient_spintuber); + nirtlab=findViewById(R.id.patient_nirtr); + timed=findViewById(R.id.timer); + resultd=findViewById(R.id.patient_resultr); + dated=findViewById(R.id.dater); + + + + + TestID = getIntent().getStringExtra("pid"); + + Log.e("main", "error id "+TestID); + + + getTestDetails(TestID); + } + private void getTestDetails(String TestID) + { + DatabaseReference productsRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + productsRef.child(TestID).addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) + { + if (dataSnapshot.exists()) + { + + + Tests products = dataSnapshot.getValue(Tests.class); + patient_id.setText(products.getTest_Id()); + patient_dob.setText(products.getSample_Date()); + + + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + + } + }); + } + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/FontAwesome.java b/app/src/main/java/no/Reader/android/iisc/Reader/FontAwesome.java new file mode 100644 index 0000000..c5209ce --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/FontAwesome.java @@ -0,0 +1,35 @@ +package no.Reader.android.iisc.Reader; + + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +public class FontAwesome extends AppCompatTextView { + + + public FontAwesome(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public FontAwesome(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FontAwesome(Context context) { + super(context); + init(); + } + + private void init() { + + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), + "fa-solid-900.ttf"); + setTypeface(tf); + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPassword.java b/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPassword.java new file mode 100644 index 0000000..8a906bb --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPassword.java @@ -0,0 +1,260 @@ +package no.Reader.android.iisc.Reader; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskExecutors; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthProvider; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; +import com.hbb20.CountryCodePicker; + +import java.util.concurrent.TimeUnit; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.VerifyOTP.VerifyOtpForgetPassword; + + +public class ForgetPassword extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private int code = 91; + private Button nextactivity; + private ProgressBar progressBar; + CountryCodePicker ccp; + PinView pinFromUser; + String mobile; + + private EditText editTextnumber; + String codeBySystem; + boolean exists; + String address,name, state , city ,pincode,phonenumber,password2,num1,phonenum; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_forget__password); + editTextnumber=findViewById(R.id.editTextMobile); + ccp=findViewById(R.id.ccp); + ccp.registerCarrierNumberEditText(editTextnumber); + // nextactivity = findViewById(R.id.buttonSignIn); + + mAuth = FirebaseAuth.getInstance(); + + + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(ForgetPassword.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + /* //Restart The Activity + Intent intent = getIntent(); + finish(); + startActivity(intent);*/ + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + mobile = editTextnumber.getText().toString().trim(); + mobile = mobile.replaceAll("[^0-9]", ""); + + + phonenum = ccp.getFullNumberWithPlus(); + if(mobile.equals("")) + { + editTextnumber.setError("Enter the contact number"); + } + + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(mobile); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + Intent intent = new Intent(ForgetPassword.this, VerifyOtpForgetPassword.class); + Toast.makeText(ForgetPassword.this, "We Have Sent the OTP to your mentioned Number", Toast.LENGTH_SHORT).show(); + intent.putExtra("mobilecode", phonenum); + intent.putExtra("mobile", mobile); + + startActivity(intent); + + + } else { + // Toast.makeText(ForgetPassword.this,phonenum,Toast.LENGTH_SHORT).show(); + editTextnumber.setError("No Such User Exists"); + + // Toast.makeText(ForgetPassword.this,"NO such user exists",Toast.LENGTH_SHORT).show(); + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Log.e("Raman", "Received an exception check chexk " + databaseError.getMessage()); + + // Toast.makeText(ForgetPassword.this,databaseError.getMessage(),Toast.LENGTH_SHORT).show(); + + } + }); + + + } + } + + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(ForgetPassword.this, ForgetPasswordReset.class); + intent.putExtra("mobile", mobile); + + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + + + startActivity(intent); + + } else { + Toast.makeText(ForgetPassword.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); + } + } + + }); + } + + private void sendVerificationCode(String number){ + + PhoneAuthProvider.getInstance().verifyPhoneNumber( + number, + 60, + TimeUnit.SECONDS, + (Activity) TaskExecutors.MAIN_THREAD, + mCallBack + ); + } + + private PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + progressBar.setVisibility(View.VISIBLE); + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(ForgetPassword.this, e.getMessage(), Toast.LENGTH_LONG).show(); + + } + }; + + + + + private void checkuserexist(String number) + { + Query chekuser= FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(number); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if(dataSnapshot.exists()) + { + exists= true; + } + else + { + exists=false; + } + + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Toast.makeText(ForgetPassword.this,databaseError.getMessage(), Toast.LENGTH_SHORT).show(); + + } + }); + + + + + + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPasswordReset.java b/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPasswordReset.java new file mode 100644 index 0000000..40ba754 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/ForgetPasswordReset.java @@ -0,0 +1,69 @@ +package no.Reader.android.iisc.Reader; + + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import no.Reader.android.iisc.R; + +public class ForgetPasswordReset extends AppCompatActivity { + private Button next; + + String phonenumber,num1,num2; + private EditText passworddata; + private EditText ConfirmPassword; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create__password); + passworddata=findViewById(R.id.password); + ConfirmPassword=findViewById(R.id.confirmpassword); + next=findViewById(R.id.next); + + + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + num1 = ConfirmPassword.getText().toString(); + num2=passworddata.getText().toString(); + if(num1.equals(num2)) { + + Intent intent = new Intent(ForgetPasswordReset.this, LoginScreen.class); + + String phonenumberk = getIntent().getStringExtra("mobile"); + phonenumber = phonenumberk; + + FirebaseDatabase rootNode = FirebaseDatabase.getInstance(); + DatabaseReference reference = rootNode.getReference("USERS"); + + + reference.child(phonenumber).child("password").setValue(num1); + Toast.makeText(ForgetPasswordReset.this, "Password Reset Successfully ", Toast.LENGTH_SHORT).show(); + startActivity(intent); + + } + else + { + ConfirmPassword.setError("Password does not match"); + } + } + }); + + + } +} + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Interface/ItemClickListner.java b/app/src/main/java/no/Reader/android/iisc/Reader/Interface/ItemClickListner.java new file mode 100644 index 0000000..528aa48 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Interface/ItemClickListner.java @@ -0,0 +1,9 @@ +package no.Reader.android.iisc.Reader.Interface; + + +import android.view.View; + +public interface ItemClickListner +{ + void onClick(View view, int position, boolean isLongClick); +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/LoginScreen.java b/app/src/main/java/no/Reader/android/iisc/Reader/LoginScreen.java new file mode 100644 index 0000000..2f907d6 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/LoginScreen.java @@ -0,0 +1,250 @@ +package no.Reader.android.iisc.Reader; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.Patterns; +import android.view.View; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatCheckBox; + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; + +import no.Reader.android.iisc.R; + + +public class LoginScreen extends AppCompatActivity { + + private TextView createaccount, forgetpassword; + private Button login; + private DatabaseReference databaseReference; + private EditText phonenumber, password; + String passworddata, phonenum, phonenumbers, name; + private ProgressDialog loadingBar; + public static final String Name = "nameKey"; + public static final String Phone = "phoneKey"; + private ImageButton close; + Animation btnAnim ; + + private AppCompatCheckBox checkbox; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login__screen); + createaccount = findViewById(R.id.createaccount); + phonenumber = findViewById(R.id.contactnumber); + checkbox = (AppCompatCheckBox) findViewById(R.id.showpassword); + + password = findViewById(R.id.password); + checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { + if (isChecked) { + // show password + password.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); + } else { + // hide password + password.setTransformationMethod(PasswordTransformationMethod.getInstance()); + } + } + }); + + // Paper.init(this); + loadingBar = new ProgressDialog(this); + // Paper.init(this); + + login = findViewById(R.id.login); + forgetpassword = findViewById(R.id.forgetpassword); + forgetpassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(LoginScreen.this, ForgetPassword.class); + startActivity(intent); + + } + }); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(LoginScreen.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + String mobile = phonenumber.getText().toString().trim(); + phonenum = mobile; + final String passwordj = password.getText().toString().trim(); + + + if (mobile.equals("") || passwordj.equals("")) { + Toast.makeText(LoginScreen.this, "Please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + + phonenumber.setError("Enter a valid number"); + + } else { + loadingBar.setTitle("Login Account"); + loadingBar.setMessage("Please wait, while we are checking the credentials."); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(phonenum); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + String systempassword = dataSnapshot.child(phonenum).child("password").getValue(String.class); + + if (systempassword.equals(passwordj)) { + + Toast.makeText(LoginScreen.this, "logged in Successfully...", Toast.LENGTH_SHORT).show(); + loadingBar.dismiss(); + String name = dataSnapshot.child(phonenum).child("name").getValue(String.class); + + + SharedPreferences preferences = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + editor.putString("Phone", phonenum); + editor.putString("Name", name); + + + editor.commit(); + + + Intent intent = new Intent(LoginScreen.this, MainActivity.class); + + + intent.putExtra("mobile", phonenum); + + startActivity(intent); + + } else { + loadingBar.dismiss(); + + Toast.makeText(LoginScreen.this, "Wrong Password", Toast.LENGTH_SHORT).show(); + } + } else { + loadingBar.dismiss(); + + Toast.makeText(LoginScreen.this, "No such user exists", Toast.LENGTH_SHORT).show(); + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Toast.makeText(LoginScreen.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show(); + + } + }); + + + } + } + } + }); + createaccount.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(LoginScreen.this, Register.class); + startActivity(intent); + } + }); + } + + private void finishQuiz() { + if (!isOnline()) { + + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(LoginScreen.this); + Checkbuilder.setTitle("Error!"); + Checkbuilder.setMessage("Enable your internet connection and Retry "); + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + } + ); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } + } + @Override + public void onBackPressed() { + + finishAffinity(); + finish(); + } + + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + + + + + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/MainActivity.java b/app/src/main/java/no/Reader/android/iisc/Reader/MainActivity.java new file mode 100644 index 0000000..30643fd --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/MainActivity.java @@ -0,0 +1,255 @@ +package no.Reader.android.iisc.Reader; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SearchView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.firebase.ui.database.FirebaseRecyclerAdapter; +import com.firebase.ui.database.FirebaseRecyclerOptions; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.Model.Tests; + + +public class MainActivity extends NavigationTop { + private DatabaseReference TestRef; + private RecyclerView recyclerView; + + private TextView info; + FloatingActionButton fasbs; + + String number; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_main, null, false); + draw.addView(contentView, 0); + + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + fasbs=findViewById(R.id.fab); + info=findViewById(R.id.info); + info.setVisibility(View.VISIBLE); + + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + recyclerView = findViewById(R.id.recycler_view); + fasbs.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, TestDetails.class); + startActivity(intent); + + } + }); + + LinearLayoutManager layoutManager1=new LinearLayoutManager(this); + + recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels / 8; + int spaceInPixel = 4; + recyclerView.addItemDecoration(new SpaceDecoration(spaceInPixel)); + + } + @Override + protected void onStart() + { + super.onStart(); + + + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(TestRef, Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull TestViewHolder holder, int position, @NonNull final Tests model) + { + if(model.getInternal().contains("Yes") || model.getInternal().contains("No")) + { + info.setVisibility(View.INVISIBLE); + + } + if(model.getInternal().contains("Yes") ) + { + holder.iconfinder.setBackgroundResource(R.drawable.green_circle); + holder.iconfinder.setText("I"); + + + + + } + + + holder.txtpatientid.setText("User Name :"+model.getUser_Name()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); +holder.txttimestamp.setText(model.getSample_Date()); + + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, ViewSamples.class); + Log.e("main", "error id"+model.getTest_Id()); + Log.e("main", "TestID"+model.getTest_Id()); + + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + private void firebasesearch(String data) + { + { + Query firebaseSearchQuery = TestRef.orderByChild("Test_Id").startAt(data).endAt(data + "\uf8ff"); + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(firebaseSearchQuery, Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull final TestViewHolder holder, int position, @NonNull final Tests model) + { + if(model.getInternal().contains("Yes") || model.getInternal().contains("No")) + { + info.setVisibility(View.INVISIBLE); + + } + if(model.getInternal().contains("Yes") ) + { + holder.iconfinder.setBackgroundResource(R.drawable.green_circle); + holder.iconfinder.setText("I"); + + + + + } + + holder.txtpatientid.setText("User Name :"+model.getUser_Name()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); + holder.txttimestamp.setText(model.getSample_Date()); + + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, ViewSamples.class); + Log.e("main", "error id"+model.getTest_Id()); + Log.e("main", "TestID"+model.getTest_Id()); + + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + + } + + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater=getMenuInflater(); + inflater.inflate(R.menu.searchmenu,menu); + MenuItem item = menu.findItem(R.id.search); + SearchView searchView = (SearchView) item.getActionView(); + //searchView.setIconified(false); + //searchView.setIconifiedByDefault(false); + searchView.setQueryHint("Search Test ID"); + + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + query=query.toLowerCase(); + + firebasesearch(query); + // processsearch(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + newText=newText.toLowerCase(); + + firebasesearch(newText); + + // processsearch(query); + + return false; + } + }); + return super.onCreateOptionsMenu(menu); + } + @Override + public void onBackPressed() { + + finishAffinity(); + finish(); + } +} + + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Model/RegisterHelper.java b/app/src/main/java/no/Reader/android/iisc/Reader/Model/RegisterHelper.java new file mode 100644 index 0000000..3260ae4 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Model/RegisterHelper.java @@ -0,0 +1,41 @@ +package no.Reader.android.iisc.Reader.Model; + +import java.io.Serializable; + +public class RegisterHelper implements Serializable { + + public String name, number, password; + + public RegisterHelper(String name, String number, String password) { + this.name = name; + this.number = number; + this.password = password; + } + public RegisterHelper() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Model/Tests.java b/app/src/main/java/no/Reader/android/iisc/Reader/Model/Tests.java new file mode 100644 index 0000000..6cfc089 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Model/Tests.java @@ -0,0 +1,77 @@ +package no.Reader.android.iisc.Reader.Model; + +public class Tests { + + private String Test_Id, Time, User_Name, Sample_volume, Sample_Date, Percentage, Internal; + + public Tests() { + + + } + + public Tests(String test_Id, String time, String user_Name, String sample_volume, String sample_Date, String percentage, String internal) { + Test_Id = test_Id; + Time = time; + User_Name = user_Name; + Sample_volume = sample_volume; + Sample_Date = sample_Date; + Percentage = percentage; + Internal = internal; + } + + public String getTest_Id() { + return Test_Id; + } + + public void setTest_Id(String test_Id) { + Test_Id = test_Id; + } + + public String getTime() { + return Time; + } + + public void setTime(String time) { + Time = time; + } + + public String getUser_Name() { + return User_Name; + } + + public void setUser_Name(String user_Name) { + User_Name = user_Name; + } + + public String getSample_volume() { + return Sample_volume; + } + + public void setSample_volume(String sample_volume) { + Sample_volume = sample_volume; + } + + public String getSample_Date() { + return Sample_Date; + } + + public void setSample_Date(String sample_Date) { + Sample_Date = sample_Date; + } + + public String getPercentage() { + return Percentage; + } + + public void setPercentage(String percentage) { + Percentage = percentage; + } + + public String getInternal() { + return Internal; + } + + public void setInternal(String internal) { + Internal = internal; + } +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Nav_Two.java b/app/src/main/java/no/Reader/android/iisc/Reader/Nav_Two.java new file mode 100644 index 0000000..dc040c0 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Nav_Two.java @@ -0,0 +1,140 @@ +package no.Reader.android.iisc.Reader; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.FileProvider; +import androidx.drawerlayout.widget.DrawerLayout; + +import com.google.android.material.navigation.NavigationView; + +import java.io.File; + +import no.Reader.android.iisc.R; + +public class Nav_Two extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + + protected DrawerLayout draw; + private LinearLayout line; + private Toolbar tool; + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { + switch (menuItem.getItemId()) + { + + case R.id.nav_contact_us: + Intent intent1=new Intent(this,About.class); + startActivity(intent1); + break; + case R.id.nav_result: + Intent intent2=new Intent(this, MainActivity.class); + startActivity(intent2); + break; + case R.id.nav_add_Test: + Intent intent3=new Intent(this, TestDetails.class); + startActivity(intent3); + break; + case R.id.nav_sample: + Intent intent6=new Intent(this, TemplateActivity2.class); + startActivity(intent6); + break; + case R.id.nav_negative: + Intent intent4=new Intent(this, NegativeResults.class); + startActivity(intent4); + break; + case R.id.nav_positive: + Intent intent5=new Intent(this, PositiveResult.class); + startActivity(intent5); + break; + case R.id.nav_logout: + Intent intent8=new Intent(this, LoginScreen.class); + SharedPreferences preferences = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + editor.putString("Phone", null); + editor.putString("Name",null); + + + editor.commit(); + + startActivity(intent8); + break; + + } + return true; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.nav_two); + + + draw = findViewById(R.id.Drawer); + line = findViewById(R.id.line); + tool = findViewById(R.id.tollbar); + NavigationView navigationView = findViewById(R.id.navigation); + navigationView.setNavigationItemSelectedListener(this); + + setSupportActionBar(tool); + + Window window = getWindow(); + window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + + + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, draw, tool, R.string.open_navigation_drawer, R.string.close_navigation_drawer) { + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + super.onDrawerSlide(drawerView, slideOffset); + float sidebar = drawerView.getWidth() * slideOffset; + line.setTranslationX(sidebar); + } + }; + + draw.addDrawerListener(toggle); + toggle.syncState(); + View headerView = navigationView.getHeaderView(0); + TextView textView=headerView.findViewById(R.id.text); + TextView textView1=headerView.findViewById(R.id.not_sign_in); + + SharedPreferences preferences=getSharedPreferences("PhoneBook_number",MODE_PRIVATE); + + String string1 = preferences.getString("Phone", null); + String string2 = preferences.getString("Name", null); + textView.setText(string2); + textView1.setText(string1); + + } + public void shared( String testid) { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + Intent intent = new Intent(Intent.ACTION_VIEW); + File file = new File(pat); + Uri path = FileProvider.getUriForFile(getApplicationContext(), "no.Reader.android.iisc.fileprovider", file); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + } + +} + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/NavigationTop.java b/app/src/main/java/no/Reader/android/iisc/Reader/NavigationTop.java new file mode 100644 index 0000000..217d333 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/NavigationTop.java @@ -0,0 +1,122 @@ +package no.Reader.android.iisc.Reader; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.drawerlayout.widget.DrawerLayout; + +import com.google.android.material.navigation.NavigationView; + +import no.Reader.android.iisc.R; + + +public class NavigationTop extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + + protected DrawerLayout draw; + private LinearLayout line; + private Toolbar tool; + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { + switch (menuItem.getItemId()) + { + + case R.id.nav_contact_us: + Intent intent1=new Intent(this,About.class); + startActivity(intent1); + break; + case R.id.nav_result: + Intent intent2=new Intent(this, MainActivity.class); + startActivity(intent2); + break; + case R.id.nav_add_Test: + Intent intent3=new Intent(this, TestDetails.class); + startActivity(intent3); + break; + case R.id.nav_sample: + Intent intent6=new Intent(this, TemplateActivity2.class); + startActivity(intent6); + break; + case R.id.nav_negative: + Intent intent4=new Intent(this, NegativeResults.class); + startActivity(intent4); + break; + case R.id.nav_positive: + Intent intent5=new Intent(this, PositiveResult.class); + startActivity(intent5); + break; + case R.id.nav_logout: + Intent intent8=new Intent(this, LoginScreen.class); + SharedPreferences preferences = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + editor.putString("Phone", null); + editor.putString("Name",null); + + + editor.commit(); + + startActivity(intent8); + break; + + } + return true; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.activity_navigation__top); + + + draw = findViewById(R.id.Drawer); + line = findViewById(R.id.line); + tool = findViewById(R.id.tollbar); + NavigationView navigationView = findViewById(R.id.navigation); + navigationView.setNavigationItemSelectedListener(this); + + setSupportActionBar(tool); + + Window window = getWindow(); + window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + + + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, draw, tool, R.string.open_navigation_drawer, R.string.close_navigation_drawer) { + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + super.onDrawerSlide(drawerView, slideOffset); + float sidebar = drawerView.getWidth() * slideOffset; + line.setTranslationX(sidebar); + } + }; + + draw.addDrawerListener(toggle); + toggle.syncState(); + View headerView = navigationView.getHeaderView(0); + TextView textView=headerView.findViewById(R.id.text); + TextView textView1=headerView.findViewById(R.id.not_sign_in); + + SharedPreferences preferences=getSharedPreferences("PhoneBook_number",MODE_PRIVATE); + + String string1 = preferences.getString("Phone", null); + String string2 = preferences.getString("Name", null); + textView.setText(string2); + textView1.setText(string1); + + } +} + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/NegativeResults.java b/app/src/main/java/no/Reader/android/iisc/Reader/NegativeResults.java new file mode 100644 index 0000000..4268e72 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/NegativeResults.java @@ -0,0 +1,200 @@ +package no.Reader.android.iisc.Reader; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.firebase.ui.database.FirebaseRecyclerAdapter; +import com.firebase.ui.database.FirebaseRecyclerOptions; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.Model.Tests; + + +public class NegativeResults extends NavigationTop { + private DatabaseReference TestRef; + private RecyclerView recyclerView; + + private TextView info; + + FloatingActionButton fasbs; + + String number; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_main, null, false); + draw.addView(contentView, 0); + + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + fasbs=findViewById(R.id.fab); + info=findViewById(R.id.info); + info.setText("No Results "); + info.setVisibility(View.VISIBLE); + + + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + recyclerView = findViewById(R.id.recycler_view); + DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); + + + + fasbs.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(NegativeResults.this, TemplateActivity.class); + startActivity(intent); + + } + }); + + LinearLayoutManager layoutManager1=new LinearLayoutManager(this); + + recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels / 8; + int spaceInPixel = 4; + recyclerView.addItemDecoration(new SpaceDecoration(spaceInPixel)); + + } + @Override + protected void onStart() + { + super.onStart(); + + + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(TestRef.orderByChild("Internal").equalTo("No"), Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull TestViewHolder holder, int position, @NonNull final Tests model) + { + // holder.txtProductName.setText(model.getPatientid()); + if(model.getInternal().contains("Yes") || model.getInternal().contains("No")) + { + info.setVisibility(View.INVISIBLE); + + } + + + holder.txtpatientid.setText("User Name :"+model.getSample_volume()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); + holder.txttimestamp.setText(model.getSample_Date()); + + + + + + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(NegativeResults.this, ViewSamples.class); + + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + private void firebasesearch(String data) + { + { + Query firebaseSearchQuery = TestRef.orderByChild("Test_Id").startAt(data).endAt(data + "\uf8ff") ; + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(firebaseSearchQuery, Tests.class) + .build(); + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull final TestViewHolder holder, int position, @NonNull final Tests model) + { + + holder.txtpatientid.setText("User Name :"+model.getSample_volume()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); + holder.txttimestamp.setText(model.getSample_Date()); + + + + + + + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + Intent intent=new Intent(NegativeResults.this, ViewSamples.class); + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + Log.e("main", "TestID"+model.getTest_Id()); + + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + } + + +} + + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/PositiveResult.java b/app/src/main/java/no/Reader/android/iisc/Reader/PositiveResult.java new file mode 100644 index 0000000..e3ba5d0 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/PositiveResult.java @@ -0,0 +1,203 @@ +package no.Reader.android.iisc.Reader; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.firebase.ui.database.FirebaseRecyclerAdapter; +import com.firebase.ui.database.FirebaseRecyclerOptions; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.Model.Tests; + + +public class PositiveResult extends NavigationTop { + private DatabaseReference TestRef; + private RecyclerView recyclerView ; + FloatingActionButton fasbs; + private TextView info; + + + String number; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_main, null, false); + draw.addView(contentView, 0); + info=findViewById(R.id.info); + + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + info.setText("No Results "); + info.setVisibility(View.VISIBLE); + number = preferences6.getString("Phone", null); + fasbs=findViewById(R.id.fab); + + + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + recyclerView = findViewById(R.id.recycler_view); + + fasbs.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(PositiveResult.this, TestDetails.class); + startActivity(intent); + + } + }); + + LinearLayoutManager layoutManager1=new LinearLayoutManager(this); + /* layoutManager1.setOrientation(LinearLayoutManager.HORIZONTAL); + cA + layoutManager = new LinearLayoutManager(this); + recyclerView.setLayoutManager(layoutManager); + */ // recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels / 8; + int spaceInPixel = 4; + recyclerView.addItemDecoration(new SpaceDecoration(spaceInPixel)); + + } + @Override + protected void onStart() + { + super.onStart(); + + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(TestRef.orderByChild("Internal").equalTo("Yes"), Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull TestViewHolder holder, int position, @NonNull final Tests model) + { + if(model.getInternal().contains("Yes") || model.getInternal().contains("No")) + { + info.setVisibility(View.INVISIBLE); + + } + // holder.txtProductName.setText(model.getPatientid()); + + holder.iconfinder.setBackgroundResource(R.drawable.green_circle); + holder.iconfinder.setText("I"); + holder.txtpatientid.setText("User Name :"+model.getSample_volume()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); + holder.txttimestamp.setText(model.getSample_Date()); + + + + + + + + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(PositiveResult.this, ViewSamples.class); + Log.e("main", "TestID"+model.getTest_Id()); + + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + private void firebasesearch(String data) + { + { + Query firebaseSearchQuery = TestRef.orderByChild("Patient_Id").startAt(data).endAt(data + "\uf8ff") ; + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(firebaseSearchQuery, Tests.class) + .build(); + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull final TestViewHolder holder, int position, @NonNull final Tests model) + { + + holder.txtpatientid.setText("User Name :"+model.getSample_volume()); + holder.txtsampletype.setText("Test Id :" +model.getTest_Id()); + holder.nikshay.setText("Volume :"+model.getSample_volume()); + holder.txttimestamp.setText(model.getSample_Date()); + + holder.iconfinder.setBackgroundResource(R.drawable.green_circle); + holder.iconfinder.setText("I"); + + + + + + + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + Intent intent=new Intent(PositiveResult.this, ViewSamples.class); + intent.putExtra("pid",model.getTest_Id()); + startActivity(intent); + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + } + + +} + + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Readme.txt b/app/src/main/java/no/Reader/android/iisc/Reader/Readme.txt new file mode 100644 index 0000000..ec04717 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Readme.txt @@ -0,0 +1,54 @@ +nRF Toolbox demonstrates how to implement the Bluetooth Smart features in an Android application. + It consists of number of profiles, like Heart Rate, Blood Pressure etc. that may be use as is to communicate with real devices. + They use the Bluetooth SIG adopted profiles, that may be found here: https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx + + The Template Profile has been created to give a quick start with implementing proprietary services. Just start modifying 4 classes inside + the template package to implement features you need. + + Below you will find a short step-by-step tutorial: + + 1. The template consists of the following files: + - TemplateActivity - the main class that is responsible for managing the view of your profile + - TemplateService - the service that is started whenever you connect to a device. I handles the Bluetooth Smart communication using the... + - TemplateManager - the manager that handles all the BLE logic required to communicate with the device. The TemplateManager derives from + the BleManager which handles most of the event itself and propagates the data-relevant to deriving class. You don't + have to, or even shouldn't modify the BleManager (unless you want to change the default behaviour). + - TemplateManagerCallbacks - the interface with a list of callbacks that the TemplateManager can call. Each method is usually related to one + BLE event, e.g. receiving a new value of the characteristic.\ + - TemplateParser - an optional class in the .parser package that is responsible for converting the characteristic value to String. + This is used only for debugging. The String returned by the parse(..) method is then logged into the nRF Logger application + (if such installed). + - /settings/SettingsActivity and /settings/SettingsFragment - classes used to present user preferences. A stub implementation in the template. + - /res/layout/activity_feature_template.xml - the layout file for the TemplateActivity + - /res/values/strings_template.xml - a set of strings used in the layout file + - /res/xml/settings/template.xml - the user settings configuration + - /res/drawable/(x)hdpi/ic_template_feature.png - the template profile icon (HDPI, XHDPI). Please, keep the files size. + - /res/drawable/(x)hdpi/ic_stat_notify_template - the icon that is used in the notification + +2. The communication between the components goes as follows: + - User clicks the CONNECT button and selects a target device on TemplateActivity. + - The base class of the TemplateActivity starts the service given by getServiceClass() method. + - The service starts and initializes the TemplateManager. TemplateActivity binds to the service and is being given the TemplateBinder object (the service API) as a result. + - The manager connects to the device using Bluetooth Smart and discovers its services. + - The manager initializes the device. Initialization is done using the list of actions given by the initGatt(..) method in the TemplateManager. + Initialization usually contains enabling notifications, writing some initial values etc. + - When initialization is complete the manager calls the onDeviceReady() callback. + - The service sends the BROADCAST_DEVICE_READY broadcast to the activity. Communication from the Service to the Activity is always done using the LocalBroadcastManager broadcasts. + - The base class of the TemplateActivity listens to the broadcasts and calls appropriate methods. + + - When a custom event occurs, for example a notification is received, the manager parses the incoming data and calls the proper callback. + - The callback implementation in the TemplateService sends a broadcast message with values given in parameters. + - The TemplateActivity, which had registered a broadcast receiver before, listens to the broadcasts, reads the values and present them to users. + + - Communication Activity->Service is done using the API in the TemplateBinder. You may find the example of how to use it in the ProximityActivity. + +3. Please read the files listed above and the TODO messages for more information what to modify in the files. + +4. Remember to add your activities and the service in the AndroidManifest.xml file. The nRF Toolbox lists all activities with the following intent filter: + + + + + +5. Feel free to rename the nRF Toolbox application (/res/values/strings.xml ->app_name), change the toolbar colors (/res/values/color.xml -> actionBarColor, actionBarColorDark). + In order to remove unused profiles from the main FeaturesActivity just comment out their intent-filter tags in the AndroidManifest.xml file. diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Register.java b/app/src/main/java/no/Reader/android/iisc/Reader/Register.java new file mode 100644 index 0000000..58681bc --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Register.java @@ -0,0 +1,200 @@ +package no.Reader.android.iisc.Reader; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.util.Log; +import android.util.Patterns; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; +import com.hbb20.CountryCodePicker; +import no.Reader.android.iisc.R; + +import no.Reader.android.iisc.Reader.VerifyOTP.VerifyOtp; + + +public class Register extends AppCompatActivity { +String numberwithcode; + private Button next; + private EditText editTextMobile; + private ProgressDialog loadingBar; + + private TextView login; + CountryCodePicker ccp; + String mobile,name; + + private EditText editTextname; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_register); + next=findViewById(R.id.buttonContinue); + editTextMobile = findViewById(R.id.editTextMobile); + + ccp=findViewById(R.id.ccp); + + ccp.registerCarrierNumberEditText(editTextMobile); + loadingBar = new ProgressDialog(this); + login=findViewById(R.id.login_account); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Register.this, LoginScreen.class); + startActivity(intent); + + } + }); + + editTextname=findViewById(R.id.editTextName); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mobile = editTextMobile.getText().toString().trim(); + mobile = mobile.replaceAll("[^0-9]", ""); + + name = editTextname.getText().toString().trim(); + + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(Register.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } + + else { + if (mobile.equals("") || name.equals("")) { + Toast.makeText(Register.this, "please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + editTextMobile.setError("Enter a valid Phone "); + // Toast.makeText(Consumer_register.this, "Please Enter a valid email", Toast.LENGTH_SHORT).show(); + + } + else if (mobile.length() <9 ) { + Toast.makeText(Register.this, "Enter a valid Phone", Toast.LENGTH_SHORT).show(); + // Toast.makeText(Consumer_register.this, "Please Enter a valid email", Toast.LENGTH_SHORT).show(); + + } + else if (mobile.length() >=11 ) { + Toast.makeText(Register.this, "Enter a valid Phone", Toast.LENGTH_SHORT).show(); + // Toast.makeText(Consumer_register.this, "Please Enter a valid email", Toast.LENGTH_SHORT).show(); + + }else { + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(mobile); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + Toast.makeText(Register.this, "User Already Exist", Toast.LENGTH_SHORT).show(); + + // editTextMobile.setError("User Already Exist"); + + + } else { + Intent intent = new Intent(Register.this, VerifyOtp.class); + Log.e("main", "error " + mobile); + + numberwithcode = ccp.getFullNumberWithPlus(); + Log.e("main", "error " + numberwithcode); + + if (mobile.equals("") || name.equals("")) { + Toast.makeText(Register.this, "please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + editTextMobile.setError("Enter a valid Phone "); + // Toast.makeText(Consumer_register.this, "Please Enter a valid email", Toast.LENGTH_SHORT).show(); + + } else { + loadingBar.setTitle("Create Account"); + loadingBar.setMessage("Please wait "); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + + intent.putExtra("numberwithcode", numberwithcode); + + intent.putExtra("mobile", mobile); + intent.putExtra("username", name); + + startActivity(intent); + } + + + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Log.e("Raman", "Received an exception check chexk " + databaseError.getMessage()); + + // Toast.makeText(ForgetPassword.this,databaseError.getMessage(),Toast.LENGTH_SHORT).show(); + + } + }); + } + } + + } + }); + + + + + } + @Override + public void onBackPressed() { + + Intent intent = new Intent(Register.this, LoginScreen.class); + startActivity(intent); + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/SPCAManagerCallbacks.java b/app/src/main/java/no/Reader/android/iisc/Reader/SPCAManagerCallbacks.java new file mode 100644 index 0000000..04276ef --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/SPCAManagerCallbacks.java @@ -0,0 +1,17 @@ +package no.Reader.android.iisc.Reader; + +import no.Reader.android.iisc.Reader.callback.SPCACharacteristicCallback; +import no.Reader.android.iisc.battery.BatteryManagerCallbacks; + +/** + * Interface {@link SPCAManagerCallbacks} must be implemented by {@link SPCAService} + * in order to receive callbacks from {@link TemplateManager} + */ +interface SPCAManagerCallbacks extends BatteryManagerCallbacks, SPCACharacteristicCallback { + + // Callbacks are called when a data has been received/written to a remote device. + // This is the way how the manager notifies the activity about this event. + + // TODO add more callbacks. + // If you need, create more ...Callback interfaces and extend this interface with them. +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/SPCAService.java b/app/src/main/java/no/Reader/android/iisc/Reader/SPCAService.java new file mode 100644 index 0000000..4e077c0 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/SPCAService.java @@ -0,0 +1,204 @@ +package no.Reader.android.iisc.Reader; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import no.nordicsemi.android.log.Logger; +import no.Reader.android.iisc.FeaturesActivity; +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.NotificationData; +import no.Reader.android.iisc.profile.BleProfileService; +import no.Reader.android.iisc.profile.LoggableBleManager; + +public class SPCAService extends BleProfileService implements SPCAManagerCallbacks { + public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.Reader.android.iisc.template.BROADCAST_MEASUREMENT"; + public static final String EXTRA_DATA = "no.Reader.android.iisc.template.EXTRA_DATA"; + + public static final String BROADCAST_BATTERY_LEVEL = "no.Reader.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String EXTRA_BATTERY_LEVEL = "no.Reader.android.iisc.EXTRA_BATTERY_LEVEL"; + + private final static String ACTION_DISCONNECT = "no.Reader.android.iisc.template.ACTION_DISCONNECT"; + + private final static int NOTIFICATION_ID = 864; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private TemplateManager mManager; + + private final LocalBinder mBinder = new TemplateBinder(); + + /** + * This local binder is an interface for the bound activity to operate with the sensor. + */ + class TemplateBinder extends LocalBinder { + // TODO Define service API that may be used by a bound Activity + + /** + * Sends some important data to the device. + * + * @param parameter some parameter. + */ + + public void heatingSwitch(int state){ + mManager.heatingSwitch(state); + } + public void sendDTemp(int d_temp) { + mManager.sendDTemp(d_temp); + } + public void sendATemp(int a_temp) { + mManager.sendATemp(a_temp); + } + public void sendETemp(int e_temp) { + mManager.sendETemp(e_temp); + } + + public void sendLTemp(int l_temp) { + mManager.sendLTemp(l_temp); + } + public void sendOTemp(int o_temp) { + mManager.sendOTemp(o_temp); + } + + + + + public void sendDTime(int d_time) { + mManager.sendDTime(d_time); + } + public void sendATime(int a_time) { + mManager.sendATime(a_time); + } + public void sendETime(int e_time) { + mManager.sendETime(e_time); + } + + public void sendLTime(int l_time) { + mManager.sendLTime(l_time); + } + public void sendOTime(int o_time) { mManager.sendOTime(o_time); } + + + public void sendNPcrN(int n_pcr_c) { + mManager.sendNPcrC(n_pcr_c); + } + + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected LoggableBleManager initializeManager() { + return mManager = new TemplateManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + protected void onRebind() { + // when the activity rebinds to the service, remove the notification + cancelNotification(); + } + + @Override + protected void onUnbind() { + // when the activity closes we need to show the notification that user is connected to the sensor + createNotification(R.string.template_notification_connected_message, 0); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT); + broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); + broadcast.putExtra(EXTRA_DATA, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + if (!mBound) { + // Here we may update the notification to display the current value. + // TODO modify the notification here + } + } + + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + + } + + /** + * Creates the notification. + * + * @param messageResId message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults signals that will be used to notify the user + */ + private void createNotification(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, TemplateActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT); + final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationData.CONNECTED_DEVICE_CHANNEL); + builder.setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_template); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.template_notification_action_disconnect), disconnectAction)); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[Notification] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/SpaceDecoration.java b/app/src/main/java/no/Reader/android/iisc/Reader/SpaceDecoration.java new file mode 100644 index 0000000..b789d67 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/SpaceDecoration.java @@ -0,0 +1,20 @@ +package no.Reader.android.iisc.Reader; + +import android.graphics.Rect; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class SpaceDecoration extends RecyclerView.ItemDecoration { + private int space; + + public SpaceDecoration(int space) { + this.space = space; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + outRect.left=outRect.bottom=outRect.right=outRect.top=space; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity.java b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity.java new file mode 100644 index 0000000..dc83456 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity.java @@ -0,0 +1,527 @@ +package no.Reader.android.iisc.Reader; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import java.util.UUID; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.profile.BleProfileService; +import no.Reader.android.iisc.profile.BleProfileServiceReadyActivity; + + +/** + * Modify the Template Activity to match your needs. + */ +public class TemplateActivity extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "TemplateActivity"; + + // TODO change view references to match your need + private TextView mValueView; + private TextView mHeatingStatusView; + + private Switch mHeatingState ; + + int p ,q,r; + int count =0; + int love=0; + int love1=0; + int love2=0; + int love3=0; + private TextView mClockView; + int act1_1=0; + int act1_2=0; + int act1_3=0; + private Button d,connect; + + /*private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + + private TextView mClockView; + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + + private EditText mNPcrCView; + private Integer mNPcrC ; + +*/ + @Override + protected void onCreateView(final Bundle savedInstanceState) { + // TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample + setContentView(R.layout.activity_feature_template); + BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setOnNavigationItemSelectedListener(navListener); + + setGUI(); + connect=findViewById(R.id.action_connect); + d.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + SharedPreferences preferences = getSharedPreferences("PhoneBook_adc1", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + + mHeatingState.setChecked(false); + editor.putString("act1_1", String.valueOf(act1_1)); + editor.putString("act1_2", String.valueOf(act1_2)); + editor.putString("act1_3", String.valueOf(act1_3)); + + + Log.d("Addact11", String.valueOf(act1_1)); + Log.d("Addact12", String.valueOf(act1_2)); + Log.d("Addact13", String.valueOf(act1_3)); + + + + editor.commit(); + + + Intent intent = new Intent(TemplateActivity.this, TemplateActivity1.class); + + + startActivity(intent); + + } + }); + } + + + private void setGUI() { + // mClockView=findViewById(R.id.RemTime_Value); + + // TODO assign your views to fields + mValueView = findViewById(R.id.Temp_Value); + d=findViewById(R.id.next); + /*mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + +*/ + + + + + + + + + + + + + + +/* + mNPcrCView = findViewById(R.id.N_Pcr_C); +*/ + + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if(connect.getText().equals("CONNECT")) + { + Toast.makeText(TemplateActivity.this, "Please connect to device", Toast.LENGTH_SHORT).show(); + + } + else { + if (isChecked) { + + + getService().heatingSwitch(1); + + + + /* mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + + + + + + + + + // Log.d("Add", String.valueOf(m)); + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); +*/ + } else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + } + }); + + + /*findViewById(R.id.time_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + + mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); + getService().sendTimeDuration(mSetTime); + } + }); + + findViewById(R.id.temp_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); + getService().sendTemp(mSetTemp); + } + });*/ + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + // TODO clear your UI + mValueView.setText(R.string.not_available_value); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + /*@Override + protected void getAboutTextId() { + Intent intent =new Intent (TemplateActivity.this,About.class); + startActivity(intent); + } +*/ + /*@Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.menu, menu); + return true; + } + + @Override + protected boolean onOptionsItemSelected(final int itemId) { + switch (itemId) { + case R.id.action_about: + Intent intent =new Intent (TemplateActivity.this,About.class); + startActivity(intent); + break; + *//*case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break;*//* + } + return true; + } +*/ + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + // TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog. + // If null is returned no filtering is done. + return TemplateManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return SPCAService.class; + } + + @Override + protected void onServiceBound(final SPCAService.TemplateBinder binder) { + // not used + } + + @Override + protected void onServiceUnbound() { + // not used + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + // Handling updates from the device + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, final int value) { + // TODO assign the value to a view + mValueView.setText(String.valueOf(value)); + + if(mHeatingState.isChecked()) + { + d.postDelayed(new Runnable() { + public void run() { + d.setEnabled(true); + Log.d(TAG, "resend1"); + } + }, 7000); + d.postDelayed(new Runnable() { + public void run() { + act1_1=value; + mValueView.setText(String.valueOf(act1_1)); + Log.d(TAG, "resend1"); + } + }, 5000); + d.postDelayed(new Runnable() { + public void run() { + act1_2=value; + mValueView.setText(String.valueOf(act1_2)); + Log.d(TAG, "resend1"); + } + }, 6000); + d.postDelayed(new Runnable() { + public void run() { + act1_3=value; + mValueView.setText(String.valueOf(act1_3)); + Log.d(TAG, "resend1"); + } + }, 7000); + + + + } + /*else if (!mHeatingState.isChecked() && count ==1) { + + love=1; + count=2; + Log.d("check1", String.valueOf(love)); + + mValueView.setText("_"); + Log.d("love", String.valueOf(love)); + Log.d("love", String.valueOf(p)); + + + } + else if ( mHeatingState.isChecked() && love ==1 ) + { + q=value; + final int d=value; + Log.d("Addq", String.valueOf(q)); + + mValueView.setText(String.valueOf(d)); + love1=1; + } + else if(!mHeatingState.isChecked() && love1 ==1) + { + love3=1; + mValueView.setText("_"); + Log.d("check1", String.valueOf(love)); + + + + } + else if(mHeatingState.isChecked() && love3 ==1) + { + r=value; + mValueView.setText(String.valueOf(value)); + Log.d("Addr", String.valueOf(r)); + + + + } +*/ + else + { + mValueView.setText("_"); + + } + } + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(SPCAService.EXTRA_DEVICE); + + if (SPCAService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + final int value = intent.getIntExtra(SPCAService.EXTRA_DATA, 0); + // Update GUI + setValueOnView(device, value); + } else if (SPCAService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(SPCAService.EXTRA_BATTERY_LEVEL, 0); + // Update GUI + onBatteryLevelChanged(device, batteryLevel); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(SPCAService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(SPCAService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_home: + Intent intent = new Intent(TemplateActivity.this, MainActivity.class); + + + startActivity(intent); + + + break; + case R.id.nav_addtest: + Intent intent2 = new Intent(TemplateActivity.this, TestDetails.class); + + + startActivity(intent2); + break; + case R.id.nav_add_sample: + Intent intent3 = new Intent(TemplateActivity.this, TemplateActivity2.class); + + + startActivity(intent3); + break; + } + + return true; + } + }; + @Override + public void onBackPressed() { + //super.onBackPressed(); + IsFinish("Want to exit Test ?"); + } + + public void IsFinish(String alertmessage) { + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent(TemplateActivity.this, TestDetails.class); + + + startActivity(intent); // This above line close correctly + //finish(); + break; + + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(alertmessage) + .setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + AlertDialog alertDialog = builder.create(); + alertDialog.show(); + alertDialog.getButton(Dialog.BUTTON_NEGATIVE).setTextColor(Color.BLACK); + alertDialog.getButton(Dialog.BUTTON_POSITIVE).setTextColor(Color.BLACK); + + alertDialog.getButton(Dialog.BUTTON_NEGATIVE). + setBackgroundColor(Color.TRANSPARENT); + alertDialog.getButton(Dialog.BUTTON_POSITIVE). + setBackgroundColor(Color.TRANSPARENT); + + } + +} + diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity1.java b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity1.java new file mode 100644 index 0000000..1f52585 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity1.java @@ -0,0 +1,528 @@ +package no.Reader.android.iisc.Reader; + +import android.Manifest; +import android.app.AlertDialog; +import android.app.Dialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import java.util.UUID; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.profile.BleProfileService; +import no.Reader.android.iisc.profile.BleProfileServiceReadyActivity; + + +/** + * Modify the Template Activity to match your needs. + */ +public class TemplateActivity1 extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "TemplateActivity"; + + // TODO change view references to match your need + private TextView mValueView; + private TextView mHeatingStatusView; + + private Switch mHeatingState ; + int p ,q,r; + int count =0; + int love=0; + int love1=0; + int act2_1=0; + int act2_2=0; + int act2_3=0; + int love2=0; + int love3=0; + private TextView mClockView; + int act2=0; + private Button d,connect; + + + /*private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + + private TextView mClockView; + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + + private EditText mNPcrCView; + private Integer mNPcrC ; + +*/ + @Override + protected void onCreateView(final Bundle savedInstanceState) { + // TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample + setContentView(R.layout.activity_feature_template1); + BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setOnNavigationItemSelectedListener(navListener); + setGUI(); + + connect=findViewById(R.id.action_connect); + + d.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(ContextCompat.checkSelfPermission(TemplateActivity1.this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(TemplateActivity1.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},23); + } + SharedPreferences preferences = getSharedPreferences("PhoneBook_adc2", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + + editor.putString("act2_1", String.valueOf(act2_1)); + editor.putString("act2_2", String.valueOf(act2_2)); + editor.putString("act2_3", String.valueOf(act2_3)); + + + Log.d("Addact21", String.valueOf(act2_1)); + Log.d("Addact22", String.valueOf(act2_2)); + Log.d("Addact23", String.valueOf(act2_3)); + + editor.commit(); + mHeatingState.setChecked(false); + + + Intent intent = new Intent(TemplateActivity1.this, TemplateActivity2.class); + + + startActivity(intent); + + } + }); + + } + + private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_home: + Intent intent = new Intent(TemplateActivity1.this, MainActivity.class); + + + startActivity(intent); + + + break; + case R.id.nav_addtest: + Intent intent2 = new Intent(TemplateActivity1.this, TestDetails.class); + + + startActivity(intent2); + break; + case R.id.nav_add_sample: + Intent intent3 = new Intent(TemplateActivity1.this, TemplateActivity2.class); + + + startActivity(intent3); + break; + } + + return true; + } + }; + + private void setGUI() { + // mClockView=findViewById(R.id.RemTime_Value); + + // TODO assign your views to fields + mValueView = findViewById(R.id.Temp_Value); + d=findViewById(R.id.next); + /*mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + +*/ + + + + + + + + + + + + + + +/* + mNPcrCView = findViewById(R.id.N_Pcr_C); +*/ + + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if(connect.getText().equals("CONNECT")) + { + Toast.makeText(TemplateActivity1.this, "Please connect to device", Toast.LENGTH_SHORT).show(); + + } + else { + if (isChecked) { + getService().heatingSwitch(1); + + + + /* mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + + + + + + + + + // Log.d("Add", String.valueOf(m)); + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); +*/ + + } else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + } + }); + + + /*findViewById(R.id.time_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + + mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); + getService().sendTimeDuration(mSetTime); + } + }); + + findViewById(R.id.temp_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); + getService().sendTemp(mSetTemp); + } + });*/ + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + // TODO clear your UI + mValueView.setText(R.string.not_available_value); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + /*@Override + protected void getAboutTextId() { + Intent =new Intent (TemplateActivity1.this,About.class); + startActivity(intent); + }*/ + /* @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.settings_and_about, menu); + return true; + } + + @Override + protected boolean onOptionsItemSelected(final int itemId) { + switch (itemId) { + *//*case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break;*//* + } + return true; + }*/ + + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + // TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog. + // If null is returned no filtering is done. + return TemplateManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return SPCAService.class; + } + + @Override + protected void onServiceBound(final SPCAService.TemplateBinder binder) { + // not used + } + + @Override + protected void onServiceUnbound() { + // not used + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + // Handling updates from the device + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, final int value) { + // TODO assign the value to a view + if(mHeatingState.isChecked()) + { + mValueView.setText(String.valueOf(value)); + + d.postDelayed(new Runnable() { + public void run() { + d.setEnabled(true); + Log.d(TAG, "resend1"); + } + }, 7000); + d.postDelayed(new Runnable() { + public void run() { + act2_1=value; + mValueView.setText(String.valueOf(act2_1)); + Log.d(TAG, "resend1"); + } + }, 5000); + d.postDelayed(new Runnable() { + public void run() { + act2_2=value; + mValueView.setText(String.valueOf(act2_2)); + Log.d(TAG, "resend1"); + } + }, 6000); + d.postDelayed(new Runnable() { + public void run() { + act2_3=value; + mValueView.setText(String.valueOf(act2_3)); + Log.d(TAG, "resend1"); + } + }, 7000); + + + } + /*else if (!mHeatingState.isChecked() && count ==1) { + + love=1; + count=2; + Log.d("check1", String.valueOf(love)); + + mValueView.setText("_"); + Log.d("love", String.valueOf(love)); + Log.d("love", String.valueOf(p)); + + + } + else if ( mHeatingState.isChecked() && love ==1 ) + { + q=value; + final int d=value; + Log.d("Addq", String.valueOf(q)); + + mValueView.setText(String.valueOf(d)); + love1=1; + } + else if(!mHeatingState.isChecked() && love1 ==1) + { + love3=1; + mValueView.setText("_"); + Log.d("check1", String.valueOf(love)); + + + + } + else if(mHeatingState.isChecked() && love3 ==1) + { + r=value; + mValueView.setText(String.valueOf(value)); + Log.d("Addr", String.valueOf(r)); + + + + } +*/ + else + { + mValueView.setText("_"); + + } + } + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(SPCAService.EXTRA_DEVICE); + + if (SPCAService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + final int value = intent.getIntExtra(SPCAService.EXTRA_DATA, 0); + // Update GUI + setValueOnView(device, value); + } else if (SPCAService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(SPCAService.EXTRA_BATTERY_LEVEL, 0); + // Update GUI + onBatteryLevelChanged(device, batteryLevel); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(SPCAService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(SPCAService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + @Override + public void onBackPressed() { + //super.onBackPressed(); + IsFinish("Want to exit Test ?"); + } + + public void IsFinish(String alertmessage) { + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent(TemplateActivity1.this, TestDetails.class); + + + startActivity(intent); // This above line close correctly + //finish(); + break; + + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(alertmessage) + .setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + AlertDialog alertDialog = builder.create(); + alertDialog.show(); + alertDialog.getButton(Dialog.BUTTON_NEGATIVE).setTextColor(Color.BLACK); + alertDialog.getButton(Dialog.BUTTON_POSITIVE).setTextColor(Color.BLACK); + + alertDialog.getButton(Dialog.BUTTON_NEGATIVE). + setBackgroundColor(Color.TRANSPARENT); + alertDialog.getButton(Dialog.BUTTON_POSITIVE). + setBackgroundColor(Color.TRANSPARENT); + } + + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity2.java b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity2.java new file mode 100644 index 0000000..102d5bd --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity2.java @@ -0,0 +1,529 @@ +package no.Reader.android.iisc.Reader; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import java.util.UUID; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.profile.BleProfileService; +import no.Reader.android.iisc.profile.BleProfileServiceReadyActivity; + + +/** + * Modify the Template Activity to match your needs. + */ +public class TemplateActivity2 extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "TemplateActivity"; + + // TODO change view references to match your need + private TextView mValueView; + private TextView mHeatingStatusView; + + private Switch mHeatingState ; + int p ,q,r; + private EditText sampledata; + int act3_1=0; + int act3_2=0; + int act3_3=0; + int count =0; + int love=0; + int love1=0; + int love2=0; + int love3=0; + private TextView mClockView; + int act3=0; + private Button d,connect; + + + /*private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + + private TextView mClockView; + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + + private EditText mNPcrCView; + private Integer mNPcrC ; + +*/ + @Override + protected void onCreateView(final Bundle savedInstanceState) { + // TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample + setContentView(R.layout.activity_feature_template2); + sampledata=findViewById(R.id.samplename); + BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setOnNavigationItemSelectedListener(navListener); + + + setGUI(); + connect=findViewById(R.id.action_connect); + + d.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + SharedPreferences preferences = getSharedPreferences("PhoneBook_adc3", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + + + /* editor.putString("act3", String.valueOf(act3)); + Log.d("Addact1", String.valueOf(act3)); + + editor.commit(); + */ + editor.putString("act3_1", String.valueOf(act3_1)); + editor.putString("act3_2", String.valueOf(act3_2)); + editor.putString("act3_3", String.valueOf(act3_3)); + editor.putString("samplename", String.valueOf(sampledata.getText())); + + + + Log.d("Addact21", String.valueOf(act3_1)); + Log.d("Addact22", String.valueOf(act3_2)); + Log.d("Addact23", String.valueOf(act3_3)); + + editor.commit(); + mHeatingState.setChecked(false); + + + Intent intent = new Intent(TemplateActivity2.this, check1.class); + + + startActivity(intent); + + } + }); + } + + + private void setGUI() { + // mClockView=findViewById(R.id.RemTime_Value); + + // TODO assign your views to fields + mValueView = findViewById(R.id.Temp_Value); + d=findViewById(R.id.next); + /*mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + +*/ + + + + + + + + + + + + + + +/* + mNPcrCView = findViewById(R.id.N_Pcr_C); +*/ + + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if(connect.getText().equals("CONNECT")) + { + Toast.makeText(TemplateActivity2.this, "Please connect to device", Toast.LENGTH_SHORT).show(); + + } + else { + if (isChecked) { + getService().heatingSwitch(1); + + + + /* mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + + + + + + + + + // Log.d("Add", String.valueOf(m)); + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); +*/ + + } + else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + }}); + + + /*findViewById(R.id.time_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + + mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); + getService().sendTimeDuration(mSetTime); + } + }); + + findViewById(R.id.temp_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); + getService().sendTemp(mSetTemp); + } + });*/ + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + // TODO clear your UI + mValueView.setText(R.string.not_available_value); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + /*@Override + protected void getAboutTextId() { + Intent intent =new Intent (TemplateActivity2.this,About.class); + startActivity(intent); + } + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.settings_and_about, menu); + return true; + } + + @Override + protected boolean onOptionsItemSelected(final int itemId) { + switch (itemId) { + *//*case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break;*//* + } + return true; + } +*/ + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + // TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog. + // If null is returned no filtering is done. + return TemplateManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return SPCAService.class; + } + + @Override + protected void onServiceBound(final SPCAService.TemplateBinder binder) { + // not used + } + + @Override + protected void onServiceUnbound() { + // not used + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + // Handling updates from the device + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, final int value) { + mValueView.setText(String.valueOf(value)); + + // TODO assign the value to a view + if(mHeatingState.isChecked()) + { + d.postDelayed(new Runnable() { + public void run() { + d.setEnabled(true); + Log.d(TAG, "resend1"); + } + }, 7000); + d.postDelayed(new Runnable() { + public void run() { + act3_1=value; + mValueView.setText(String.valueOf(act3_1)); + Log.d(TAG, "resend1"); + } + }, 5000); + d.postDelayed(new Runnable() { + public void run() { + act3_2=value; + mValueView.setText(String.valueOf(act3_2)); + Log.d(TAG, "resend1"); + } + }, 6000); + d.postDelayed(new Runnable() { + public void run() { + act3_3=value; + mValueView.setText(String.valueOf(act3_3)); + Log.d(TAG, "resend1"); + } + }, 7000); + + + } + /*else if (!mHeatingState.isChecked() && count ==1) { + + love=1; + count=2; + Log.d("check1", String.valueOf(love)); + + mValueView.setText("_"); + Log.d("love", String.valueOf(love)); + Log.d("love", String.valueOf(p)); + + + } + else if ( mHeatingState.isChecked() && love ==1 ) + { + q=value; + final int d=value; + Log.d("Addq", String.valueOf(q)); + + mValueView.setText(String.valueOf(d)); + love1=1; + } + else if(!mHeatingState.isChecked() && love1 ==1) + { + love3=1; + mValueView.setText("_"); + Log.d("check1", String.valueOf(love)); + + + + } + else if(mHeatingState.isChecked() && love3 ==1) + { + r=value; + mValueView.setText(String.valueOf(value)); + Log.d("Addr", String.valueOf(r)); + + + + } +*/ + else + { + mValueView.setText("_"); + + } + } + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(SPCAService.EXTRA_DEVICE); + + if (SPCAService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + final int value = intent.getIntExtra(SPCAService.EXTRA_DATA, 0); + // Update GUI + setValueOnView(device, value); + } else if (SPCAService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(SPCAService.EXTRA_BATTERY_LEVEL, 0); + // Update GUI + onBatteryLevelChanged(device, batteryLevel); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(SPCAService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(SPCAService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_home: + Intent intent = new Intent(TemplateActivity2.this, MainActivity.class); + + + startActivity(intent); + + + break; + case R.id.nav_addtest: + Intent intent2 = new Intent(TemplateActivity2.this, TestDetails.class); + + + startActivity(intent2); + break; + case R.id.nav_add_sample: + Intent intent3 = new Intent(TemplateActivity2.this, TemplateActivity2.class); + + + startActivity(intent3); + break; + } + + return true; + } + }; + @Override + public void onBackPressed() { + //super.onBackPressed(); + IsFinish("Want to exit Test ?"); + } + + public void IsFinish(String alertmessage) { + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent(TemplateActivity2.this, TestDetails.class); + + + startActivity(intent); + break; + + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(alertmessage) + .setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + AlertDialog alertDialog = builder.create(); + alertDialog.show(); + alertDialog.getButton(Dialog.BUTTON_NEGATIVE).setTextColor(Color.BLACK); + alertDialog.getButton(Dialog.BUTTON_POSITIVE).setTextColor(Color.BLACK); + + alertDialog.getButton(Dialog.BUTTON_NEGATIVE). + setBackgroundColor(Color.TRANSPARENT); + alertDialog.getButton(Dialog.BUTTON_POSITIVE). + setBackgroundColor(Color.TRANSPARENT); + + } + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity3.java b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity3.java new file mode 100644 index 0000000..8295a01 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateActivity3.java @@ -0,0 +1,391 @@ +package no.Reader.android.iisc.Reader; + +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.Switch; +import android.widget.TextView; + + +import java.util.UUID; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.profile.BleProfileService; +import no.Reader.android.iisc.profile.BleProfileServiceReadyActivity; + + +/** + * Modify the Template Activity to match your needs. + */ +public class TemplateActivity3 extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "TemplateActivity"; + + // TODO change view references to match your need + private TextView mValueView; + private TextView mHeatingStatusView; + + private Switch mHeatingState ; + int p ,q,r; + int count =0; + int love=0; + int love1=0; + int love2=0; + int love3=0; + private TextView mClockView; + int act1=0; + private Button d,next; + String value1,value2,value3; + + /*private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + + private TextView mClockView; + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + + private EditText mNPcrCView; + private Integer mNPcrC ; + +*/ + @Override + protected void onCreateView(final Bundle savedInstanceState) { + // TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample + setContentView(R.layout.activity_feature_template3); + setGUI(); + SharedPreferences preferences6 = getSharedPreferences("PhoneBook", MODE_PRIVATE); + + value1 = preferences6.getString("act1", null); + SharedPreferences preferences7 = getSharedPreferences("PhoneBook1", MODE_PRIVATE); + value2 = preferences7.getString("act2", null); + + SharedPreferences preferences8 = getSharedPreferences("PhoneBook2", MODE_PRIVATE); + + value3 = preferences8.getString("act3", null); + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + Intent intent =new Intent (TemplateActivity3.this,TemplateActivity.class); + startActivity(intent); + } + }); + + + Log.d("value1", String.valueOf(value1)); + Log.d("value2", String.valueOf(value2)); + + Log.d("value3", String.valueOf(value3)); + + } + + + private void setGUI() { + // mClockView=findViewById(R.id.RemTime_Value); + + // TODO assign your views to fields +// mValueView = findViewById(R.id.Temp_Value); +// d=findViewById(R.id.next); + /*mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + +*/ + + + + + + + + + + + + + + +/* + mNPcrCView = findViewById(R.id.N_Pcr_C); +*/ + + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + next=findViewById(R.id.next); + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + getService().heatingSwitch(1); + + + + /* mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + + + + + + + + + // Log.d("Add", String.valueOf(m)); + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); +*/ + + } + else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + }); + + + /*findViewById(R.id.time_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + + mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); + getService().sendTimeDuration(mSetTime); + } + }); + + findViewById(R.id.temp_set_button).setOnClickListener(v -> { + if (isDeviceConnected()) { + mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); + getService().sendTemp(mSetTemp); + } + });*/ + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + // TODO clear your UI + mValueView.setText(R.string.not_available_value); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + /*@Override + protected void getAboutTextId() { + Intent intent =new Intent (TemplateActivity3.this,About.class); + startActivity(intent); + } + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.settings_and_about, menu); + return true; + } + + @Override + protected boolean onOptionsItemSelected(final int itemId) { + switch (itemId) { + *//*case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break;*//* + } + return true; + } +*/ + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + // TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog. + // If null is returned no filtering is done. + return TemplateManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return SPCAService.class; + } + + @Override + protected void onServiceBound(final SPCAService.TemplateBinder binder) { + // not used + } + + @Override + protected void onServiceUnbound() { + // not used + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + // Handling updates from the device + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, final int value) { + // TODO assign the value to a view + if(mHeatingState.isChecked()) + { + act1=value; + mValueView.setText(String.valueOf(act1)); + + } + /*else if (!mHeatingState.isChecked() && count ==1) { + + love=1; + count=2; + Log.d("check1", String.valueOf(love)); + + mValueView.setText("_"); + Log.d("love", String.valueOf(love)); + Log.d("love", String.valueOf(p)); + + + } + else if ( mHeatingState.isChecked() && love ==1 ) + { + q=value; + final int d=value; + Log.d("Addq", String.valueOf(q)); + + mValueView.setText(String.valueOf(d)); + love1=1; + } + else if(!mHeatingState.isChecked() && love1 ==1) + { + love3=1; + mValueView.setText("_"); + Log.d("check1", String.valueOf(love)); + + + + } + else if(mHeatingState.isChecked() && love3 ==1) + { + r=value; + mValueView.setText(String.valueOf(value)); + Log.d("Addr", String.valueOf(r)); + + + + } +*/ + else + { + mValueView.setText("_"); + + } + } + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(SPCAService.EXTRA_DEVICE); + + if (SPCAService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + final int value = intent.getIntExtra(SPCAService.EXTRA_DATA, 0); + // Update GUI + setValueOnView(device, value); + } else if (SPCAService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(SPCAService.EXTRA_BATTERY_LEVEL, 0); + // Update GUI + onBatteryLevelChanged(device, batteryLevel); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(SPCAService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(SPCAService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TemplateManager.java b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateManager.java new file mode 100644 index 0000000..bf5244c --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TemplateManager.java @@ -0,0 +1,959 @@ +package no.Reader.android.iisc.Reader; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import androidx.annotation.NonNull; + +import android.util.Log; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.data.Data; +import no.nordicsemi.android.log.LogContract; +import no.Reader.android.iisc.battery.BatteryManager; +import no.Reader.android.iisc.parser.SPCAParser; +import no.Reader.android.iisc.Reader.callback.SPCADataCallback; + + +/** + * Modify to template manager to match your requirements. + * The TemplateManager extends {@link BatteryManager}, but it may easily extend {@link BleManager} + * instead if you don't need Battery Service support. If not, also modify the + * {@link SPCAManagerCallbacks} to extend {@link no.nordicsemi.android.ble.BleManagerCallbacks} + * and replace BatteryManagerGattCallback to BleManagerGattCallback in this class. + */ +public class TemplateManager extends BatteryManager { + // TODO Replace the services and characteristics below to match your device. + /** + * The service UUID. + */ + /*static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); // Heart Rate service + *//** + * A UUID of a characteristic with notify property. + *//* + //private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + //private static final UUID TEMPERATURE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + *//** + * A UUID of a characteristic with read property. + *//* + //private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Body Sensor Location + + *//** + * A UUID of a characteristic with write property. + *//* + private static final UUID D_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001503-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001504-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001505-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Device Name + + + *//** + * A UUID of a characteristic with write property. + *//* + private static final UUID D_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001509-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001510-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001511-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001515-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001508-1212-efde-1523-785feabcd123"); // Device Name + + + private static final UUID N_PCR_C_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001512-1212-efde-1523-785feabcd123"); // Device Name + + *//** + * A UUID of a characteristic with write property. + *//* + private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001513-1212-efde-1523-785feabcd123"); // Device Name + + *//** + * Some other service UUID. + *//* + private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service + *//** + * A UUID of a characteristic with write property. + *//* + private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); // Device Name +*/ + + static final UUID SERVICE_UUID = UUID.fromString("00001600-1212-efde-1523-785feabcd123"); // Heart Rate service + + /** + * A UUID of a characteristic with notify property. + */ + //private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + //private static final UUID TEMPERATURE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + /** + * A UUID of a characteristic with read property. + */ + //private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001601-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID CLOCK_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Body Sensor Location + + /** + * A UUID of a characteristic with write property. + */ + private static final UUID D_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID S_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + + + /** + * A UUID of a characteristic with write property. + */ + private static final UUID D_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + + private static final UUID S_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name00001604-1212-efde-1523-785feabcd123 + + private static final UUID N_PCR_C_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + + /** + * A UUID of a characteristic with write property. + */ + private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001604-1212-efde-1523-785feabcd123"); // Device Name + + /** + * Some other service UUID. + */ + private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service + /** + * A UUID of a characteristic with write property. + */ + private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); // Device Name + + // TODO Add more services and characteristics references. + + private BluetoothGattCharacteristic mReadBlockTempCharacteristic, mSetDTempCharacteristic, mSetDTimeCharacteristic, mSetATempCharacteristic, mSetATimeCharacteristic, mSetETempCharacteristic, mSetETimeCharacteristic, mSetNPcrCCharacteristic, mAmpStartStopCharacteristic, mDeviceNameCharacteristic, mRequiredCharacteristic, mOptionalCharacteristic + ,mSetLTempCharacteristic,mSetOTempCharacteristic,mSetLTimeCharacteristic,mSetOTimeCharacteristic; + + public TemplateManager(final Context context) { + super(context); + } + + @NonNull + @Override + protected BatteryManagerGattCallback getGattCallback() { + return mGattCallback; + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, + * receiving indication, etc. + */ + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { + + @Override + protected void initialize() { + // Initialize the Battery Manager. It will enable Battery Level notifications. + // Remove it if you don't need this feature. + super.initialize(); + + // TODO Initialize your manager here. + // Initialization is done once, after the device is connected. Usually it should + // enable notifications or indications on some characteristics, write some data or + // read some features / version. + // After the initialization is complete, the onDeviceReady(...) method will be called. + + // Increase the MTU + requestMtu(43)//requestMtu(43) + .with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu)) + .done(device -> { + // You may do some logic in here that should be done when the request finished successfully. + // In case of MTU this method is called also when the MTU hasn't changed, or has changed + // to a different (lower) value. Use .with(...) to get the MTU value. + }) + .fail((device, status) -> log(Log.WARN, "MTU change not supported")) + .enqueue(); + + // Set notification callback + setNotificationCallback(mReadBlockTempCharacteristic) + // This callback will be called each time the notification is received + .with(new SPCADataCallback() { + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + if(data!=null) { + log(LogContract.Log.Level.APPLICATION, SPCAParser.parse(data)); + + super.onDataReceived(device, data); + } + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + // Let's lass received data to the service + mCallbacks.onSampleValueReceived(device, value); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(Log.WARN, "Invalid data received: " + data); + } + }); + + // Enable notifications + enableNotifications(mReadBlockTempCharacteristic) + // Method called after the data were sent (data will contain 0x0100 in this case) + .with((device, data) -> log(Log.DEBUG, "Data sent: " + data)) + // Method called when the request finished successfully. This will be called after .with(..) callback + .done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully")) + // Methods called in case of an error, for example when the characteristic does not have Notify property + .fail((device, status) -> log(Log.WARN, "Failed to enable notifications")) + .enqueue(); + } + + @Override + protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { + // TODO Initialize required characteristics. + // It should return true if all has been discovered (that is that device is supported). + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mReadBlockTempCharacteristic = service.getCharacteristic(TEMP_READABLE_CHARACTERISTIC_UUID); + + mSetDTempCharacteristic = service.getCharacteristic(D_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetDTimeCharacteristic = service.getCharacteristic(D_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetATempCharacteristic = service.getCharacteristic(A_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetATimeCharacteristic = service.getCharacteristic(A_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetETempCharacteristic = service.getCharacteristic(E_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetETimeCharacteristic = service.getCharacteristic(E_TIME_WRITABLE_CHARACTERISTIC_UUID); + + mSetLTempCharacteristic = service.getCharacteristic(L_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetLTimeCharacteristic = service.getCharacteristic(L_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetOTempCharacteristic = service.getCharacteristic(O_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetOTimeCharacteristic = service.getCharacteristic(O_TIME_WRITABLE_CHARACTERISTIC_UUID); + + + mSetNPcrCCharacteristic = service.getCharacteristic(N_PCR_C_WRITABLE_CHARACTERISTIC_UUID); + + mAmpStartStopCharacteristic = service.getCharacteristic(AMP_WRITABLE_CHARACTERISTIC_UUID); + } + final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID); + if (otherService != null) { + mDeviceNameCharacteristic = otherService.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + + return mReadBlockTempCharacteristic != null && mSetDTempCharacteristic != null && mSetDTimeCharacteristic!= null && mSetATempCharacteristic != null && mSetATimeCharacteristic!= null && mSetETempCharacteristic != null && mSetLTempCharacteristic != null && mSetETimeCharacteristic!= null && mSetOTempCharacteristic != null && mSetLTimeCharacteristic!= null && mSetOTimeCharacteristic!= null && mSetNPcrCCharacteristic!= null && mAmpStartStopCharacteristic != null ; + } + + @Override + protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + // Initialize Battery characteristic + super.isOptionalServiceSupported(gatt); + + // TODO If there are some optional characteristics, initialize them there. + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + return mOptionalCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + // Release Battery Service + super.onDeviceDisconnected(); + + // TODO Release references to your characteristics. + mRequiredCharacteristic = null; + mDeviceNameCharacteristic = null; + mOptionalCharacteristic = null; + } + + @Override + protected void onDeviceReady() { + super.onDeviceReady(); + + // Initialization is now ready. + // The service or activity has been notified with no.nordicsemi.android.ble.BatteryManagerCallbacks#onDeviceReady(). + // TODO Do some extra logic here, of remove onDeviceReady(). + + // Device is ready, let's read something here. Usually there is nothing else to be done + // here, as all had been done during initialization. + readCharacteristic(mReadBlockTempCharacteristic) + .with((device, data) -> { + // Characteristic value has been read + // Let's do some magic with it. + if (data.size() > 0) { + final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); + log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); + } else { + log(Log.WARN, "Value is empty!"); + } + }) + .enqueue(); + } + }; + + // TODO Define manager's API + + /** + * This method will write important data to the device. + * + * @param parameter parameter to be written. + */ + + + //Heating Switch + void heatingSwitch(int state) { + log(Log.WARN, "Write time duration \"" + state + "\""); + //final byte time_in_byte = time_duration.getBytes()[0]; + final byte state_in_byte = (byte) state; + writeCharacteristic(mAmpStartStopCharacteristic, Data.opCode(state_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Heating State")) + .split() + .enqueue(); + + } + + //Set Time + void sendDTime(int d_time) { + log(Log.WARN, "Write D Time Duration \"" + d_time + "\""); + final byte d_time_in_byte = (byte) d_time; + writeCharacteristic(mSetDTimeCharacteristic, Data.opCode(d_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendATime(int a_time) { + log(Log.WARN, "Write A Time Duration \"" + a_time + "\""); + final byte a_time_in_byte = (byte) a_time; + writeCharacteristic(mSetATimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + void sendLTime(int l_time) { + log(Log.WARN, "Write A Time Duration \"" + l_time + "\""); + final byte l_time_in_byte = (byte) l_time; + writeCharacteristic(mSetLTimeCharacteristic, Data.opCode(l_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendOTime(int o_time) { + log(Log.WARN, "Write A Time Duration \"" + o_time + "\""); + final byte a_time_in_byte = (byte) o_time; + writeCharacteristic(mSetOTimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + void sendETime(int e_time) { + log(Log.WARN, "Write E Time Duration \"" + e_time + "\""); + final byte e_time_in_byte = (byte) e_time; + writeCharacteristic(mSetETimeCharacteristic, Data.opCode(e_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + //Set Temp + void sendDTemp(int d_temp) { + log(Log.WARN, "Write D temp \"" + d_temp + "\""); + final byte d_temp_in_byte = (byte) d_temp; + writeCharacteristic(mSetDTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + void sendLTemp(int l_temp) { + log(Log.WARN, "Write D temp \"" + l_temp + "\""); + final byte d_temp_in_byte = (byte) l_temp; + writeCharacteristic(mSetLTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendOTemp(int o_temp) { + log(Log.WARN, "Write D temp \"" + o_temp + "\""); + final byte d_temp_in_byte = (byte) o_temp; + writeCharacteristic(mSetOTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + + + + + + + + void sendATemp(int a_temp) { + log(Log.WARN, "Write A temp \"" + a_temp + "\""); + final byte a_temp_in_byte = (byte) a_temp; + writeCharacteristic(mSetATempCharacteristic, Data.opCode(a_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + void sendETemp(int e_temp) { + log(Log.WARN, "Write E temp \"" + e_temp + "\""); + final byte e_temp_in_byte = (byte) e_temp; + writeCharacteristic(mSetETempCharacteristic, Data.opCode(e_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendNPcrC(int n_pcr_c) { + log(Log.WARN, "Write E temp \"" + n_pcr_c + "\""); + final byte n_pcr_c_in_byte = (byte) n_pcr_c; + writeCharacteristic(mSetNPcrCCharacteristic, Data.opCode(n_pcr_c_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + +} + + + + + + + + + +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *//* + +package no.Reader.android.iisc.template; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import androidx.annotation.NonNull; + +import android.util.Log; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.data.Data; +import no.nordicsemi.android.log.LogContract; +import no.Reader.android.iisc.battery.BatteryManager; +import no.Reader.android.iisc.parser.SPCAParser; +import no.Reader.android.iisc.template.callback.SPCADataCallback; + + +*/ +/** + * Modify to template manager to match your requirements. + * The TemplateManager extends {@link BatteryManager}, but it may easily extend {@link BleManager} + * instead if you don't need Battery Service support. If not, also modify the + * {@link TemplateManagerCallbacks} to extend {@link no.nordicsemi.android.ble.BleManagerCallbacks} + * and replace BatteryManagerGattCallback to BleManagerGattCallback in this class. + *//* + +public class TemplateManager extends BatteryManager { + // TODO Replace the services and characteristics below to match your device. + */ +/** + * The service UUID. + *//* + + */ +/*static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); // Heart Rate service + *//* +*/ +/** + * A UUID of a characteristic with notify property. + *//* +*/ +/* + //private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + //private static final UUID TEMPERATURE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + *//* +*/ +/** + * A UUID of a characteristic with read property. + *//* +*/ +/* + //private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Body Sensor Location + + *//* +*/ +/** + * A UUID of a characteristic with write property. + *//* +*/ +/* + private static final UUID D_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001503-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001504-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001505-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Device Name + + + *//* +*/ +/** + * A UUID of a characteristic with write property. + *//* +*/ +/* + private static final UUID D_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001509-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001510-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001511-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001515-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001508-1212-efde-1523-785feabcd123"); // Device Name + + + private static final UUID N_PCR_C_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001512-1212-efde-1523-785feabcd123"); // Device Name + + *//* +*/ +/** + * A UUID of a characteristic with write property. + *//* +*/ +/* + private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001513-1212-efde-1523-785feabcd123"); // Device Name + + *//* +*/ +/** + * Some other service UUID. + *//* +*/ +/* + private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service + *//* +*/ +/** + * A UUID of a characteristic with write property. + *//* +*/ +/* + private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); // Device Name +*//* + + + static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); // Heart Rate service + + */ +/** + * A UUID of a characteristic with notify property. + *//* + + //private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + //private static final UUID TEMPERATURE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement + */ +/** + * A UUID of a characteristic with read property. + *//* + + //private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); // Body Sensor Location + private static final UUID CLOCK_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); // Body Sensor Location + + */ +/** + * A UUID of a characteristic with write property. + *//* + + private static final UUID D_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001504-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001506-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001508-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001515-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID S_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001510-1212-efde-1523-785feabcd123"); // Device Name + + + */ +/** + * A UUID of a characteristic with write property. + *//* + + private static final UUID D_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001505-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID A_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001507-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID E_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001509-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID L_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001516-1212-efde-1523-785feabcd123"); // Device Name + private static final UUID O_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001503-1212-efde-1523-785feabcd123"); // Device Name + + private static final UUID S_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001511-1212-efde-1523-785feabcd123"); // Device Name + + private static final UUID N_PCR_C_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001512-1212-efde-1523-785feabcd123"); // Device Name + + */ +/** + * A UUID of a characteristic with write property. + *//* + + private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001513-1212-efde-1523-785feabcd123"); // Device Name + + */ +/** + * Some other service UUID. + *//* + + private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service + */ +/** + * A UUID of a characteristic with write property. + *//* + + private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); // Device Name + + // TODO Add more services and characteristics references. + + private BluetoothGattCharacteristic mReadBlockTempCharacteristic, mSetDTempCharacteristic, mSetDTimeCharacteristic, mSetATempCharacteristic, mSetATimeCharacteristic, mSetETempCharacteristic, mSetETimeCharacteristic, mSetNPcrCCharacteristic, mAmpStartStopCharacteristic, mDeviceNameCharacteristic, mRequiredCharacteristic, mOptionalCharacteristic + ,mSetLTempCharacteristic,mSetOTempCharacteristic,mSetLTimeCharacteristic,mSetOTimeCharacteristic; + + public TemplateManager(final Context context) { + super(context); + } + + @NonNull + @Override + protected BatteryManagerGattCallback getGattCallback() { + return mGattCallback; + } + + */ +/** + * BluetoothGatt callbacks for connection/disconnection, service discovery, + * receiving indication, etc. + *//* + + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { + + @Override + protected void initialize() { + // Initialize the Battery Manager. It will enable Battery Level notifications. + // Remove it if you don't need this feature. + super.initialize(); + + // TODO Initialize your manager here. + // Initialization is done once, after the device is connected. Usually it should + // enable notifications or indications on some characteristics, write some data or + // read some features / version. + // After the initialization is complete, the onDeviceReady(...) method will be called. + + // Increase the MTU + requestMtu(43)//requestMtu(43) + .with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu)) + .done(device -> { + // You may do some logic in here that should be done when the request finished successfully. + // In case of MTU this method is called also when the MTU hasn't changed, or has changed + // to a different (lower) value. Use .with(...) to get the MTU value. + }) + .fail((device, status) -> log(Log.WARN, "MTU change not supported")) + .enqueue(); + + // Set notification callback + setNotificationCallback(mReadBlockTempCharacteristic) + // This callback will be called each time the notification is received + .with(new SPCADataCallback() { + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(LogContract.Log.Level.APPLICATION, SPCAParser.parse(data)); + super.onDataReceived(device, data); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + // Let's lass received data to the service + mCallbacks.onSampleValueReceived(device, value); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(Log.WARN, "Invalid data received: " + data); + } + }); + + // Enable notifications + enableNotifications(mReadBlockTempCharacteristic) + // Method called after the data were sent (data will contain 0x0100 in this case) + .with((device, data) -> log(Log.DEBUG, "Data sent: " + data)) + // Method called when the request finished successfully. This will be called after .with(..) callback + .done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully")) + // Methods called in case of an error, for example when the characteristic does not have Notify property + .fail((device, status) -> log(Log.WARN, "Failed to enable notifications")) + .enqueue(); + } + + @Override + protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { + // TODO Initialize required characteristics. + // It should return true if all has been discovered (that is that device is supported). + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mReadBlockTempCharacteristic = service.getCharacteristic(TEMP_READABLE_CHARACTERISTIC_UUID); + + mSetDTempCharacteristic = service.getCharacteristic(D_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetDTimeCharacteristic = service.getCharacteristic(D_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetATempCharacteristic = service.getCharacteristic(A_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetATimeCharacteristic = service.getCharacteristic(A_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetETempCharacteristic = service.getCharacteristic(E_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetETimeCharacteristic = service.getCharacteristic(E_TIME_WRITABLE_CHARACTERISTIC_UUID); + + mSetLTempCharacteristic = service.getCharacteristic(L_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetLTimeCharacteristic = service.getCharacteristic(L_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetOTempCharacteristic = service.getCharacteristic(O_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetOTimeCharacteristic = service.getCharacteristic(O_TIME_WRITABLE_CHARACTERISTIC_UUID); + + + mSetNPcrCCharacteristic = service.getCharacteristic(N_PCR_C_WRITABLE_CHARACTERISTIC_UUID); + + mAmpStartStopCharacteristic = service.getCharacteristic(AMP_WRITABLE_CHARACTERISTIC_UUID); + } + final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID); + if (otherService != null) { + mDeviceNameCharacteristic = otherService.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + + return mReadBlockTempCharacteristic != null && mSetDTempCharacteristic != null && mSetDTimeCharacteristic!= null && mSetATempCharacteristic != null && mSetATimeCharacteristic!= null && mSetETempCharacteristic != null && mSetLTempCharacteristic != null && mSetETimeCharacteristic!= null && mSetOTempCharacteristic != null && mSetLTimeCharacteristic!= null && mSetOTimeCharacteristic!= null && mSetNPcrCCharacteristic!= null && mAmpStartStopCharacteristic != null ; + } + + @Override + protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + // Initialize Battery characteristic + super.isOptionalServiceSupported(gatt); + + // TODO If there are some optional characteristics, initialize them there. + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + return mOptionalCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + // Release Battery Service + super.onDeviceDisconnected(); + + // TODO Release references to your characteristics. + mRequiredCharacteristic = null; + mDeviceNameCharacteristic = null; + mOptionalCharacteristic = null; + } + + @Override + protected void onDeviceReady() { + super.onDeviceReady(); + + // Initialization is now ready. + // The service or activity has been notified with no.nordicsemi.android.ble.BatteryManagerCallbacks#onDeviceReady(). + // TODO Do some extra logic here, of remove onDeviceReady(). + + // Device is ready, let's read something here. Usually there is nothing else to be done + // here, as all had been done during initialization. + readCharacteristic(mReadBlockTempCharacteristic) + .with((device, data) -> { + // Characteristic value has been read + // Let's do some magic with it. + if (data.size() > 0) { + final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); + log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); + } else { + log(Log.WARN, "Value is empty!"); + } + }) + .enqueue(); + } + }; + + // TODO Define manager's API + + */ +/** + * This method will write important data to the device. + * + * @param parameter parameter to be written. + *//* + + + + //Heating Switch + void heatingSwitch(int state) { + log(Log.WARN, "Write time duration \"" + state + "\""); + //final byte time_in_byte = time_duration.getBytes()[0]; + final byte state_in_byte = (byte) state; + writeCharacteristic(mAmpStartStopCharacteristic, Data.opCode(state_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Heating State")) + .split() + .enqueue(); + + } + + //Set Time + void sendDTime(int d_time) { + log(Log.WARN, "Write D Time Duration \"" + d_time + "\""); + final byte d_time_in_byte = (byte) d_time; + writeCharacteristic(mSetDTimeCharacteristic, Data.opCode(d_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendATime(int a_time) { + log(Log.WARN, "Write A Time Duration \"" + a_time + "\""); + final byte a_time_in_byte = (byte) a_time; + writeCharacteristic(mSetATimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + void sendLTime(int l_time) { + log(Log.WARN, "Write A Time Duration \"" + l_time + "\""); + final byte a_time_in_byte = (byte) l_time; + writeCharacteristic(mSetLTimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendOTime(int o_time) { + log(Log.WARN, "Write A Time Duration \"" + o_time + "\""); + final byte a_time_in_byte = (byte) o_time; + writeCharacteristic(mSetOTimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + void sendETime(int e_time) { + log(Log.WARN, "Write E Time Duration \"" + e_time + "\""); + final byte e_time_in_byte = (byte) e_time; + writeCharacteristic(mSetETimeCharacteristic, Data.opCode(e_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + //Set Temp + void sendDTemp(int d_temp) { + log(Log.WARN, "Write D temp \"" + d_temp + "\""); + final byte d_temp_in_byte = (byte) d_temp; + writeCharacteristic(mSetDTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + void sendLTemp(int l_temp) { + log(Log.WARN, "Write D temp \"" + l_temp + "\""); + final byte d_temp_in_byte = (byte) l_temp; + writeCharacteristic(mSetLTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendOTemp(int o_temp) { + log(Log.WARN, "Write D temp \"" + o_temp + "\""); + final byte d_temp_in_byte = (byte) o_temp; + writeCharacteristic(mSetOTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + + + + + + + + void sendATemp(int a_temp) { + log(Log.WARN, "Write A temp \"" + a_temp + "\""); + final byte a_temp_in_byte = (byte) a_temp; + writeCharacteristic(mSetATempCharacteristic, Data.opCode(a_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + void sendETemp(int e_temp) { + log(Log.WARN, "Write E temp \"" + e_temp + "\""); + final byte e_temp_in_byte = (byte) e_temp; + writeCharacteristic(mSetETempCharacteristic, Data.opCode(e_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendNPcrC(int n_pcr_c) { + log(Log.WARN, "Write E temp \"" + n_pcr_c + "\""); + final byte n_pcr_c_in_byte = (byte) n_pcr_c; + writeCharacteristic(mSetNPcrCCharacteristic, Data.opCode(n_pcr_c_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + +} +*/ diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TestDetails.java b/app/src/main/java/no/Reader/android/iisc/Reader/TestDetails.java new file mode 100644 index 0000000..2d3ab81 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TestDetails.java @@ -0,0 +1,150 @@ +package no.Reader.android.iisc.Reader; + +import android.Manifest; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Environment; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.widget.AppCompatCheckBox; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import java.io.File; + +import no.Reader.android.iisc.R; + + +public class TestDetails extends NavigationTop { + private EditText user_name,test_id, per,volume; + private Button Createtest; + int i=0; + File filePath=null; + + private AppCompatCheckBox checkbox; + String flag="false",username,testid,percentage,vol; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.testdetails, null, false); + draw.addView(contentView, 0); + + /* LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_about, null, false); + */ + // setContentView(R.layout.testdetails); + if(ContextCompat.checkSelfPermission(TestDetails.this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(TestDetails.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},23); + } + user_name=findViewById(R.id.username); + test_id=findViewById(R.id.test_id); + per=findViewById(R.id.percent); + volume=findViewById(R.id.volume); + Createtest=findViewById(R.id.createtest); + checkbox = (AppCompatCheckBox) findViewById(R.id.positivesample); + checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { + if (isChecked) { + i=1; + flag="true"; + // show password + } + } + }); + + + Createtest.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (ContextCompat.checkSelfPermission(TestDetails.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(TestDetails.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 23); + } + username = user_name.getText().toString(); + percentage = per.getText().toString(); + + testid = test_id.getText().toString(); + File filePath1 = new File(Environment.getExternalStorageDirectory() + "/" + testid + ".xls"); + + vol = volume.getText().toString(); + + if (username.equals("") || percentage.equals("") || testid.equals("") || vol.equals("")) { + Toast.makeText(TestDetails.this, "Please fill all fields", Toast.LENGTH_SHORT).show(); + + } else if (Integer.parseInt(String.valueOf(percentage)) > 100 || Integer.parseInt(String.valueOf(percentage)) < 1) { + + + Toast.makeText(TestDetails.this, "Enter a valid Percentage Data", Toast.LENGTH_SHORT).show(); + + + } else if (Integer.parseInt(String.valueOf(percentage)) > 100 || Integer.parseInt(String.valueOf(percentage)) < 1) { + + + Toast.makeText(TestDetails.this, "Enter a valid Percentage Data", Toast.LENGTH_SHORT).show(); + + + } else if (filePath1.exists()) { + Toast.makeText(TestDetails.this, "File With this testid already exists please fill other test id", Toast.LENGTH_SHORT).show(); + + } else { + + + if (i == 1) { + Intent intent = new Intent(TestDetails.this, TemplateActivity.class); + SharedPreferences preferences = getSharedPreferences("TestEntry", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + editor.putString("testid", testid); + editor.putString("username", username); + editor.putString("percentage", percentage); + editor.putString("internal", flag); + + editor.putString("volume", vol); + + + editor.commit(); + + + startActivity(intent); + + + } else { + Intent intent = new Intent(TestDetails.this, TemplateActivity1.class); + SharedPreferences preferences = getSharedPreferences("TestEntry", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + // editor.putString(Name, phonenum); + editor.putString("testid", testid); + editor.putString("username", username); + editor.putString("percentage", percentage); + editor.putString("internal", flag); + editor.putString("volume", vol); + + + editor.commit(); + + + startActivity(intent); + } + } + } + }); + + } + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/TestViewHolder.java b/app/src/main/java/no/Reader/android/iisc/Reader/TestViewHolder.java new file mode 100644 index 0000000..a32ae6d --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/TestViewHolder.java @@ -0,0 +1,48 @@ +package no.Reader.android.iisc.Reader; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.Interface.ItemClickListner; + + +public class TestViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener +{ + public TextView txtpatientid, txttimestamp,nikshay,iconfinder,txtsampletype; + public ImageView imageView; + public ItemClickListner listner; + + + public TestViewHolder(View itemView) + { + super(itemView); + + + + + imageView = (ImageView) itemView.findViewById(R.id.icon_profile); + iconfinder=(TextView) itemView.findViewById(R.id.icon_text); + + txtpatientid = (TextView) itemView.findViewById(R.id.patient_Id); + txtsampletype = (TextView) itemView.findViewById(R.id.sample_type); + txttimestamp=itemView.findViewById(R.id.timestamp); + nikshay=itemView.findViewById(R.id.nikshayid); + + //txtProductDescription= (TextView) itemView.findViewById(R.id.switch_toggle); + } + + public void setItemClickListner(ItemClickListner listner) + { + this.listner = listner; + } + + @Override + public void onClick(View view) + { + listner.onClick(view, getAdapterPosition(), false); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/Try1.java b/app/src/main/java/no/Reader/android/iisc/Reader/Try1.java new file mode 100644 index 0000000..0439f0b --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/Try1.java @@ -0,0 +1,293 @@ +package no.Reader.android.iisc.Reader; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Context; +import android.os.Bundle; + + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Environment; +import android.util.Log; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.utils.ColorTemplate; + +import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; + +import no.Reader.android.iisc.R; + + + + public class Try1 extends AppCompatActivity { + String TAG ="main"; + private TextView textView; + BarChart barChart; + ArrayList adcVal; + ArrayList samplelabel; + ArrayList entries = new ArrayList<>(); + ArrayList labels = new ArrayList(); + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_try1); + textView = findViewById(R.id.textview); + barChart = (BarChart) findViewById(R.id.barchart); + + if(ContextCompat.checkSelfPermission(Try1.this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(Try1.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},23); + } + readExcelFileFromAssets(); + } + public void readExcelFileFromAssets() { + if(ContextCompat.checkSelfPermission(Try1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(Try1.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + + try { + + + InputStream myInput; + Context context = null; + File filePath1 = new File(Environment.getExternalStorageDirectory() + "/" +"do.xls"); + File file = new File(getApplicationContext().getExternalFilesDir(null), "do.xls"); + /* fis = new FileInputStream(file); + String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + + File sdcard = Environment.getExternalStorageDirectory(); + File file = new File("/sdcard/Demo.xls"); + if(file.exists()){ + +*/ + if(filePath1.exists()){ + + Toast.makeText(Try1.this, "id exist", Toast.LENGTH_SHORT).show(); + + + + } + else + { + Toast.makeText(Try1.this, "nooo", Toast.LENGTH_SHORT).show(); + + } + + myInput = new FileInputStream(filePath1); + + + // initialize asset manager + /* AssetManager assetManager = getAssets(); + // open excel sheet + myInput = assetManager.open("file_example_XLS_50.xls"); + */ // Create a POI File System object + POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput); + // Create a workbook using the File System + HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem); + // Get the first sheet from workbook + HSSFSheet mySheet = myWorkBook.getSheetAt(0); + int rowCount = mySheet.getLastRowNum(); + + // We now need something to iterate through the cells. + Iterator rowIter = mySheet.rowIterator(); + int[][] arr = new int[0][]; + + for(int i=11;i<=rowCount;i++) + { + + Row row = mySheet.getRow(i); + + //Create a loop to print cell values in a row + + int j =1; + + //Print Excel data in console + labels.add(String.valueOf(row.getCell(j).getStringCellValue())); + + samplelabel.add(String.valueOf(row.getCell(j).getStringCellValue())); +int k=3; + entries.add(new BarEntry(Float.parseFloat(String.valueOf(i)), i-11)); + + + + System.out.println(); + } + + + + + + BarDataSet bardataset = new BarDataSet(entries, "Result"); + + + + BarData data = new BarData(labels, bardataset); + barChart.setData(data); // set the data and list of labels into chart + barChart.setDescription("Bar Graph for Result"); // set the description + bardataset.setColors(ColorTemplate.COLORFUL_COLORS); + barChart.animateY(1000); + + + + + + + + + + + + + + + + + + /* int rowno =0; + textView.append("\n"); + while (rowIter.hasNext()) { + Log.e(TAG, " row no "+ rowno ); + HSSFRow myRow = (HSSFRow) rowIter.next(); + if(rowno !=0) { + Iterator cellIter = myRow.cellIterator(); + Log.e(TAG, " Cell "+ myRow.cellIterator() ); + + int colno =0; + String sno=""; + String date=""; + String det=""; + int value = 0; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno==0){ + value= Integer.parseInt(String.valueOf(myCell)); + Log.e(TAG, " Cell value 1 "+ value ); + + } + if (colno==1){ + sno = myCell.toString(); + Log.e(TAG, " Cell value 2 "+ sno ); + + }else if (colno==2){ + date = myCell.toString(); + Log.e(TAG, " Cell value 3 "+ date ); + + } + colno++; + Log.e(TAG, " Index :" + myCell.getColumnIndex() + " -- " + myCell.toString()); + }*/ + + + + + + + + + + + + + + + + + + + + + + + + + + } catch (Exception e) { + Log.e(TAG, "error "+ e.toString()); + } + change(); + } + private void change() + { + try { + InputStream myInput; + File filePath1 = new File(Environment.getExternalStorageDirectory() + "/" +"file_example_XLS_50.xls"); + + myInput = new FileInputStream(filePath1); + + Workbook workbook = WorkbookFactory.create(myInput); + + Sheet sheet = workbook.getSheetAt(0); + + Object[][] bookData = { + + {51,"love1", "Chad Fowler", "Chad Fowler","Chad Fowler",45,"fff",5555}, + {51,"love2", "Chad Fowler", "Chad Fowler","Chad Fowler",45,"fff",5555}, + {51,"Thggggg", "Chad Fowler", "Chad Fowler","Chad Fowler",45,"fff",5555}, + {51,"The Passionate Program", "Chad Fowler", "Chad Fowler","Chad Fowler",45,"fff",5555}, + + }; + + int rowCount = sheet.getLastRowNum(); + + for (Object[] aBook : bookData) { + Row row = sheet.createRow(++rowCount); + + int columnCount = 0; + + Cell cell = row.createCell(columnCount); + cell.setCellValue(rowCount); + + for (Object field : aBook) { + cell = row.createCell(++columnCount); + if (field instanceof String) { + cell.setCellValue((String) field); + } else if (field instanceof Integer) { + cell.setCellValue((Integer) field); + } + } + + } + + myInput.close(); + + FileOutputStream outputStream = new FileOutputStream(filePath1); + workbook.write(outputStream); + workbook.close(); + outputStream.close(); + + } catch (IOException | EncryptedDocumentException ex) { + ex.printStackTrace(); + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtp.java b/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtp.java new file mode 100644 index 0000000..e864125 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtp.java @@ -0,0 +1,155 @@ +package no.Reader.android.iisc.Reader.VerifyOTP; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthOptions; +import com.google.firebase.auth.PhoneAuthProvider; + +import java.util.concurrent.TimeUnit; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.CreatePassword; + + +public class VerifyOtp extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private Button nextactivity; + private ProgressBar progressBar; + PinView pinFromUser; + private EditText editText; + String codeBySystem; + String address,name, state , city ,pincode,phonenumber,password2,num1,phonenumberke; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_verify__o_t_p); + pinFromUser = findViewById(R.id.firstPinView); + nextactivity = findViewById(R.id.buttonSignIn); + + mAuth = FirebaseAuth.getInstance(); + + + String phonenumberk = getIntent().getStringExtra("numberwithcode"); + phonenumberke = getIntent().getStringExtra("mobile"); + + phonenumber = phonenumberk; + + name = getIntent().getStringExtra("username"); + + + + sendVerificationCode(phonenumber); + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + String code = pinFromUser.getText().toString().trim(); + + if ((code.isEmpty() || code.length() < 6)) { + + editText.setError("Enter code..."); + editText.requestFocus(); + return; + } + verifyCode(code); + + } + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(VerifyOtp.this, CreatePassword.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.putExtra("mobile", phonenumberke); + intent.putExtra("username", name); + + + startActivity(intent); + + } else { + // Toast.makeText(VerifyOTP.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); + } + } + + }); + } + + private void sendVerificationCode(String number){ + + PhoneAuthOptions options = + PhoneAuthOptions.newBuilder(mAuth) + .setPhoneNumber(number) // Phone number to verify + .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit + .setActivity(this) // Activity (for callback binding) + .setCallbacks(mCallBack) // OnVerificationStateChangedCallbacks + .build(); + PhoneAuthProvider.verifyPhoneNumber(options); + + } + + private PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + // progressBar.setVisibility(View.VISIBLE); + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(VerifyOtp.this, e.getMessage(),Toast.LENGTH_LONG).show(); + + } + }; + + + + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtpForgetPassword.java b/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtpForgetPassword.java new file mode 100644 index 0000000..0f1693e --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/VerifyOTP/VerifyOtpForgetPassword.java @@ -0,0 +1,154 @@ +package no.Reader.android.iisc.Reader.VerifyOTP; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthOptions; +import com.google.firebase.auth.PhoneAuthProvider; + +import java.util.concurrent.TimeUnit; + +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.Reader.ForgetPassword; +import no.Reader.android.iisc.Reader.ForgetPasswordReset; + + +public class VerifyOtpForgetPassword extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private Button nextactivity; + private ProgressBar progressBar; + PinView pinFromUser; + private EditText editText; + String codeBySystem; + String address,name, state , city ,pincode,phonenumber,password2,num1,mobile; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_verify__o_t_p); + pinFromUser = findViewById(R.id.firstPinView); + nextactivity = findViewById(R.id.buttonSignIn); + + mAuth = FirebaseAuth.getInstance(); + + + String phonenumberk = getIntent().getStringExtra("mobilecode"); + phonenumber = phonenumberk; + mobile= getIntent().getStringExtra("mobile"); + + + + + sendVerificationCode(phonenumber); + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + String code = pinFromUser.getText().toString().trim(); + + if ((code.isEmpty() || code.length() < 6)) { + + editText.setError("Enter code..."); + editText.requestFocus(); + return; + } + verifyCode(code); + + } + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(VerifyOtpForgetPassword.this, ForgetPasswordReset.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.putExtra("mobile", mobile); + + + startActivity(intent); + + } else { + Toast.makeText(VerifyOtpForgetPassword.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); + } + } + + }); + } + + private void sendVerificationCode(String number){ + PhoneAuthOptions options = + PhoneAuthOptions.newBuilder(mAuth) + .setPhoneNumber(number) // Phone number to verify + .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit + .setActivity(this) // Activity (for callback binding) + .setCallbacks(mCallBack) // OnVerificationStateChangedCallbacks + .build(); + PhoneAuthProvider.verifyPhoneNumber(options); + + + } + + private PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + // progressBar.setVisibility(View.VISIBLE); + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(VerifyOtpForgetPassword.this, e.getMessage(),Toast.LENGTH_LONG).show(); + + } + }; + @Override + public void onBackPressed() { + + Intent intent = new Intent(VerifyOtpForgetPassword.this, ForgetPassword.class); + startActivity(intent); + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/ViewGraph.java b/app/src/main/java/no/Reader/android/iisc/Reader/ViewGraph.java new file mode 100644 index 0000000..0453e77 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/ViewGraph.java @@ -0,0 +1,429 @@ +package no.Reader.android.iisc.Reader; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; + +import android.Manifest; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.StrictMode; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.ImageButton; +import android.widget.TextView; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.utils.ColorTemplate; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; + +import no.Reader.android.iisc.R; + + +public class ViewGraph extends AppCompatActivity { + private TextView result, textadc; + String value1_1, value1_2, value1_3, value2_1, value2_2, value2_3, value3_1, value3_2, value3_3, testid, username, percentage, internal, samplename, volume; + BarChart barChart; + BarData barData; + String string1,string2,string3,string4,string5,string6,string7,string8,string9,number,logi,lati; + + private ProgressDialog loadingBar; + private String TestRandomKey, downloadImageUrl1,saveCurrentDate, saveCurrentTime; +Uri path; + + File filePath3 = null; + private DatabaseReference TestRef; + + File filePath1 = null; + File filePath = null; + String directory_path; + int love = 0; + BarDataSet barDataSet; + ArrayList barEntries; + int positive, negative, sample, positive_value, negative_value, sample_value, sampleraw, sampleraw1, sampleraw2; + int delta = 0; + String resultdata; + int count = 0; + + ImageButton dowbloadd; + ImageButton save; + + + String date, time; + private String TestID = ""; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_view_graph); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + /* BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setOnNavigationItemSelectedListener(navListener); + */ StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); + StrictMode.setVmPolicy(builder.build()); + builder.detectFileUriExposure(); + barChart = (BarChart) findViewById(R.id.barchart); + loadingBar = new ProgressDialog(this); + textadc = findViewById(R.id.textadc); + testid = getIntent().getStringExtra("pid"); + + Log.e("main", "error id "+TestID); + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + + /* LayoutInflater inflater = (LayoutInflater) this + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_feature_template3, null, false); + draw.addView(contentView, 0); + */ + + + + + if (ContextCompat.checkSelfPermission(ViewGraph.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(ViewGraph.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } else { + + + + readExcelFileFromAssets(); + + + + } + + + + + + + } + + + + + + /* private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_result: + Intent intent=new Intent(ViewGraph.this, ViewSamples.class); + + intent.putExtra("pid",testid); + startActivity(intent); + + + break; + case R.id.nav_home: + Intent intent2 = new Intent(ViewGraph.this, MainActivity.class); + + startActivity(intent2); + break; + case R.id.nav_excel: + shared(); + } + + return true; + } + }; +*/ + public void readExcelFileFromAssets() { + if (ContextCompat.checkSelfPermission(ViewGraph.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(ViewGraph.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } + + try { + + + InputStream myInput; + Context context = null; + + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + + + String targetPdf = directory_path + "Report_" + testid + ".xls"; + filePath1 = new File(targetPdf); + + + if (filePath1.exists()) { + + + } else { + // Toast.makeText(ViewGraph.this, "nooo", Toast.LENGTH_SHORT).show(); + + } + + myInput = new FileInputStream(filePath1); + + + POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput); + // Create a workbook using the File System + HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem); + + + ArrayList entries = new ArrayList<>(); + + + BarDataSet bardataset = new BarDataSet(entries, "Result"); + + ArrayList labels = new ArrayList(); + + + // Get the first sheet from workbook + HSSFSheet mySheet = myWorkBook.getSheetAt(0); + + // We now need something to iterate through the cells. + Iterator rowIter = mySheet.rowIterator(); + int rowCount = mySheet.getLastRowNum(); + + + int rowno = 0; + while (rowIter.hasNext()) { + HSSFRow myRow = (HSSFRow) rowIter.next(); + + // 5 + if (rowno != 0 && rowno > 5) { + + + if (rowno == rowCount - 1) { + + + Iterator cellIter = myRow.cellIterator(); + int colno = 0; + String sno = "", date = "", det = "", vald = "", adcvals = "", result = ""; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno == 0) { + sno = myCell.toString(); + } else if (colno == 1) { + date = myCell.toString(); + } else if (colno == 2) { + adcvals = myCell.toString(); + } else if (colno == 3) { + det = myCell.toString(); + } else if (colno == 4) { + vald = myCell.toString(); + } else if (colno == 5) { + result = myCell.toString(); + } + colno++; + } + + if (!result.contains("Positive")) { + + // Toast.makeText(ViewGraph.this, "positive " + result + " File ", Toast.LENGTH_LONG).show(); + + + } else { + // Toast.makeText(ViewGraph.this, "positive " + result + " File ", Toast.LENGTH_LONG).show(); + + bardataset.setColors(ColorTemplate.COLORFUL_COLORS); + + } + if (!det.equals("-")) { + + entries.add(new BarEntry(Float.parseFloat((det)), rowno - 6)); + labels.add(date + "(" + result + ")"); + + + } else { + entries.add(new BarEntry(Float.parseFloat(String.valueOf((0))), rowno - 6)); + labels.add(date + "(" + result + ")"); + + + } + + + textadc.append("Test ID : " +testid+ "\n"); + + + } else { + Iterator cellIter = myRow.cellIterator(); + int colno = 0; + String sno = "", date = "", det = "", result1 = ""; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno == 0) { + sno = myCell.toString(); + } else if (colno == 1) { + date = myCell.toString(); + } else if (colno == 3) { + det = myCell.toString(); + + } else if (colno == 5) { + result1 = myCell.toString(); + } + + colno++; + } + if (!det.equals("-")) { + + entries.add(new BarEntry(Float.parseFloat((det)), rowno - 6)); + labels.add(date + "(" + result1 + ")"); + + } else { + entries.add(new BarEntry(Float.parseFloat(String.valueOf((0))), rowno - 6)); + + labels.add(date + "(" + result1 + ")"); + + } + + } + + } + rowno++; + + } + BarData data = new BarData(labels, bardataset); + barChart.setData(data); // set the data and list of labels into chart + barChart.setDescription("Bar Graph for Result"); // set the description + barChart.animateY(1000); + + } catch (Exception e) { + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu1, menu); + return true; + } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.nav_samples: + Intent intent=new Intent(ViewGraph.this, ViewSamples.class); + + intent.putExtra("pid",testid); + startActivity(intent); + + + return true; + case R.id.nav_home: + Intent intent2 = new Intent(ViewGraph.this, MainActivity.class); + + startActivity(intent2); + return true; + case R.id.nav_excel: + shared(); + return true; + case R.id.nav_share: + srk(); + return true; + + + + default: + return super.onOptionsItemSelected(item); + } + } + + public void srk() + { + if(ContextCompat.checkSelfPermission(ViewGraph.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(ViewGraph.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + else + { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + File file = new File(pat); + + + + + + + + Intent intent=new Intent(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_TEXT,"Report"); + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) { + Uri path= FileProvider.getUriForFile(ViewGraph.this,"no.Reader.android.iisc.fileprovider",file); + intent.putExtra(Intent.EXTRA_STREAM,path); + } + else{ + + intent.putExtra(Intent.EXTRA_STREAM,Uri.fromFile(file)); + } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + + + } + + } + + + + + + + + + + + + + + public void shared() { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + Intent intent = new Intent(Intent.ACTION_VIEW); + File file = new File(pat); + Uri path = FileProvider.getUriForFile(getApplicationContext(), "no.Reader.android.iisc.fileprovider", file); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + } + + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/ViewSamples.java b/app/src/main/java/no/Reader/android/iisc/Reader/ViewSamples.java new file mode 100644 index 0000000..6c0574b --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/ViewSamples.java @@ -0,0 +1,548 @@ +package no.Reader.android.iisc.Reader; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; + +import android.Manifest; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.StrictMode; +import android.util.Log; +import android.view.Gravity; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.ImageButton; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.google.firebase.database.DatabaseReference; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; + +import no.Reader.android.iisc.R; + + +public class ViewSamples extends AppCompatActivity { + private TextView result, textadc; + String value1_1, value1_2, value1_3, value2_1, value2_2, value2_3, value3_1, value3_2, value3_3, testid, username, percentage, internal, samplename, volume; + BarChart barChart; + Uri path; + BarData barData; + String string1,string2,string3,string4,string5,string6,string7,string8,string9,number,logi,lati; + + private ProgressDialog loadingBar; + private String TestRandomKey, downloadImageUrl1,saveCurrentDate, saveCurrentTime; + + + File filePath3 = null; + private DatabaseReference TestRef; + + File filePath1 = null; + File filePath = null; + String directory_path; + int love = 0; + BarDataSet barDataSet; + ArrayList barEntries; + int positive, negative, sample, positive_value, negative_value, sample_value, sampleraw, sampleraw1, sampleraw2; + int delta = 0; + String resultdata; + int count = 0; + + ImageButton dowbloadd; + ImageButton share; + + + String date, time; + private String TestID = ""; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_view_samples); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + // BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + // bottomNav.setOnNavigationItemSelectedListener(navListener); + StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); + StrictMode.setVmPolicy(builder.build()); + builder.detectFileUriExposure(); + loadingBar = new ProgressDialog(this); + testid = getIntent().getStringExtra("pid"); + Log.e("TestIdll",testid); + textadc = findViewById(R.id.textadc); + /* share=findViewById(R.id.share); + share.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(ContextCompat.checkSelfPermission(ViewSamples.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(ViewSamples.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + else + { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + File file = new File(pat); + + + + + + + + Intent intent=new Intent(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_TEXT,"Report"); + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) { + Uri path= FileProvider.getUriForFile(ViewSamples.this,"no.Reader.android.iisc.fileprovider",file); + intent.putExtra(Intent.EXTRA_STREAM,path); + } + else{ + + intent.putExtra(Intent.EXTRA_STREAM,Uri.fromFile(file)); + } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + + + } + + } + }); + */ textadc.append("Test ID : " +testid+ "\n"); + + + + /* LayoutInflater inflater = (LayoutInflater) this + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_feature_template3, null, false); + draw.addView(contentView, 0); + */ + + + + + if(ContextCompat.checkSelfPermission(ViewSamples.this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(ViewSamples.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},23); + } + // init("1","1","1","1","1","1"); + readExcelFileFromAssets(); + } + public void readExcelFileFromAssets() { + if(ContextCompat.checkSelfPermission(ViewSamples.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(ViewSamples.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + + try { + + + InputStream myInput; + Context context = null; + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + + String targetPdf = directory_path + "Report_" +testid+".xls"; + filePath1 = new File(targetPdf); + File file = new File(getApplicationContext().getExternalFilesDir(null), "78.xls"); + /* fis = new FileInputStream(file); + String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + + File sdcard = Environment.getExternalStorageDirectory(); + File file = new File("/sdcard/Demo.xls"); + if(file.exists()){ + +*/ + if(filePath1.exists()){ + + // Toast.makeText(ViewSamples.this, "id exist", Toast.LENGTH_SHORT).show(); + + + + } + else + { + // Toast.makeText(ViewSamples.this, "nooo", Toast.LENGTH_SHORT).show(); + + } + + myInput = new FileInputStream(filePath1); + + + // initialize asset manager + /* AssetManager assetManager = getAssets(); + // open excel sheet + myInput = assetManager.open("file_example_XLS_50.xls"); + */ // Create a POI File System object + POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput); + // Create a workbook using the File System + HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem); + // Get the first sheet from workbook + HSSFSheet mySheet = myWorkBook.getSheetAt(0); + // We now need something to iterate through the cells. + Iterator rowIter = mySheet.rowIterator(); + int rowno =0; + // textView.append("\n"); + while (rowIter.hasNext()) { + HSSFRow myRow = (HSSFRow) rowIter.next(); + if(rowno !=0) { + Iterator cellIter = myRow.cellIterator(); + int colno =0; + String sno="", sampletype="", adcval="",delta="",result="",avgadc=""; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno==0){ + sno = myCell.toString(); + }else if (colno==1){ + sampletype = myCell.toString(); + }else if (colno==2){ + adcval= myCell.toString(); + } + else if (colno==3){ + avgadc= myCell.toString(); + } + else if (colno==4){ + delta= myCell.toString(); + } + else if (colno==5){ + result= myCell.toString(); + } + colno++; + } + // init1(sno); + Log.e("s",sno); + init(sno,sampletype,adcval,avgadc,delta,result); + // textView.append( sno + " "+ sampletype+" "+ adcval+" "+avgadc+" "+delta+" "+result+ " "+"\n"); + } + rowno++; + } + } catch (Exception e) { + } + } + public void init(String sno ,String sampletype,String adcval,String avgadc ,String delta,String result) { + + TableLayout stk = (TableLayout) findViewById(R.id.table_main); + + /* TableRow tbrow0 = new TableRow(this); + TextView tv0 = new TextView(this); + tv0.setText(" Sl.No "); + tv0.setTextColor(Color.WHITE); + tbrow0.addView(tv0); + TextView tv1 = new TextView(this); + tv1.setText(" Product "); + tv1.setTextColor(Color.WHITE); + tbrow0.addView(tv1); + TextView tv2 = new TextView(this); + tv2.setText(" Unit Price "); + tv2.setTextColor(Color.WHITE); + tbrow0.addView(tv2); + TextView tv3 = new TextView(this); + tv3.setText(" Stock Remaining "); + tv3.setTextColor(Color.WHITE); + tbrow0.addView(tv3); + stk.addView(tbrow0);*/ + TableRow tbrow = new TableRow(this); + TextView t1v = new TextView(this); + t1v.setText("" + sno +" "); + t1v.setGravity(Gravity.CENTER); + tbrow.addView(t1v); + TextView t2v = new TextView(this); + t2v.setText(sampletype+" "); + t2v.setGravity(Gravity.CENTER); + tbrow.addView(t2v); + TextView t3v = new TextView(this); + t3v.setText(adcval+" "); + t3v.setGravity(Gravity.CENTER); + tbrow.addView(t3v); + TextView t4v = new TextView(this); + t4v.setText(avgadc+" "); + t4v.setGravity(Gravity.CENTER); + tbrow.addView(t4v); + + TextView t5v = new TextView(this); + t5v.setText(delta+" "); + t5v.setGravity(Gravity.CENTER); + tbrow.addView(t5v); + + + TextView t6v = new TextView(this); + t6v.setText(" "+result); + t6v.setGravity(Gravity.CENTER); + + tbrow.addView(t6v); + + + + stk.addView(tbrow); + + + + + + + + /* TableRow tbrow0 = new TableRow(this); + TextView tv0 = new TextView(this); + tv0.setText(" Sl.No "); + tv0.setTextColor(Color.WHITE); + tbrow0.addView(tv0); + TextView tv1 = new TextView(this); + tv1.setText(" Product "); + tv1.setTextColor(Color.WHITE); + tbrow0.addView(tv1); + TextView tv2 = new TextView(this); + tv2.setText(" Unit Price "); + tv2.setTextColor(Color.WHITE); + tbrow0.addView(tv2); + TextView tv3 = new TextView(this); + tv3.setText(" Stock Remaining "); + tv3.setTextColor(Color.WHITE); + tbrow0.addView(tv3); + stk.addView(tbrow0);*/ + + } + + + public void init1(String sno ) { + + TableLayout stk = (TableLayout) findViewById(R.id.table_main); + + TableRow tbrow0 = new TableRow(this); + TextView tv0 = new TextView(this); + tv0.setText(" Sl.No "); + tbrow0.addView(tv0); + TextView tv1 = new TextView(this); + tv1.setText(" Product "); + tbrow0.addView(tv1); + TextView tv2 = new TextView(this); + tv2.setText(" Unit Price "); + tbrow0.addView(tv2); + TextView tv3 = new TextView(this); + tv3.setText(" Stock Remaining "); + tbrow0.addView(tv3); + stk.addView(tbrow0); + TableRow tbrow = new TableRow(this); + TextView t1v = new TextView(this); + t1v.setText("" + sno); + t1v.setGravity(Gravity.CENTER); + tbrow.addView(t1v); + + + + stk.addView(tbrow); + + + + + + + + /* TableRow tbrow0 = new TableRow(this); + TextView tv0 = new TextView(this); + tv0.setText(" Sl.No "); + tv0.setTextColor(Color.WHITE); + tbrow0.addView(tv0); + TextView tv1 = new TextView(this); + tv1.setText(" Product "); + tv1.setTextColor(Color.WHITE); + tbrow0.addView(tv1); + TextView tv2 = new TextView(this); + tv2.setText(" Unit Price "); + tv2.setTextColor(Color.WHITE); + tbrow0.addView(tv2); + TextView tv3 = new TextView(this); + tv3.setText(" Stock Remaining "); + tv3.setTextColor(Color.WHITE); + tbrow0.addView(tv3); + stk.addView(tbrow0);*/ + + } + + + + + + + + + + + +/* + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu2, menu); + return true; + } +*/ + +/* + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.nav_graph: + startActivity(new Intent(this, ViewGraph.class)); + return true; + */ +/* return true; + case R.id.help: + startActivity(new Intent(this, Help.class)); + return true;*//* + + default: + return super.onOptionsItemSelected(item); + } + } +*/ + + + + /* private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_graph: + Intent intent=new Intent(ViewSamples.this, ViewGraph.class); + + intent.putExtra("pid",testid); + startActivity(intent); + + + break; + case R.id.nav_home: + Intent intent2 = new Intent(ViewSamples.this, MainActivity.class); + + startActivity(intent2); + break; + case R.id.nav_excel: + shared(); + } + + return true; + } + }; +*/ + public void shared() { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + Intent intent = new Intent(Intent.ACTION_VIEW); + File file = new File(pat); + Uri path = FileProvider.getUriForFile(getApplicationContext(), "no.Reader.android.iisc.fileprovider", file); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu2, menu); + return true; + } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.nav_graph: + Intent intent=new Intent(ViewSamples.this, ViewGraph.class); + + intent.putExtra("pid",testid); + startActivity(intent); + + + return true; + case R.id.nav_home: + Intent intent2 = new Intent(ViewSamples.this, MainActivity.class); + + startActivity(intent2); + return true; + case R.id.nav_excel: + shared(); + return true; + case R.id.nav_share: + srk(); + return true; + + + + default: + return super.onOptionsItemSelected(item); + } + } + +public void srk() +{ + if(ContextCompat.checkSelfPermission(ViewSamples.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(ViewSamples.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + else + { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat= directory_path + "Report_" + testid + ".xls"; + + File file = new File(pat); + + + + + + + + Intent intent=new Intent(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_TEXT,"Report"); + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) { + Uri path= FileProvider.getUriForFile(ViewSamples.this,"no.Reader.android.iisc.fileprovider",file); + intent.putExtra(Intent.EXTRA_STREAM,path); + } + else{ + + intent.putExtra(Intent.EXTRA_STREAM,Uri.fromFile(file)); + } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + + + } + +} + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCACharacteristicCallback.java b/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCACharacteristicCallback.java new file mode 100644 index 0000000..0dac56f --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCACharacteristicCallback.java @@ -0,0 +1,21 @@ +package no.Reader.android.iisc.Reader.callback; + +import android.bluetooth.BluetoothDevice; +import androidx.annotation.NonNull; + +/** + * This class defines your characteristic API. + * In this example (that is the HRM characteristic, which the template is based on), is notifying + * with a value (Heart Rate). The single method just returns the value and ignores other + * optional data from Heart Rate Measurement characteristic for simplicity. + */ +public interface SPCACharacteristicCallback { + + /** + * Called when a value is received. + * + * @param device a device from which the value was obtained. + * @param value the new value. + */ + void onSampleValueReceived(@NonNull final BluetoothDevice device, int value); +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCADataCallback.java b/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCADataCallback.java new file mode 100644 index 0000000..e86e0cb --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/callback/SPCADataCallback.java @@ -0,0 +1,47 @@ +package no.Reader.android.iisc.Reader.callback; + +import android.bluetooth.BluetoothDevice; +import androidx.annotation.NonNull; + +import no.nordicsemi.android.ble.callback.profile.ProfileDataCallback; +import no.nordicsemi.android.ble.data.Data; + +/** + * This is a sample data callback, that's based on Heart Rate Measurement characteristic. + * It parses the HR value and ignores other optional data for simplicity. + * Check {@link no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback} + * for full implementation. + * + * TODO Modify the content to parse your data. + */ +@SuppressWarnings("ConstantConditions") +public abstract class SPCADataCallback implements ProfileDataCallback, SPCACharacteristicCallback { + + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + if (data.size() < 2) { + onInvalidDataReceived(device, data); + return; + } + + // Read flags + int offset = 0; + final int flags = data.getIntValue(Data.FORMAT_UINT8, offset); + final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16; + offset += 1; + + // Validate packet length. The type's lower nibble is its length. + if (data.size() < 1 + (hearRateType & 0x0F)) { + onInvalidDataReceived(device, data); + return; + } + + final int value = data.getIntValue(hearRateType, offset); + // offset += hearRateType & 0xF; + + // ... + + // Report the parsed value(s) + onSampleValueReceived(device, value); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/check1.java b/app/src/main/java/no/Reader/android/iisc/Reader/check1.java new file mode 100644 index 0000000..f8e6dad --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/check1.java @@ -0,0 +1,1654 @@ +package no.Reader.android.iisc.Reader; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; + +import android.Manifest; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.pdf.PdfDocument; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.StrictMode; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.utils.ColorTemplate; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +import no.Reader.android.iisc.R; + + +public class check1 extends AppCompatActivity { + private TextView result, textadc; + String value1_1, value1_2, value1_3, value2_1, value2_2, value2_3, value3_1, value3_2, value3_3, testid, username, percentage, internal, samplename, volume; + BarChart barChart; + Uri path; + + BarData barData; + String string1,string2,string3,string4,string5,string6,string7,string8,string9,number,logi,lati; + + private ProgressDialog loadingBar; + private String TestRandomKey, downloadImageUrl1,saveCurrentDate, saveCurrentTime; + + + File filePath3 = null; + private DatabaseReference TestRef; + + File filePath1 = null; + File filePath = null; + String directory_path; + int love = 0; + BarDataSet barDataSet; + ArrayList barEntries; + int positive, negative, sample, positive_value, negative_value, sample_value, sampleraw, sampleraw1, sampleraw2; + int delta = 0; + String resultdata; + int count = 0; +int internal_data=0; + + + String date, time; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_feature_template3); + BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setOnNavigationItemSelectedListener(navListener); + StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); + StrictMode.setVmPolicy(builder.build()); + builder.detectFileUriExposure(); + barChart = (BarChart) findViewById(R.id.barchart); + loadingBar = new ProgressDialog(this); + textadc = findViewById(R.id.textadc); + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + + /* LayoutInflater inflater = (LayoutInflater) this + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_feature_template3, null, false); + draw.addView(contentView, 0); + */ + SharedPreferences preferences45 = getSharedPreferences("TestEntry", MODE_PRIVATE); + + testid = preferences45.getString("testid", null); + username = preferences45.getString("username", null); + percentage = preferences45.getString("percentage", null); + internal = preferences45.getString("internal", null); + + volume = preferences45.getString("volume", null); + + if (internal.equals("true")) { +internal_data=1; + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_adc1", MODE_PRIVATE); + + value1_1 = preferences6.getString("act1_1", null); + value1_2 = preferences6.getString("act1_2", null); + value1_3 = preferences6.getString("act1_3", null); + + + Log.d("positive 1", String.valueOf(value1_1)); + Log.d("positive 2", String.valueOf(value1_3)); + Log.d("positive 3", String.valueOf(value1_2)); + + + } + SharedPreferences preferences7 = getSharedPreferences("PhoneBook_adc2", MODE_PRIVATE); + value2_1 = preferences7.getString("act2_1", null); + value2_2 = preferences7.getString("act2_2", null); + value2_3 = preferences7.getString("act2_3", null); + Log.d("negative 1", String.valueOf(value2_1)); + Log.d("negative 2", String.valueOf(value2_2)); + + Log.d("negative 3", String.valueOf(value2_3)); + + + SharedPreferences preferences8 = getSharedPreferences("PhoneBook_adc3", MODE_PRIVATE); + + value3_1 = preferences8.getString("act3_1", null); + value3_2 = preferences8.getString("act3_2", null); + value3_3 = preferences8.getString("act3_3", null); + samplename = preferences8.getString("samplename", null); + + Log.d("sample 1", String.valueOf(value3_1)); + Log.d("sample 2", String.valueOf(value3_2)); + + Log.d("sample 3", String.valueOf(value3_3)); + sample = Integer.parseInt(String.valueOf((Integer.parseInt(value3_2) + Integer.parseInt(value3_3)))) / 2; + Log.d("sample actual value ", String.valueOf(sample)); + + + negative = (Integer.parseInt(value2_2) + Integer.parseInt(value2_3)) / 2; + + + sampleraw = sample; + sampleraw1 = sample; + sampleraw2 = sample; + Log.d("avg negative", String.valueOf(negative)); + Log.d(" avg sample ", String.valueOf(sample)); + + + + + + result = findViewById(R.id.result); + + date = String.valueOf(android.text.format.DateFormat.format("dd-MM-yyyy", new java.util.Date())); + DateFormat df = new SimpleDateFormat("h:mm a"); + time = df.format(Calendar.getInstance().getTime()); + + + + /* Log.d("value1_1", String.valueOf(value3_1)); + positive = (Integer.parseInt(value1_2) + Integer.parseInt(value1_3)) / 2; + + sample = (Integer.parseInt(value3_2) + Integer.parseInt(value3_3)) / 2; +*/ + if (internal.equals("true")) { + positive = (Integer.parseInt(value1_2) + Integer.parseInt(value1_3)) / 2; + negative = (Integer.parseInt(value2_2) + Integer.parseInt(value2_3)) / 2; + + delta = positive - negative; + // delta=positive-sample; + Log.d(" delta ", String.valueOf(delta)); + + int p = Integer.parseInt(percentage); + int b = p / 100; + if (sample > (((Integer.parseInt(percentage) * delta)) / 100) + negative) { + resultdata = "Positive"; + result.setText("Result : Positive"); + Log.d("result", "error " + String.valueOf(((Integer.parseInt(percentage) * sample)) / 100)); + down(); + + } else { + result.setText("Result : Negative"); + resultdata = "Negative"; + Log.d("result", "error " + String.valueOf(((Integer.parseInt(percentage) * sample)) / 100)); + down(); + + + } + + File filePath2 = new File(Environment.getExternalStorageDirectory() + "/" + testid + ".xls"); +/*if(!filePath2.exists()) { + + + + + + + ArrayList entries = new ArrayList<>(); + entries.add(new BarEntry(Float.parseFloat(String.valueOf(positive)), 0)); + entries.add(new BarEntry(Float.parseFloat(String.valueOf(negative)), 1)); + entries.add(new BarEntry(Float.parseFloat(String.valueOf(sampleraw1)), 2)); + + + BarDataSet bardataset = new BarDataSet(entries, "Result"); + + ArrayList labels = new ArrayList(); + labels.add("Positive AVG"); + + + labels.add("Negative AVG"); + labels.add("Sample AVG"); + + + BarData data = new BarData(labels, bardataset); + barChart.setData(data); // set the data and list of labels into chart + barChart.setDescription("Bar Graph for Result"); // set the description + bardataset.setColors(ColorTemplate.COLORFUL_COLORS); + barChart.animateY(1000); +} +else { + try { + Thread.sleep(7000); + readExcelFileFromAssets(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + +}*/ + } else { + if (sample > (((Integer.parseInt(percentage) * negative)) / 100)) { + resultdata = "Positive"; + + result.setText("Result : Positive"); + Log.d("result", "error " + String.valueOf((Integer.parseInt(percentage) / 100) * negative)); + down(); + + } else { + resultdata = "Negative"; + + result.setText("Result : Negative"); + Log.d("result", "error " + String.valueOf((Integer.parseInt(percentage) / 100) * negative)); + down(); + + } + + + File filePath3 = new File(Environment.getExternalStorageDirectory() + "/" + testid + ".xls"); + +/* +if(!filePath3.exists()) { + ArrayList entries = new ArrayList<>(); + entries.add(new BarEntry(Float.parseFloat(String.valueOf(negative)), 0)); + entries.add(new BarEntry(Float.parseFloat(String.valueOf(sampleraw2)), 1)); += + + BarDataSet bardataset = new BarDataSet(entries, "Result"); + + ArrayList labels = new ArrayList(); + + + labels.add("Negative AVG"); + labels.add("Sample AVG"); + + + BarData data = new BarData(labels, bardataset); + barChart.setData(data); // set the data and list of labels into chart + barChart.setDescription("Bar Graph for Result"); // set the description + bardataset.setColors(ColorTemplate.COLORFUL_COLORS); + barChart.animateY(1000); +} +*/ +/* +else { + + + + + + + + + + */ +/* try { + Thread.sleep(7000); + readExcelFileFromAssets(); + + } catch (InterruptedException e) { + e.printStackTrace(); + }*//* + +} +*/ + + } + + + + + + + + + + + + + + + + // down(); + + + + + + + + + + +/* + save.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ValidateProductData(); + + } + }); +*/ +/* + dowbloadd.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View view) { + + dowbloadd.isEnabled(); + if (ContextCompat.checkSelfPermission(check1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(check1.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } else { + + try { + buttonCreateExcel(); + ValidateProductData(); + + } catch (IOException e) { + e.printStackTrace(); + } + loadingBar.setTitle("Saving Sample Data "); + loadingBar.setMessage("Please wait, while we are saving the data in " + testid + "File"); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + readExcelFileFromAssets(); + loadingBar.dismiss(); + + Toast.makeText(check1.this, "Data Saved Successfully in " + testid + " File ", Toast.LENGTH_LONG).show(); + + + } + }, 5000); + + + } + + } + + + }); +*/ + + + } + + private void ValidateProductData() + { + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(check1.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } + else { + StoreProductInformation(); + } + + } + + /* barChart=findViewById(R.id.chart); + barEntries=new ArrayList<>(); + barEntries.add(new BarEntry(1,Integer.parseInt(value1))); + barEntries.add(new BarEntry(2,Integer.parseInt(value1))); + + barEntries.add(new BarEntry(3,Integer.parseInt(value1))); + + + barDataSet=new BarDataSet(barEntries,"Test Results"); + barData=new BarData(barDataSet,barEntries); + barChart.setData(barData); + + +*/ + + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void createPdf() { + PdfDocument document = new PdfDocument(); + + PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(1000, 2000, 1).create(); + + PdfDocument.Page page = document.startPage(pageInfo); + Canvas canvas = page.getCanvas(); + Paint paint = new Paint(); + paint.setTextSize(80); + canvas.drawText("Sample Read Out ", 40, 80, paint); + paint.setTextSize(30); + canvas.drawText("Department of Science and Technology", 30, 120, paint); + paint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText(date, canvas.getWidth() - 40, 40, paint); + canvas.drawText(time, canvas.getWidth() - 40, 80, paint); + paint.setTextAlign(Paint.Align.LEFT); + paint.setColor(Color.rgb(150, 150, 150)); + canvas.drawRect(30, 250, canvas.getWidth() - 30, 300, paint); + paint.setColor(Color.WHITE); + canvas.drawText("Result", 50, 285, paint); + // canvas.drawText("name 2",450,435,paint); + paint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText(resultdata, canvas.getWidth() - 40, 285, paint); + paint.setTextAlign(Paint.Align.LEFT); + + + paint.setColor(Color.rgb(150, 150, 150)); + // canvas.drawRect(30,150,canvas.getWidth()-30,160,paint); + + + canvas.drawRect(30, 400, canvas.getWidth() - 30, 450, paint); + paint.setColor(Color.WHITE); + canvas.drawText("Sample Value", 50, 435, paint); + + canvas.drawText(String.valueOf(sample), canvas.getWidth() - 100, 435, paint); + paint.setTextAlign(Paint.Align.LEFT); + paint.setColor(Color.BLACK); + + canvas.drawText(".", canvas.getWidth() - 40, 480, paint); + + paint.setTextAlign(Paint.Align.RIGHT); + + paint.setColor(Color.rgb(150, 150, 150)); + // canvas.drawRect(30,150,canvas.getWidth()-30,160,paint); + + // canvas.drawRect(30,550,canvas.getWidth()-30,560,paint); + canvas.drawRect(30, 570, canvas.getWidth() - 30, 620, paint); + + + paint.setColor(Color.WHITE); + canvas.drawText("Negative Control Value", 350, 605, paint); + canvas.drawText(String.valueOf(negative), canvas.getWidth() - 40, 605, paint); + paint.setTextAlign(Paint.Align.LEFT); + paint.setColor(Color.BLACK); + + paint.setTextAlign(Paint.Align.RIGHT); + paint.setColor(Color.rgb(150, 150, 150)); + + canvas.drawRect(30, 740, canvas.getWidth() - 30, 790, paint); + + paint.setColor(Color.WHITE); + canvas.drawText("Internal Control Value", 350, 775, paint); + + canvas.drawText(String.valueOf(positive), canvas.getWidth() - 40, 775, paint); + paint.setTextAlign(Paint.Align.LEFT); + paint.setColor(Color.BLACK); + + paint.setTextAlign(Paint.Align.RIGHT); + paint.setColor(Color.rgb(150, 150, 150)); + + // finish the page + document.finishPage(page); + + directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + File file = new File(directory_path); + if (!file.exists()) { + file.mkdirs(); + } + String targetPdf = directory_path + "Report" + ".pdf"; + + filePath = new File(targetPdf); + + try { + document.writeTo(new FileOutputStream(filePath)); + } catch (IOException e) { + Log.e("main", "error " + e.toString()); + } + + document.close(); + + } + +/* + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater=getMenuInflater(); + inflater.inflate(R.menu.download,menu); + MenuItem item1=menu.findItem(R.id.download1); + item1.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + @Override + public boolean onMenuItemClick(MenuItem item) { + if(ContextCompat.checkSelfPermission(check1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) + { + + ActivityCompat.requestPermissions(check1.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},23); + } + else + { + //startCropImageActivity(); + try { + buttonCreateExcel(); + } catch (IOException e) { + e.printStackTrace(); + } + // createPdf(); + // Toast.makeText(check1.this, "File Downloaded", Toast.LENGTH_LONG).show(); + + + + } + + return true; + } + }); + + + return super.onCreateOptionsMenu(menu); + } +*/ + + + public void buttonCreateExcel() throws IOException { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + File file = new File(directory_path); + if (!file.exists()) { + file.mkdirs(); + } + + + String targetPdf = directory_path + "Report_" + testid + ".xls"; + filePath1 = new File(targetPdf); + + + if (filePath1.exists()) { + + + try { + InputStream myInput; + + myInput = new FileInputStream(filePath1); + + Workbook workbook = WorkbookFactory.create(myInput); + + Sheet sheet = workbook.getSheetAt(0); + + + int rowCount = sheet.getLastRowNum(); + Row row = sheet.createRow(++rowCount); + Cell cell0 = row.createCell(0); + cell0.setCellValue(rowCount - 6); + Cell cell1 = row.createCell(1); + cell1.setCellValue(samplename); + Cell cell2 = row.createCell(2); + + cell2.setCellValue("(" + value3_1 + "," + value3_2 + "," + value3_3 + ")"); + + + Cell cell3 = row.createCell(3); + + cell3.setCellValue(sampleraw); + + + if (internal.equals("true")) { + Cell cell4 = row.createCell(4); + cell4.setCellValue(delta); + } else { + Cell cell4 = row.createCell(4); + cell4.setCellValue("-"); + + } + Cell cell5 = row.createCell(5); + cell5.setCellValue(resultdata); + + + myInput.close(); + + FileOutputStream outputStream = new FileOutputStream(filePath1); + workbook.write(outputStream); + workbook.close(); + outputStream.close(); + + } catch (IOException | EncryptedDocumentException ex) { + ex.printStackTrace(); + } + } + + + + + + + + + + + + + + + + /* String excelFilePath = "JavaBooks.xls"; + + try { + FileInputStream inputStream = new FileInputStream(new File(Environment.getExternalStorageDirectory() +"/"+testid+".xls")); + Workbook workbook = WorkbookFactory.create(inputStream); + + Sheet sheet = workbook.getSheetAt(0); + + Object[][] bookData = { + {"The Passionate Programmer", "Chad Fowler", 16}, + {"Software Craftmanship", "Pete McBreen", 26}, + {"The Art of Agile Development", "James Shore", 32}, + {"Continuous Delivery", "Jez Humble", 41}, + }; + + int rowCount = sheet.getLastRowNum(); + Log.d("last row", String.valueOf(row.getLastCellNum())); + + + for (Object[] aBook : bookData) { + Row row = sheet.createRow(++rowCount); + + int columnCount = 0; + + Cell cell = row.createCell(columnCount); + cell.setCellValue(rowCount); + + for (Object field : aBook) { + cell = row.createCell(++columnCount); + if (field instanceof String) { + cell.setCellValue((String) field); + } else if (field instanceof Integer) { + cell.setCellValue((Integer) field); + } + } + + } + + inputStream.close(); + + FileOutputStream outputStream = new FileOutputStream(Environment.getExternalStorageDirectory() +"/"+testid+".xls"); + workbook.write(outputStream); + workbook.close(); + outputStream.close(); + + } catch (IOException | EncryptedDocumentException ex) { + ex.printStackTrace(); + }*/ + + + + + + + + + + + + + + + + + /* FileInputStream fis=new FileInputStream(new File(Environment.getExternalStorageDirectory() +"/"+testid+".xls")); +//creating workbook instance that refers to .xls file + HSSFWorkbook wb=new HSSFWorkbook(fis); +//creating a Sheet object to retrieve the object + HSSFSheet sheet=wb.getSheet("Result Sheet"); + HSSFRow row=sheet.getRow(0); //Get the first row (the row in excel starts from 0 by default, so this is why an excel must have a field column header), that is, a field column header, which is convenient for assignment + Log.d("last row", String.valueOf(row.getLastCellNum())); + + System.out.println(sheet.getLastRowNum()+" "+row.getLastCellNum()); //Get the row number of the last row and the last cell of a record, respectively + + FileOutputStream out=new FileOutputStream(filePath1); //Write data to head.xls + row=sheet.createRow((short)(sheet.getLastRowNum()+1)); //Append data after the existing row number + row.createCell(0).setCellValue("hello"); //Set the data of the first (starting from 0) cell + row.createCell(1).setCellValue(1); //Set the data of the second (starting from 0) cell + + + out.flush(); + wb.write(out); + out.close(); + System.out.println(row.getPhysicalNumberOfCells()+" "+row.getLastCellNum()); + +*/ + + + + + + + /* FileInputStream fs = new FileInputStream(System.getProperty(Environment.getExternalStorageDirectory()+"\\head.xls")); //Get head.xls + POIFSFileSystem ps = new POIFSFileSystem(fs); //Use the method provided by POI to get excel information + HSSFWorkbook wb = new HSSFWorkbook(ps); + HSSFSheet sheet = wb.getSheetAt(0); //Get worksheet, because an excel may have multiple worksheets + HSSFRow row = sheet.getRow(0); //Get the first row (the row in excel starts from 0 by default, so this is why an excel must have a field column header), that is, a field column header, which is convenient for assignment + System.out.println(sheet.getLastRowNum() + " " + row.getLastCellNum()); //Get the row number of the last row and the last cell of a record, respectively + + FileOutputStream out = new FileOutputStream(System.getProperty(Environment.getExternalStorageDirectory() + "\\head.xls")); //Write data to head.xls + row = sheet.createRow((short) (sheet.getLastRowNum() + 1)); //Append data after the existing row number + row.createCell(0).setCellValue("hello"); //Set the data of the first (starting from 0) cell + row.createCell(1).setCellValue(1); + + //Set the data of the second (starting from 0) cell + + + + + + + out.flush(); + wb.write(out); + out.close(); + System.out.println(row.getPhysicalNumberOfCells() + " " + row.getLastCellNum()); + +*/ + + + else { + + + + + + + + /* File filePath1 = new File(Environment.getExternalStorageDirectory() + "/" + testid + ".xls"); + if (filePath1.exists()) { + HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); + + HSSFSheet hssfSheet = hssfWorkbook.createSheet("Custom Sheet"); + + HSSFRow hssfRow = hssfSheet.createRow(3); + HSSFCell hssfCell = hssfRow.createCell(0); + hssfCell.setCellValue("Test Name"); + HSSFCell hssfCell2 = hssfRow.createCell(1); + hssfCell2.setCellValue("sample Id"); + HSSFCell hssfCell3 = hssfRow.createCell(2); + hssfCell3.setCellValue("Sample Result"); + + HSSFCell hssfCell4 = hssfRow.createCell(3); + hssfCell4.setCellValue("Sample Adc Value"); + + + HSSFCell hssfCell5 = hssfRow.createCell(4); + hssfCell5.setCellValue("Internal Adc Value"); + + HSSFCell hssfCell6 = hssfRow.createCell(5); + hssfCell6.setCellValue("Negative Avg Adc Value "); + + + int d = findRow(hssfSheet, samplename); + if (d != 2) { + HSSFRow newRow = hssfSheet.createRow(hssfSheet.getLastRowNum() + 1); + + HSSFCell newRowCell0 = newRow.createCell(0); + newRowCell0.setCellValue(testid); + HSSFCell newRowCell1 = newRow.createCell(1); + newRowCell1.setCellValue(samplename); + HSSFCell newRowCell2 = newRow.createCell(2); + newRowCell2.setCellValue(resultdata); + + HSSFCell newRowCell3 = newRow.createCell(3); + newRowCell3.setCellValue(samplename); + + + HSSFCell newRowCell4 = newRow.createCell(4); + newRowCell4.setCellValue("Internal Adc Value"); + + HSSFCell newRowCell5 = newRow.createCell(5); + newRowCell5.setCellValue("Negative Avg Adc Value "); + + + + + + + + + *//* HSSFRow hssfRow1 = hssfSheet.createRow(1); + HSSFCell hssfCell1 = hssfRow1.createCell(0); + hssfCell1.setCellValue(sample); + + + hssfCell.setCellValue(negative);*//* + + try { + if (!filePath1.exists()) { + filePath1.createNewFile(); + } + + FileOutputStream fileOutputStream = new FileOutputStream(filePath1); + hssfWorkbook.write(fileOutputStream); + + if (fileOutputStream != null) { + fileOutputStream.flush(); + fileOutputStream.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + Toast.makeText(check1.this, "id exist", Toast.LENGTH_SHORT).show(); + } + + + + } else { +*/ + HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); + + HSSFSheet hssfSheet = hssfWorkbook.createSheet("Result Sheet"); + HSSFRow hssfRow1 = hssfSheet.createRow(0); + + + /* set the weight of the font */ + /* Also make the font color to RED */ + /* attach the font to the style created earlier */ + + + HSSFCell Cell1 = hssfRow1.createCell(0); + + Cell1.setCellValue("User:" + username); + HSSFRow hssfRow2 = hssfSheet.createRow(1); + HSSFCell Cellr1 = hssfRow2.createCell(0); + Cellr1.setCellValue("Date : " + date); + + HSSFRow hssfRow4 = hssfSheet.createRow(2); + + HSSFCell Cellr4 = hssfRow4.createCell(0); + + Cellr4.setCellValue("Time : " + time); + + + HSSFRow hssfRow3 = hssfSheet.createRow(3); + HSSFCell Cellr3 = hssfRow3.createCell(0); + Cellr3.setCellValue("Volume : " + volume); + + HSSFRow hssfRow5 = hssfSheet.createRow(4); + HSSFCell Cellr5 = hssfRow5.createCell(0); + Cellr5.setCellValue("Percentage : " + percentage); + + + HSSFRow hssfRow = hssfSheet.createRow(6); + + HSSFCell hssfCell = hssfRow.createCell(0); + hssfCell.setCellValue("SI No"); + HSSFCell hssfCell2 = hssfRow.createCell(1); + hssfCell2.setCellValue("sample Type"); + HSSFCell hssfCell3 = hssfRow.createCell(2); + hssfCell3.setCellValue("ADC Values"); + + HSSFCell hssfCell4 = hssfRow.createCell(3); + hssfCell4.setCellValue("AVG ADC "); + + + HSSFCell hssfCell5 = hssfRow.createCell(4); + hssfCell5.setCellValue("ΔADC"); + + HSSFCell hssfCell6 = hssfRow.createCell(5); + hssfCell6.setCellValue("Result "); + /* HSSFCell hssfCell7 = hssfRow.createCell(6); + hssfCell7.setCellValue("User Name"); + + HSSFCell hssfCell8 = hssfRow.createCell(7); + hssfCell8.setCellValue("Percentage"); +*/ + + + HSSFRow newRow = hssfSheet.createRow(hssfSheet.getLastRowNum() + 1); + + HSSFCell newRowCell0 = newRow.createCell(0); + newRowCell0.setCellValue(hssfSheet.getLastRowNum() - 6); + HSSFCell newRowCell1 = newRow.createCell(1); + newRowCell1.setCellValue("NC"); + + + HSSFCell newRowCell2 = newRow.createCell(2); + newRowCell2.setCellValue("(" + value2_1 + "," + value2_2 + "," + value2_3 + ")"); + + HSSFCell newRowCell3 = newRow.createCell(3); + newRowCell3.setCellValue(negative); + HSSFCell newRowCell4 = newRow.createCell(4); + + if (internal.equals("true")) { + newRowCell4.setCellValue(delta); + + } else { + + newRowCell4.setCellValue("-"); + + } + + HSSFCell newRowCell5 = newRow.createCell(5); + + newRowCell5.setCellValue("-"); + + + HSSFRow newRow1 = hssfSheet.createRow(hssfSheet.getLastRowNum() + 1); + + HSSFCell newRow1Cell0 = newRow1.createCell(0); + newRow1Cell0.setCellValue(hssfSheet.getLastRowNum() - 6); + HSSFCell newRow1Cell1 = newRow1.createCell(1); + newRow1Cell1.setCellValue("PC"); + + + HSSFCell newRow1Cell2 = newRow1.createCell(2); + if (internal.equals("true")) { + newRow1Cell2.setCellValue("(" + value1_1 + "," + value1_2 + "," + value1_3 + ")"); + + } else { + + newRow1Cell2.setCellValue("-"); + + } + HSSFCell newRow1Cell3 = newRow1.createCell(3); + + if (internal.equals("true")) { + newRow1Cell3.setCellValue(positive); + + } else { + + newRow1Cell3.setCellValue("-"); + + } + + HSSFCell newRow1Cell4 = newRow1.createCell(4); + + if (internal.equals("true")) { + newRow1Cell4.setCellValue(delta); + + } else { + + newRow1Cell4.setCellValue("-"); + + } + + HSSFCell newRow1Cell5 = newRow1.createCell(5); + + newRow1Cell5.setCellValue("-"); + + + HSSFRow row = hssfSheet.createRow(hssfSheet.getLastRowNum() + 1); + + + HSSFCell cell0 = row.createCell(0); + cell0.setCellValue(3); + HSSFCell cell1 = row.createCell(1); + cell1.setCellValue(samplename); + HSSFCell cell2 = row.createCell(2); + + cell2.setCellValue("(" + value3_1 + "," + value3_2 + "," + value3_3 + ")"); + + + HSSFCell cell3 = row.createCell(3); + + cell3.setCellValue(sampleraw); + + + if (internal.equals("true")) { + HSSFCell cell4 = row.createCell(4); + cell4.setCellValue(delta); + } else { + HSSFCell cell4 = row.createCell(4); + cell4.setCellValue("-"); + + } + HSSFCell cell5 = row.createCell(5); + cell5.setCellValue(resultdata); + + + + + + + + + + + + + + + + + + + + + + + /* HSSFCell hssfCell = hssfRow.createCell(0); + hssfCell.setCellValue("Test Name"); + HSSFCell hssfCell2 = hssfRow.createCell(1); + hssfCell2.setCellValue("sample Id"); + HSSFCell hssfCell3 = hssfRow.createCell(2); + hssfCell3.setCellValue("Sample Result"); + + HSSFCell hssfCell4 = hssfRow.createCell(3); + hssfCell4.setCellValue("Sample Avg Adc Value"); + + + HSSFCell hssfCell5 = hssfRow.createCell(4); + hssfCell5.setCellValue("Internal Avg Adc Value"); + + HSSFCell hssfCell6 = hssfRow.createCell(5); + hssfCell6.setCellValue("Negative Avg Adc Value "); + HSSFCell hssfCell7 = hssfRow.createCell(6); + hssfCell7.setCellValue("User Name"); + + HSSFCell hssfCell8 = hssfRow.createCell(7); + hssfCell8.setCellValue("Percentage"); + + + int d = findRow(hssfSheet, samplename); + if (d != 2) { + HSSFRow newRow = hssfSheet.createRow(hssfSheet.getLastRowNum() + 1); + + HSSFCell newRowCell0 = newRow.createCell(0); + newRowCell0.setCellValue(testid); + HSSFCell newRowCell1 = newRow.createCell(1); + newRowCell1.setCellValue(samplename); + if (internal.equals("true")) { + HSSFCell newRowCell2 = newRow.createCell(2); + newRowCell2.setCellValue(resultdata); + + } else { + HSSFCell newRowCell2 = newRow.createCell(2); + newRowCell2.setCellValue("-"); + + } + + HSSFCell newRowCell3 = newRow.createCell(3); + newRowCell3.setCellValue(sample); + + + if (internal.equals("true")) { + HSSFCell newRowCell4 = newRow.createCell(4); + newRowCell4.setCellValue(negative); + } else { + HSSFCell newRowCell4 = newRow.createCell(4); + newRowCell4.setCellValue("-"); + + } + HSSFCell newRowCell5 = newRow.createCell(5); + newRowCell5.setCellValue(positive); + + HSSFCell newRowCell6 = newRow.createCell(6); + newRowCell6.setCellValue(username); + + HSSFCell newRowCell7 = newRow.createCell(7); + newRowCell7.setCellValue(percentage); + +*/ + + + + + + + /* HSSFRow hssfRow1 = hssfSheet.createRow(1); + HSSFCell hssfCell1 = hssfRow1.createCell(0); + hssfCell1.setCellValue(sample); + + + hssfCell.setCellValue(negative);*/ + + try { + if (!filePath1.exists()) { + filePath1.createNewFile(); + } + + FileOutputStream fileOutputStream = new FileOutputStream(filePath1); + hssfWorkbook.write(fileOutputStream); + + if (fileOutputStream != null) { + fileOutputStream.flush(); + fileOutputStream.close(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + + } + } + + public void export(View view) { + //generate data + StringBuilder data = new StringBuilder(); + data.append("Time,Distance"); + for (int i = 0; i < 5; i++) { + data.append("\n" + String.valueOf(i) + "," + String.valueOf(i * i)); + } + + try { + //saving the file into device + FileOutputStream out = openFileOutput("data.csv", Context.MODE_PRIVATE); + out.write((data.toString()).getBytes()); + out.close(); + + //exporting + Context context = getApplicationContext(); + File filelocation = new File(getFilesDir(), "data.csv"); + Uri path = FileProvider.getUriForFile(context, "com.example.exportcsv.fileprovider", filelocation); + Intent fileIntent = new Intent(Intent.ACTION_SEND); + fileIntent.setType("text/csv"); + fileIntent.putExtra(Intent.EXTRA_SUBJECT, "Data"); + fileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + fileIntent.putExtra(Intent.EXTRA_STREAM, path); + startActivity(Intent.createChooser(fileIntent, "Send mail")); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + + private static int findRow(HSSFSheet sheet, String cellContent) { + for (Row row : sheet) { + for (Cell cell : row) { + /* if (cell.getCellType() == Cell.CELL_TYPE_STRING) { + if (cell.getRichStringCellValue().getString().trim().equals(cellContent)) { + return 2; + } + }*/ + } + } + return 0; + } + + private BottomNavigationView.OnNavigationItemSelectedListener navListener = + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + + switch (item.getItemId()) { + case R.id.nav_share: + + dshare(); + + + + + + + + + + + + + + + + + + + +/* + Intent intent = new Intent(check1.this, TestDetails.class); + + + startActivity(intent);*/ + + + break; + case R.id.nav_add_sample: + Intent intent4 = new Intent(check1.this, TemplateActivity2.class); + + + startActivity(intent4); + break; + case R.id.nav_home: + Intent intent3 = new Intent(check1.this, MainActivity.class); + + + startActivity(intent3); + break; + } + + return true; + } + }; + + public void readExcelFileFromAssets() { + if (ContextCompat.checkSelfPermission(check1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(check1.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } + + try { + + + InputStream myInput; + Context context = null; + + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + + + String targetPdf = directory_path + "Report_" + testid + ".xls"; + filePath1 = new File(targetPdf); + + + + + + + + + + + + + + + /* File filePath1 = new File(Environment.getExternalStorageDirectory() + "/" +"uio.xls"); + File file = new File(getApplicationContext().getExternalFilesDir(null), "file_example_XLS_50.xls"); + */ /* fis = new FileInputStream(file); + String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + + File sdcard = Environment.getExternalStorageDirectory(); + File file = new File("/sdcard/Demo.xls"); + if(file.exists()){ + +*/ + if (filePath1.exists()) { + + + } else { + // Toast.makeText(check1.this, "nooo", Toast.LENGTH_SHORT).show(); + + } + + myInput = new FileInputStream(filePath1); + + + // initialize asset manager + /* AssetManager assetManager = getAssets(); + // open excel sheet + myInput = assetManager.open("file_example_XLS_50.xls"); + */ // Create a POI File System object + POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput); + // Create a workbook using the File System + HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem); + + + ArrayList entries = new ArrayList<>(); + + + BarDataSet bardataset = new BarDataSet(entries, "Result"); + + ArrayList labels = new ArrayList(); + + + // Get the first sheet from workbook + HSSFSheet mySheet = myWorkBook.getSheetAt(0); + + // We now need something to iterate through the cells. + Iterator rowIter = mySheet.rowIterator(); + int rowCount = mySheet.getLastRowNum(); + + + int rowno = 0; + while (rowIter.hasNext()) { + HSSFRow myRow = (HSSFRow) rowIter.next(); + + // 5 + if (rowno != 0 && rowno > 5) { + + + if (rowno == rowCount - 1) { + + + Iterator cellIter = myRow.cellIterator(); + int colno = 0; + String sno = "", date = "", det = "", vald = "", adcvals = "", result = ""; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno == 0) { + sno = myCell.toString(); + } else if (colno == 1) { + date = myCell.toString(); + } else if (colno == 2) { + adcvals = myCell.toString(); + } else if (colno == 3) { + det = myCell.toString(); + } else if (colno == 4) { + vald = myCell.toString(); + } else if (colno == 5) { + result = myCell.toString(); + } + colno++; + } + + if (!result.contains("Positive")) { + bardataset.setColors(Collections.singletonList(ColorTemplate.getHoloBlue())); + + // Toast.makeText(check1.this, "positive " + result + " File ", Toast.LENGTH_LONG).show(); + + + } else { + // Toast.makeText(check1.this, "positive " + result + " File ", Toast.LENGTH_LONG).show(); + + bardataset.setColors(ColorTemplate.COLORFUL_COLORS); + + } + if (!det.equals("-")) { + + entries.add(new BarEntry(Float.parseFloat((det)), rowno - 6)); + labels.add(date + "(" + result + ")"); + + + } else { + entries.add(new BarEntry(Float.parseFloat(String.valueOf((0))), rowno - 6)); + labels.add(date + "(" + result + ")"); + + + } + + + textadc.append("ADC Val : " + adcvals + " AVG : " + det + " ΔADC : " + vald + "\n"); + + + } else { + Iterator cellIter = myRow.cellIterator(); + int colno = 0; + String sno = "", date = "", det = "", result1 = ""; + while (cellIter.hasNext()) { + HSSFCell myCell = (HSSFCell) cellIter.next(); + if (colno == 0) { + sno = myCell.toString(); + } else if (colno == 1) { + date = myCell.toString(); + } else if (colno == 3) { + det = myCell.toString(); + + } else if (colno == 5) { + result1 = myCell.toString(); + } + + colno++; + } + if (!det.equals("-")) { + + entries.add(new BarEntry(Float.parseFloat((det)), rowno - 6)); + labels.add(date + "(" + result1 + ")"); + + } else { + entries.add(new BarEntry(Float.parseFloat(String.valueOf((0))), rowno - 6)); + + labels.add(date + "(" + result1 + ")"); + + } + + } + + } + rowno++; + + } + BarData data = new BarData(labels, bardataset); + barChart.setData(data); // set the data and list of labels into chart + barChart.setDescription("Bar Graph for Result"); // set the description + // bardataset.setColorsbardataset.setColors(ColorTemplate.COLORFUL_COLORS); + barChart.animateY(1000); + + } catch (Exception e) { + } + } + + public void shared() { + String pat=Environment.getExternalStorageDirectory()+"/"+"Test Report"+"/"; + Uri uri=Uri.parse(pat); + Intent intent =new Intent(Intent. + + ACTION_PICK ) ; + intent.setDataAndType(uri,"*/*"); + startActivity(intent); + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + private void StoreProductInformation() + { + loadingBar.setTitle("Add Test"); + loadingBar.setMessage("Please wait while we are adding the Test Details ."); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + Calendar calendar = Calendar.getInstance(); + + SimpleDateFormat currentDate = new SimpleDateFormat("MMM dd, yyyy"); + saveCurrentDate = currentDate.format(calendar.getTime()); + + SimpleDateFormat currentTime = new SimpleDateFormat("HH:mm:ss a"); + saveCurrentTime = currentTime.format(calendar.getTime()); + + TestRandomKey = saveCurrentDate + saveCurrentTime+number; + + + + + + // Toast.makeText(Farmer_add_new_Products.this, "Product Image uploaded Successfully...", Toast.LENGTH_SHORT).show(); + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(check1.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + SaveProductInfoToDatabase(); + } + + + + } + private void SaveProductInfoToDatabase() + { + HashMap productMap = new HashMap<>(); + + + + productMap.put("Test_Id",testid); + productMap.put("Time", saveCurrentTime); + + productMap.put("User_Name", username); + + productMap.put("Sample_volume", volume); + productMap.put("Sample_Date",saveCurrentDate ); + + productMap.put("Percentage",percentage ); +if(internal_data==1) +{ + productMap.put("Internal","Yes" ); + +} +else +{ + productMap.put("Internal","No"); + +} + + + + TestRef.child(testid).updateChildren(productMap) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) + { + if (task.isSuccessful()) { + + /* Intent intent = new Intent(check1.this, MainActivity.class); + loadingBar.dismiss(); + *//* Intent intent = new Intent(check1.this, MainActivity.class); + loadingBar.dismiss(); + */ Toast.makeText(check1.this, "Test Details is added successfully ", Toast.LENGTH_SHORT).show(); + + // editor.putString(Name, phonenum); + + + + + + + } + else + { + loadingBar.dismiss(); + String message = task.getException().toString(); + Toast.makeText(check1.this, "Error: " + message, Toast.LENGTH_SHORT).show(); + } + } + }); + } + + + public void down() + { + if (ContextCompat.checkSelfPermission(check1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(check1.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } else { + + try { + ValidateProductData(); + + buttonCreateExcel(); + + } catch (IOException e) { + e.printStackTrace(); + } + loadingBar.setTitle("Saving Sample Data "); + loadingBar.setMessage("Please wait, while we are saving the data in " + testid + "File"); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + readExcelFileFromAssets(); + loadingBar.dismiss(); + + Toast.makeText(check1.this, "Data Saved Successfully in " + testid + " File ", Toast.LENGTH_LONG).show(); + + + } + }, 5000); + + + } + + } + + public void dshare() { + if (ContextCompat.checkSelfPermission(check1.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(check1.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 23); + } else { + String directory_path = Environment.getExternalStorageDirectory().getPath() + "/Test Report/"; + String pat = directory_path + "Report_" + testid + ".xls"; + + File file = new File(pat); + + + Intent intent = new Intent(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_TEXT, "Report"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Uri path = FileProvider.getUriForFile(check1.this, "no.Reader.android.iisc.fileprovider", file); + intent.putExtra(Intent.EXTRA_STREAM, path); + } else { + + intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); + } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(path, "application/vnd.ms-excel"); + startActivity(intent); + + + } + } + + +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsActivity.java b/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsActivity.java new file mode 100644 index 0000000..f93a41e --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsActivity.java @@ -0,0 +1,34 @@ +package no.Reader.android.iisc.Reader.settings; + +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import android.view.MenuItem; + +import no.Reader.android.iisc.R; + +public class SettingsActivity extends AppCompatActivity { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + // Display the fragment as the main content. + getSupportFragmentManager().beginTransaction().replace(R.id.content, new SettingsFragment()).commit(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsFragment.java b/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsFragment.java new file mode 100644 index 0000000..9f88b85 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/Reader/settings/SettingsFragment.java @@ -0,0 +1,18 @@ +package no.Reader.android.iisc.Reader.settings; + +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; +import no.Reader.android.iisc.R; + +public class SettingsFragment extends PreferenceFragmentCompat { + public static final String SETTINGS_DATA = "settings_template_data"; // TODO values matching those in settings_template.xml file in /res/xml + public static final int SETTINGS_VARIANT_A = 0; + public static final int SETTINGS_VARIANT_B = 1; + public static final int SETTINGS_VARIANT_DEFAULT = SETTINGS_VARIANT_A; + + @Override + public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { + addPreferencesFromResource(R.xml.settings_template); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/SplashscreenActivity.java b/app/src/main/java/no/Reader/android/iisc/SplashscreenActivity.java new file mode 100644 index 0000000..9f71525 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/SplashscreenActivity.java @@ -0,0 +1,144 @@ +package no.Reader.android.iisc; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.os.Bundle; +import android.os.Parcelable; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.Button; + +import no.Reader.android.iisc.Reader.LoginScreen; +import no.Reader.android.iisc.Reader.MainActivity; + +public class SplashscreenActivity extends Activity { + /** Splash screen duration time inew n milliseconds */ + private static final int DELAY = 1000; + Animation btnAnim ; + Button btnGetStarted; + private static int SPLASH_TIME_OUT=3000; + String number; + + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splashscreen); + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + + btnGetStarted=findViewById(R.id.started); + btnGetStarted.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + if (number == null ) { + + + Intent home = new Intent(SplashscreenActivity.this, LoginScreen.class); + startActivity(home); + finish(); + } + else { + final Intent newIntent = new Intent(SplashscreenActivity.this, MainActivity.class); + newIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + btnGetStarted.setAnimation(btnAnim); + + + // Handle NFC message, if app was opened using NFC AAR record + final Intent intent = getIntent(); + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { + final Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMsgs != null) { + for (Parcelable rawMsg : rawMsgs) { + final NdefMessage msg = (NdefMessage) rawMsg; + final NdefRecord[] records = msg.getRecords(); + + for (NdefRecord record : records) { + if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA) { + switch (record.toMimeType()) { + case FeaturesActivity.EXTRA_APP: + newIntent.putExtra(FeaturesActivity.EXTRA_APP, new String(record.getPayload())); + break; + case FeaturesActivity.EXTRA_ADDRESS: + newIntent.putExtra(FeaturesActivity.EXTRA_ADDRESS, invertEndianness(record.getPayload())); + break; + } + } + } + } + } + } + startActivity(newIntent); + finish(); + + } + } + }); + btnAnim = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.button_animation); + btnGetStarted.setAnimation(btnAnim); + + + // Jump to SensorsActivity after DELAY milliseconds +/* + new Handler().postDelayed(() -> { + final Intent newIntent = new Intent(SplashscreenActivity.this, TemplateActivity.class); + newIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + + // Handle NFC message, if app was opened using NFC AAR record + final Intent intent = getIntent(); + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { + final Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMsgs != null) { + for (Parcelable rawMsg : rawMsgs) { + final NdefMessage msg = (NdefMessage) rawMsg; + final NdefRecord[] records = msg.getRecords(); + + for (NdefRecord record : records) { + if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA) { + switch (record.toMimeType()) { + case FeaturesActivity.EXTRA_APP: + newIntent.putExtra(FeaturesActivity.EXTRA_APP, new String(record.getPayload())); + break; + case FeaturesActivity.EXTRA_ADDRESS: + newIntent.putExtra(FeaturesActivity.EXTRA_ADDRESS, invertEndianness(record.getPayload())); + break; + } + } + } + } + } + } + startActivity(newIntent); + finish(); + }, DELAY); +*/ + } + + @Override + public void onBackPressed() { + // do nothing. Protect from exiting the application when splash screen is shown + } + + /** + * Inverts endianness of the byte array. + * @param bytes input byte array + * @return byte array in opposite order + */ + private byte[] invertEndianness(final byte[] bytes) { + if (bytes == null) + return null; + final int length = bytes.length; + final byte[] result = new byte[length]; + for (int i = 0; i < length; i++) + result[i] = bytes[length - i - 1]; + return result; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/adapter/AppAdapter.java b/app/src/main/java/no/Reader/android/iisc/adapter/AppAdapter.java new file mode 100644 index 0000000..592ab02 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/adapter/AppAdapter.java @@ -0,0 +1,100 @@ +package no.Reader.android.iisc.adapter; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import no.Reader.android.iisc.R; + + +public class AppAdapter extends BaseAdapter { + private static final String CATEGORY = "no.Reader.android.iisc.LAUNCHER"; + private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp"; + + private final Context mContext; + private final PackageManager mPackageManager; + private final LayoutInflater mInflater; + private final List mApplications; + + public AppAdapter(final Context context) { + mContext = context; + mInflater = LayoutInflater.from(context); + + // get nRF installed app plugins from package manager + final PackageManager pm = mPackageManager = context.getPackageManager(); + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(CATEGORY); + + final List appList = mApplications = pm.queryIntentActivities(intent, 0); + // TODO remove the following loop after some time, when there will be no more MCP 1.1 at the market. + for (final ResolveInfo info : appList) { + if (NRF_CONNECT_PACKAGE.equals(info.activityInfo.packageName)) { + appList.remove(info); + break; + } + } + Collections.sort(appList, new ResolveInfo.DisplayNameComparator(pm)); + } + + @Override + public int getCount() { + return mApplications.size(); + } + + @Override + public Object getItem(int position) { + return mApplications.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + if (view == null) { + view = mInflater.inflate(R.layout.feature_icon, parent, false); + + final ViewHolder holder = new ViewHolder(); + holder.view = view; + holder.icon = view.findViewById(R.id.icon); + holder.label = view.findViewById(R.id.label); + view.setTag(holder); + } + + final ResolveInfo info = mApplications.get(position); + final PackageManager pm = mPackageManager; + + final ViewHolder holder = (ViewHolder) view.getTag(); + holder.icon.setImageDrawable(info.loadIcon(pm)); + holder.label.setText(info.loadLabel(pm).toString().toUpperCase(Locale.US)); + holder.view.setOnClickListener(v -> { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + mContext.startActivity(intent); + }); + + return view; + } + + private class ViewHolder { + private View view; + private ImageView icon; + private TextView label; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/app/ExpandableListActivity.java b/app/src/main/java/no/Reader/android/iisc/app/ExpandableListActivity.java new file mode 100644 index 0000000..408e2d5 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/app/ExpandableListActivity.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package no.Reader.android.iisc.app; + +import android.app.Activity; +import android.database.Cursor; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View; +import android.view.View.OnCreateContextMenuListener; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.SimpleCursorTreeAdapter; +import android.widget.SimpleExpandableListAdapter; + +import java.util.List; +import java.util.Map; + +import no.Reader.android.iisc.R; + + +/** + * An activity that displays an expandable list of items by binding to a data source implementing the ExpandableListAdapter, and exposes event handlers when the + * user selects an item. + *

+ * ExpandableListActivity hosts a {@link android.widget.ExpandableListView ExpandableListView} object that can be bound to different data sources that provide a + * two-levels of data (the top-level is group, and below each group are children). Binding, screen layout, and row layout are discussed in the following + * sections. + *

+ * Screen Layout + *

+ *

+ * ExpandableListActivity has a default layout that consists of a single, full-screen, centered expandable list. However, if you desire, you can customize the + * screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain an ExpandableListView object with + * the id "@android:id/list" (or {@link android.R.id#list} if it's in code) + *

+ * Optionally, your custom view can contain another view object of any type to display when the list view is empty. This "empty list" notifier must have an id + * "android:empty". Note that when an empty view is present, the expandable list view will be hidden when there is no data to display. + *

+ * The following code demonstrates an (ugly) custom screen layout. It has a list with a green background, and an alternate red "no data" message. + *

+ * + *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ *         android:orientation="vertical"
+ *         android:layout_width="match_parent" 
+ *         android:layout_height="match_parent"
+ *         android:paddingLeft="8dp"
+ *         android:paddingRight="8dp">
+ * 
+ *     <ExpandableListView android:id="@id/android:list"
+ *               android:layout_width="match_parent" 
+ *               android:layout_height="match_parent"
+ *               android:background="#00FF00"
+ *               android:layout_weight="1"
+ *               android:drawSelectorOnTop="false"/>
+ * 
+ *     <TextView android:id="@id/android:empty"
+ *               android:layout_width="match_parent" 
+ *               android:layout_height="match_parent"
+ *               android:background="#FF0000"
+ *               android:text="No data"/>
+ * </LinearLayout>
+ * 
+ * + *

+ * Row Layout + *

+ * The {@link ExpandableListAdapter} set in the {@link ExpandableListActivity} via {@link #setListAdapter(ExpandableListAdapter)} provides the {@link View}s for + * each row. This adapter has separate methods for providing the group {@link View}s and child {@link View}s. There are a couple provided + * {@link ExpandableListAdapter}s that simplify use of adapters: {@link SimpleCursorTreeAdapter} and {@link SimpleExpandableListAdapter}. + *

+ * With these, you can specify the layout of individual rows for groups and children in the list. These constructor takes a few parameters that specify layout + * resources for groups and children. It also has additional parameters that let you specify which data field to associate with which object in the row layout + * resource. The {@link SimpleCursorTreeAdapter} fetches data from {@link Cursor}s and the {@link SimpleExpandableListAdapter} fetches data from {@link List}s + * of {@link Map}s. + *

+ *

+ * Android provides some standard row layout resources. These are in the {@link android.R.layout} class, and have names such as simple_list_item_1, + * simple_list_item_2, and two_line_list_item. The following layout XML is the source for the resource two_line_list_item, which displays two data fields,one + * above the other, for each list row. + *

+ * + *
+ * <?xml version="1.0" encoding="utf-8"?>
+ * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:layout_width="match_parent"
+ *     android:layout_height="wrap_content"
+ *     android:orientation="vertical">
+ * 
+ *     <TextView android:id="@+id/text1"
+ *         android:textSize="16sp"
+ *         android:textStyle="bold"
+ *         android:layout_width="match_parent"
+ *         android:layout_height="wrap_content"/>
+ * 
+ *     <TextView android:id="@+id/text2"
+ *         android:textSize="16sp"
+ *         android:layout_width="match_parent"
+ *         android:layout_height="wrap_content"/>
+ * </LinearLayout>
+ * 
+ * + *

+ * You must identify the data bound to each TextView object in this layout. The syntax for this is discussed in the next section. + *

+ *

+ * Binding to Data + *

+ *

+ * You bind the ExpandableListActivity's ExpandableListView object to data using a class that implements the {@link android.widget.ExpandableListAdapter + * ExpandableListAdapter} interface. Android provides two standard list adapters: {@link android.widget.SimpleExpandableListAdapter SimpleExpandableListAdapter} + * for static data (Maps), and {@link android.widget.SimpleCursorTreeAdapter SimpleCursorTreeAdapter} for Cursor query results. + *

+ * + * @see #setListAdapter + * @see android.widget.ExpandableListView + */ +public class ExpandableListActivity extends AppCompatActivity implements + OnCreateContextMenuListener, + ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, + ExpandableListView.OnGroupExpandListener { + ExpandableListAdapter mAdapter; + ExpandableListView mList; + boolean mFinishedStart = false; + + /** + * Override this to populate the context menu when an item is long pressed. menuInfo will contain an + * {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo} whose packedPosition is a packed position that should be used with + * {@link ExpandableListView#getPackedPositionType(long)} and the other similar methods. + *

+ * {@inheritDoc} + */ + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + } + + /** + * Override this for receiving callbacks when a child has been clicked. + *

+ * {@inheritDoc} + */ + @Override + public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, + int childPosition, long id) { + return false; + } + + /** + * Override this for receiving callbacks when a group has been collapsed. + */ + @Override + public void onGroupCollapse(int groupPosition) { + } + + /** + * Override this for receiving callbacks when a group has been expanded. + */ + @Override + public void onGroupExpand(int groupPosition) { + } + + /** + * Ensures the expandable list view has been created before Activity restores all of the view states. + * + * @see Activity#onRestoreInstanceState(Bundle) + */ + @Override + protected void onRestoreInstanceState(@NonNull Bundle state) { + ensureList(); + super.onRestoreInstanceState(state); + } + + /** + * Updates the screen state (current list and other views) when the content changes. + * + * @see androidx.appcompat.app.AppCompatActivity#onContentChanged() + */ + @Override + public void onContentChanged() { + super.onContentChanged(); + View emptyView = findViewById(R.id.empty); + mList = findViewById(R.id.list); + if (mList == null) { + throw new RuntimeException( + "Your content must have a ExpandableListView whose id attribute is " + + "'R.id.list'"); + } + if (emptyView != null) { + mList.setEmptyView(emptyView); + } + mList.setOnChildClickListener(this); + mList.setOnGroupExpandListener(this); + mList.setOnGroupCollapseListener(this); + + if (mFinishedStart) { + setListAdapter(mAdapter); + } + mFinishedStart = true; + } + + /** + * Provide the adapter for the expandable list. + */ + public void setListAdapter(ExpandableListAdapter adapter) { + synchronized (this) { + ensureList(); + mAdapter = adapter; + mList.setAdapter(adapter); + } + } + + /** + * Get the activity's expandable list view widget. This can be used to get the selection, set the selection, and many other useful functions. + * + * @see ExpandableListView + */ + public ExpandableListView getExpandableListView() { + ensureList(); + return mList; + } + + /** + * Get the ExpandableListAdapter associated with this activity's ExpandableListView. + */ + public ExpandableListAdapter getExpandableListAdapter() { + return mAdapter; + } + + private void ensureList() { + if (mList != null) { + return; + } + setContentView(R.layout.expandable_list_content); + } + + /** + * Gets the ID of the currently selected group or child. + * + * @return The ID of the currently selected group or child. + */ + public long getSelectedId() { + return mList.getSelectedId(); + } + + /** + * Gets the position (in packed position representation) of the currently selected group or child. Use {@link ExpandableListView#getPackedPositionType}, + * {@link ExpandableListView#getPackedPositionGroup}, and {@link ExpandableListView#getPackedPositionChild} to unpack the returned packed position. + * + * @return A packed position representation containing the currently selected group or child's position and type. + */ + public long getSelectedPosition() { + return mList.getSelectedPosition(); + } + + /** + * Sets the selection to the specified child. If the child is in a collapsed group, the group will only be expanded and child subsequently selected if + * shouldExpandGroup is set to true, otherwise the method will return false. + * + * @param groupPosition + * The position of the group that contains the child. + * @param childPosition + * The position of the child within the group. + * @param shouldExpandGroup + * Whether the child's group should be expanded if it is collapsed. + * @return Whether the selection was successfully set on the child. + */ + public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) { + return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup); + } + + /** + * Sets the selection to the specified group. + * + * @param groupPosition + * The position of the group that should be selected. + */ + public void setSelectedGroup(int groupPosition) { + mList.setSelectedGroup(groupPosition); + } + +} diff --git a/app/src/main/java/no/Reader/android/iisc/battery/BatteryManager.java b/app/src/main/java/no/Reader/android/iisc/battery/BatteryManager.java new file mode 100644 index 0000000..29113c3 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/battery/BatteryManager.java @@ -0,0 +1,124 @@ +package no.Reader.android.iisc.battery; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import androidx.annotation.NonNull; +import android.util.Log; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.callback.DataReceivedCallback; +import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelDataCallback; +import no.nordicsemi.android.ble.data.Data; +import no.nordicsemi.android.log.LogContract; +import no.Reader.android.iisc.profile.LoggableBleManager; + +/** + * The Ble Manager with Battery Service support. + * + * @param The profile callbacks type. + * @see BleManager + */ +@SuppressWarnings("WeakerAccess") +public abstract class BatteryManager extends LoggableBleManager { + /** Battery Service UUID. */ + private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + /** Battery Level characteristic UUID. */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + + private BluetoothGattCharacteristic mBatteryLevelCharacteristic; + /** Last received Battery Level value. */ + private Integer mBatteryLevel; + + /** + * The manager constructor. + * + * @param context context. + */ + public BatteryManager(final Context context) { + super(context); + } + + private DataReceivedCallback mBatteryLevelDataCallback = new BatteryLevelDataCallback() { + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + log(LogContract.Log.Level.APPLICATION,"Battery Level received: " + batteryLevel + "%"); + mBatteryLevel = batteryLevel; + mCallbacks.onBatteryLevelChanged(device, batteryLevel); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { + log(Log.WARN, "Invalid Battery Level data received: " + data); + } + }; + + public void readBatteryLevelCharacteristic() { + if (isConnected()) { + readCharacteristic(mBatteryLevelCharacteristic) + .with(mBatteryLevelDataCallback) + .fail((device, status) -> log(Log.WARN,"Battery Level characteristic not found")) + .enqueue(); + } + } + + public void enableBatteryLevelCharacteristicNotifications() { + if (isConnected()) { + // If the Battery Level characteristic is null, the request will be ignored + setNotificationCallback(mBatteryLevelCharacteristic) + .with(mBatteryLevelDataCallback); + enableNotifications(mBatteryLevelCharacteristic) + .done(device -> log(Log.INFO, "Battery Level notifications enabled")) + .fail((device, status) -> log(Log.WARN, "Battery Level characteristic not found")) + .enqueue(); + } + } + + /** + * Disables Battery Level notifications on the Server. + */ + public void disableBatteryLevelCharacteristicNotifications() { + if (isConnected()) { + disableNotifications(mBatteryLevelCharacteristic) + .done(device -> log(Log.INFO, "Battery Level notifications disabled")) + .enqueue(); + } + } + + /** + * Returns the last received Battery Level value. + * The value is set to null when the device disconnects. + * @return Battery Level value, in percent. + */ + public Integer getBatteryLevel() { + return mBatteryLevel; + } + + protected abstract class BatteryManagerGattCallback extends BleManagerGattCallback { + + @Override + protected void initialize() { + readBatteryLevelCharacteristic(); + enableBatteryLevelCharacteristicNotifications(); + } + + @Override + protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + final BluetoothGattService service = gatt.getService(BATTERY_SERVICE_UUID); + if (service != null) { + mBatteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID); + } + return mBatteryLevelCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + mBatteryLevelCharacteristic = null; + mBatteryLevel = null; + } + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/battery/BatteryManagerCallbacks.java b/app/src/main/java/no/Reader/android/iisc/battery/BatteryManagerCallbacks.java new file mode 100644 index 0000000..b020fee --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/battery/BatteryManagerCallbacks.java @@ -0,0 +1,7 @@ +package no.Reader.android.iisc.battery; + +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.common.profile.battery.BatteryLevelCallback; + +public interface BatteryManagerCallbacks extends BleManagerCallbacks, BatteryLevelCallback { +} diff --git a/app/src/main/java/no/Reader/android/iisc/parser/SPCAParser.java b/app/src/main/java/no/Reader/android/iisc/parser/SPCAParser.java new file mode 100644 index 0000000..06f5ae0 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/parser/SPCAParser.java @@ -0,0 +1,48 @@ +package no.Reader.android.iisc.parser; + +import no.nordicsemi.android.ble.data.Data; + +// TODO this method may be used for developing purposes to log the data from your device using the nRF Logger application. + +@SuppressWarnings("ConstantConditions") +public class SPCAParser { + // TODO add some flags, if needed + private static final byte HEART_RATE_VALUE_FORMAT = 0x01; // 1 bit + + /** + * This method converts the value of the characteristic to the String. The String is then logged in the nRF logger log session + * @param data the characteristic data to be parsed + * @return human readable value of the characteristic + */ + @SuppressWarnings("UnusedAssignment") + public static String parse(final Data data) { + int offset = 0; + int flags = 0; + int value=0; + if(data.getIntValue(Data.FORMAT_UINT8, offset++)!=null) { + flags = data.getIntValue(Data.FORMAT_UINT8, offset++); + + } + + /* + * In the template we are using the HRM values as an example. + * false Heart Rate Value Format is set to UINT8. Units: beats per minute (bpm) + * true Heart Rate Value Format is set to UINT16. Units: beats per minute (bpm) + */ + final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0; + + // heart rate value is 8 or 16 bit long +if((data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++)!=null)) + { + value = data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++); // bits per minute + + } + + if (value16bit) + offset++; + + // TODO parse more data + + return "Template Measurement: " + value + " bpm"; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/BleProfileActivity.java b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileActivity.java new file mode 100644 index 0000000..57f0134 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileActivity.java @@ -0,0 +1,398 @@ +package no.Reader.android.iisc.profile; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LocalLogSession; +import no.nordicsemi.android.log.Logger; +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.scanner.ScannerFragment; +import no.Reader.android.iisc.DebugLogger; + +@SuppressWarnings("unused") +public abstract class BleProfileActivity extends AppCompatActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { + private static final String TAG = "BaseProfileActivity"; + + private static final String SIS_CONNECTION_STATUS = "connection_status"; + private static final String SIS_DEVICE_NAME = "device_name"; + protected static final int REQUEST_ENABLE_BT = 2; + + private LoggableBleManager mBleManager; + + private TextView mDeviceNameView; + private Button mConnectButton; + private ILogSession mLogSession; + + private boolean mDeviceConnected = false; + private String mDeviceName; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + /* + * We use the managers using a singleton pattern. It's not recommended for the Android, because the singleton instance remains after Activity has been + * destroyed but it's simple and is used only for this demo purpose. In final application Managers should be created as a non-static objects in + * Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding, + * broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach. + */ + mBleManager = initializeManager(); + + // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service + onInitialize(savedInstanceState); + // The onCreateView class should... create the view + onCreateView(savedInstanceState); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + + // Common nRF Toolbox view references are obtained here + setUpView(); + // View is ready to be used + onViewCreated(savedInstanceState); + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, i.e. using {@link #setContentView(int)}. + * Use to obtain references to views. Connect/Disconnect button and the device name view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected void onViewCreated(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called after the view and the toolbar has been created. + */ + protected final void setUpView() { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = findViewById(R.id.action_connect); + mDeviceNameView = findViewById(R.id.device_name); + } + + @Override + public void onBackPressed() { + mBleManager.disconnect().enqueue(); + super.onBackPressed(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected); + outState.putString(SIS_DEVICE_NAME, mDeviceName); + } + + @Override + protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS); + mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME); + + if (mDeviceConnected) { + mConnectButton.setText(R.string.action_disconnect); + } else { + mConnectButton.setText(R.string.action_connect); + } + } + + + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (!mDeviceConnected) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID()); + } else { + mBleManager.disconnect().enqueue(); + } + } else { + showBLEDialog(); + } + } + + /** + * Returns the title resource id that will be used to create logger session. If 0 is returned (default) logger will not be used. + * + * @return the title resource id + */ + protected int getLoggerProfileTitle() { + return 0; + } + + /** + * This method may return the local log content provider authority if local log sessions are supported. + * + * @return local log session content provider URI + */ + protected Uri getLocalAuthorityLogger() { + return null; + } + + /** + * This method returns whether autoConnect option should be used. + * + * @return true to use autoConnect feature, false (default) otherwise. + */ + protected boolean shouldAutoConnect() { + return false; + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final int titleId = getLoggerProfileTitle(); + if (titleId > 0) { + mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); + // If nRF Logger is not installed we may want to use local logger + if (mLogSession == null && getLocalAuthorityLogger() != null) { + mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); + } + } + mDeviceName = name; + mBleManager.setLogger(mLogSession); + mBleManager.connect(device) + .useAutoConnect(shouldAutoConnect()) + .retry(3, 100) + .enqueue(); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnecting(@NonNull final BluetoothDevice device) { + runOnUiThread(() -> { + mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available)); + mConnectButton.setText(R.string.action_connecting); + }); + } + + @Override + public void onDeviceConnected(@NonNull final BluetoothDevice device) { + mDeviceConnected = true; + runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect)); + } + + @Override + public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) { + runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting)); + } + + @Override + public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { + mDeviceConnected = false; + mBleManager.close(); + runOnUiThread(() -> { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + }); + } + + @Override + public void onLinkLossOccurred(@NonNull final BluetoothDevice device) { + mDeviceConnected = false; + } + + @Override + public void onServicesDiscovered(@NonNull final BluetoothDevice device, boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceReady(@NonNull final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingRequired(@NonNull final BluetoothDevice device) { + showToast(R.string.bonding); + } + + @Override + public void onBonded(@NonNull final BluetoothDevice device) { + showToast(R.string.bonded); + } + + @Override + public void onBondingFailed(@NonNull final BluetoothDevice device) { + showToast(R.string.bonding_failed); + } + + @Override + public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + } + + @Override + public void onDeviceNotSupported(@NonNull final BluetoothDevice device) { + showToast(R.string.not_supported); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(() -> Toast.makeText(BleProfileActivity.this, message, Toast.LENGTH_SHORT).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(() -> Toast.makeText(BleProfileActivity.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mDeviceConnected; + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Initializes the Bluetooth Low Energy manager. A manager is used to communicate with profile's services. + * + * @return the manager that was created + */ + protected abstract LoggableBleManager initializeManager(); + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter) { + runOnUiThread(() -> { + final ScannerFragment dialog = ScannerFragment.getInstance(filter); + dialog.show(getSupportFragmentManager(), "scan_fragment"); + }); + } + + /** + * Returns the log session. Log session is created when the device was selected using the {@link ScannerFragment} and released when user press DISCONNECT. + * + * @return the logger session or null + */ + protected ILogSession getLogSession() { + return mLogSession; + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/BleProfileExpandableListActivity.java b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileExpandableListActivity.java new file mode 100644 index 0000000..05672df --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileExpandableListActivity.java @@ -0,0 +1,401 @@ +package no.Reader.android.iisc.profile; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; + +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LocalLogSession; +import no.nordicsemi.android.log.Logger; +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.app.ExpandableListActivity; +import no.Reader.android.iisc.scanner.ScannerFragment; +import no.Reader.android.iisc.DebugLogger; + +@SuppressWarnings("unused") +public abstract class BleProfileExpandableListActivity extends ExpandableListActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { + private static final String TAG = "BaseProfileActivity"; + + private static final String SIS_CONNECTION_STATUS = "connection_status"; + private static final String SIS_DEVICE_NAME = "device_name"; + protected static final int REQUEST_ENABLE_BT = 2; + + private LoggableBleManager mBleManager; + + private TextView mDeviceNameView; + private Button mConnectButton; + private ILogSession mLogSession; + + private boolean mDeviceConnected = false; + private String mDeviceName; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + /* + * We use the managers using a singleton pattern. It's not recommended for the Android, because the singleton instance remains after Activity has been + * destroyed but it's simple and is used only for this demo purpose. In final application Managers should be created as a non-static objects in + * Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding, + * broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach. + */ + mBleManager = initializeManager(); + + // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service + onInitialize(savedInstanceState); + // The onCreateView class should... create the view + onCreateView(savedInstanceState); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + + // Common nRF Toolbox view references are obtained here + setUpView(); + // View is ready to be used + onViewCreated(savedInstanceState); + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + @SuppressWarnings("unused") + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, i.e. using {@link #setContentView(int)}. + * Use to obtain references to views. Connect/Disconnect button and the device name view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + @SuppressWarnings("unused") + protected void onViewCreated(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called after the view and the toolbar has been created. + */ + protected final void setUpView() { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = findViewById(R.id.action_connect); + mDeviceNameView = findViewById(R.id.device_name); + } + + @Override + public void onBackPressed() { + mBleManager.disconnect().enqueue(); + super.onBackPressed(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected); + outState.putString(SIS_DEVICE_NAME, mDeviceName); + } + + @Override + protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS); + mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME); + + if (mDeviceConnected) { + mConnectButton.setText(R.string.action_disconnect); + } else { + mConnectButton.setText(R.string.action_connect); + } + } + + + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + @SuppressWarnings("unused") + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (!mDeviceConnected) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID()); + } else { + mBleManager.disconnect().enqueue(); + } + } else { + showBLEDialog(); + } + } + + /** + * Returns the title resource id that will be used to create logger session. If 0 is returned (default) logger will not be used. + * + * @return the title resource id + */ + protected int getLoggerProfileTitle() { + return 0; + } + + /** + * This method may return the local log content provider authority if local log sessions are supported. + * + * @return local log session content provider URI + */ + protected Uri getLocalAuthorityLogger() { + return null; + } + + /** + * This method returns whether autoConnect option should be used. + * + * @return true to use autoConnect feature, false (default) otherwise. + */ + protected boolean shouldAutoConnect() { + return false; + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final int titleId = getLoggerProfileTitle(); + if (titleId > 0) { + mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); + // If nRF Logger is not installed we may want to use local logger + if (mLogSession == null && getLocalAuthorityLogger() != null) { + mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); + } + } + mDeviceName = name; + mBleManager.setLogger(mLogSession); + mBleManager.connect(device) + .useAutoConnect(shouldAutoConnect()) + .retry(3, 100) + .enqueue(); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnecting(@NonNull final BluetoothDevice device) { + runOnUiThread(() -> { + mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available)); + mConnectButton.setText(R.string.action_connecting); + }); + } + + @Override + public void onDeviceConnected(@NonNull final BluetoothDevice device) { + mDeviceConnected = true; + runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect)); + } + + @Override + public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) { + runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting)); + } + + @Override + public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { + mDeviceConnected = false; + mBleManager.close(); + runOnUiThread(() -> { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + }); + } + + @Override + public void onLinkLossOccurred(@NonNull final BluetoothDevice device) { + mDeviceConnected = false; + } + + @Override + public void onServicesDiscovered(@NonNull final BluetoothDevice device, boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onDeviceReady(@NonNull final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingRequired(@NonNull final BluetoothDevice device) { + showToast(R.string.bonding); + } + + @Override + public void onBonded(@NonNull final BluetoothDevice device) { + showToast(R.string.bonded); + } + + @Override + public void onBondingFailed(@NonNull final BluetoothDevice device) { + showToast(R.string.bonding_failed); + } + + @Override + public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + } + + @Override + public void onDeviceNotSupported(@NonNull final BluetoothDevice device) { + showToast(R.string.not_supported); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(() -> Toast.makeText(BleProfileExpandableListActivity.this, message, Toast.LENGTH_SHORT).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(() -> Toast.makeText(BleProfileExpandableListActivity.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mDeviceConnected; + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Initializes the Bluetooth Low Energy manager. A manager is used to communicate with profile's services. + * + * @return the manager that was created + */ + protected abstract LoggableBleManager initializeManager(); + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter) { + runOnUiThread(() -> { + final ScannerFragment dialog = ScannerFragment.getInstance(filter); + dialog.show(getSupportFragmentManager(), "scan_fragment"); + }); + } + + /** + * Returns the log session. Log session is created when the device was selected using the {@link ScannerFragment} and released when user press DISCONNECT. + * + * @return the logger session or null + */ + protected ILogSession getLogSession() { + return mLogSession; + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/BleProfileService.java b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileService.java new file mode 100644 index 0000000..ff22e4b --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileService.java @@ -0,0 +1,582 @@ +package no.Reader.android.iisc.profile; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import android.util.Log; +import android.widget.Toast; + +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.utils.ILogger; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; + +@SuppressWarnings("unused") +public abstract class BleProfileService extends Service implements BleManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "BleProfileService"; + + public static final String BROADCAST_CONNECTION_STATE = "no.Reader.android.iisc.BROADCAST_CONNECTION_STATE"; + public static final String BROADCAST_SERVICES_DISCOVERED = "no.Reader.android.iisc.BROADCAST_SERVICES_DISCOVERED"; + public static final String BROADCAST_DEVICE_READY = "no.Reader.android.iisc.DEVICE_READY"; + public static final String BROADCAST_BOND_STATE = "no.Reader.android.iisc.BROADCAST_BOND_STATE"; + @Deprecated + public static final String BROADCAST_BATTERY_LEVEL = "no.Reader.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String BROADCAST_ERROR = "no.Reader.android.iisc.BROADCAST_ERROR"; + + /** The parameter passed when creating the service. Must contain the address of the sensor that we want to connect to */ + public static final String EXTRA_DEVICE_ADDRESS = "no.Reader.android.iisc.EXTRA_DEVICE_ADDRESS"; + /** The key for the device name that is returned in {@link #BROADCAST_CONNECTION_STATE} with state {@link #STATE_CONNECTED}. */ + public static final String EXTRA_DEVICE_NAME = "no.Reader.android.iisc.EXTRA_DEVICE_NAME"; + public static final String EXTRA_DEVICE = "no.Reader.android.iisc.EXTRA_DEVICE"; + public static final String EXTRA_LOG_URI = "no.Reader.android.iisc.EXTRA_LOG_URI"; + public static final String EXTRA_CONNECTION_STATE = "no.Reader.android.iisc.EXTRA_CONNECTION_STATE"; + public static final String EXTRA_BOND_STATE = "no.Reader.android.iisc.EXTRA_BOND_STATE"; + public static final String EXTRA_SERVICE_PRIMARY = "no.Reader.android.iisc.EXTRA_SERVICE_PRIMARY"; + public static final String EXTRA_SERVICE_SECONDARY = "no.Reader.android.iisc.EXTRA_SERVICE_SECONDARY"; + @Deprecated + public static final String EXTRA_BATTERY_LEVEL = "no.Reader.android.iisc.EXTRA_BATTERY_LEVEL"; + public static final String EXTRA_ERROR_MESSAGE = "no.Reader.android.iisc.EXTRA_ERROR_MESSAGE"; + public static final String EXTRA_ERROR_CODE = "no.Reader.android.iisc.EXTRA_ERROR_CODE"; + + public static final int STATE_LINK_LOSS = -1; + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTED = 1; + public static final int STATE_CONNECTING = 2; + public static final int STATE_DISCONNECTING = 3; + + private LoggableBleManager mBleManager; + private Handler mHandler; + + protected boolean mBound; + private boolean mActivityIsChangingConfiguration; + private BluetoothDevice mBluetoothDevice; + private String mDeviceName; + private ILogSession mLogSession; + + private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); + final ILogger logger = getBinder(); + + final String stateString = "[Broadcast] Action received: " + BluetoothAdapter.ACTION_STATE_CHANGED + ", state changed to " + state2String(state); + logger.log(Log.DEBUG, stateString); + + switch (state) { + case BluetoothAdapter.STATE_ON: + onBluetoothEnabled(); + break; + case BluetoothAdapter.STATE_TURNING_OFF: + case BluetoothAdapter.STATE_OFF: + onBluetoothDisabled(); + break; + } + } + + private String state2String(final int state) { + switch (state) { + case BluetoothAdapter.STATE_TURNING_ON: + return "TURNING ON"; + case BluetoothAdapter.STATE_ON: + return "ON"; + case BluetoothAdapter.STATE_TURNING_OFF: + return "TURNING OFF"; + case BluetoothAdapter.STATE_OFF: + return "OFF"; + default: + return "UNKNOWN (" + state + ")"; + } + } + }; + + public class LocalBinder extends Binder implements ILogger { + /** + * Disconnects from the sensor. + */ + public final void disconnect() { + final int state = mBleManager.getConnectionState(); + if (state == BluetoothGatt.STATE_DISCONNECTED || state == BluetoothGatt.STATE_DISCONNECTING) { + mBleManager.close(); + onDeviceDisconnected(mBluetoothDevice); + return; + } + + mBleManager.disconnect().enqueue(); + } + + /** + * Sets whether the bound activity if changing configuration or not. + * If false, we will turn off battery level notifications in onUnbind(..) method below. + * @param changing true if the bound activity is finishing + */ + public void setActivityIsChangingConfiguration(final boolean changing) { + mActivityIsChangingConfiguration = changing; + } + + /** + * Returns the device address + * + * @return device address + */ + public String getDeviceAddress() { + return mBluetoothDevice.getAddress(); + } + + /** + * Returns the device name + * + * @return the device name + */ + public String getDeviceName() { + return mDeviceName; + } + + /** + * Returns the Bluetooth device + * + * @return the Bluetooth device + */ + public BluetoothDevice getBluetoothDevice() { + return mBluetoothDevice; + } + + /** + * Returns true if the device is connected to the sensor. + * + * @return true if device is connected to the sensor, false otherwise + */ + public boolean isConnected() { + return mBleManager.isConnected(); + } + + + /** + * Returns the connection state of given device. + * @return the connection state, as in {@link BleManager#getConnectionState()}. + */ + public int getConnectionState() { + return mBleManager.getConnectionState(); + } + + /** + * Returns the log session that can be used to append log entries. + * The log session is created when the service is being created. + * The method returns null if the nRF Logger app was not installed. + * + * @return the log session + */ + public ILogSession getLogSession() { + return mLogSession; + } + + @Override + public void log(final int level, @NonNull final String message) { + Logger.log(mLogSession, level, message); + } + + @Override + public void log(final int level, final @StringRes int messageRes, final Object... params) { + Logger.log(mLogSession, level, messageRes, params); + } + } + + /** + * Returns a handler that is created in onCreate(). + * The handler may be used to postpone execution of some operations or to run them in UI thread. + */ + protected Handler getHandler() { + return mHandler; + } + + /** + * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the bound activity. + * + * @return the service binder + */ + protected LocalBinder getBinder() { + // default implementation returns the basic binder. You can overwrite the LocalBinder with your own, wider implementation + return new LocalBinder(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBound = true; + return getBinder(); + } + + @Override + public final void onRebind(final Intent intent) { + mBound = true; + + if (!mActivityIsChangingConfiguration) + onRebind(); + } + + /** + * Called when the activity has rebound to the service after being recreated. + * This method is not called when the activity was killed to be recreated when the phone orientation changed + * if prior to being killed called {@link BleProfileService.LocalBinder#setActivityIsChangingConfiguration(boolean)} with parameter true. + */ + protected void onRebind() { + // empty default implementation + } + + @Override + public final boolean onUnbind(final Intent intent) { + mBound = false; + + if (!mActivityIsChangingConfiguration) + onUnbind(); + + // We want the onRebind method be called if anything else binds to it again + return true; + } + + /** + * Called when the activity has unbound from the service before being finished. + * This method is not called when the activity is killed to be recreated when the phone orientation changed. + */ + protected void onUnbind() { + // empty default implementation + } + + @SuppressWarnings("unchecked") + @Override + public void onCreate() { + super.onCreate(); + + mHandler = new Handler(); + + // Initialize the manager + mBleManager = initializeManager(); + mBleManager.setGattCallbacks(this); + + // Register broadcast receivers + registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + + // Service has now been created + onServiceCreated(); + + // Call onBluetoothEnabled if Bluetooth enabled + final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter.isEnabled()) { + onBluetoothEnabled(); + } + } + + /** + * Called when the service has been created, before the {@link #onBluetoothEnabled()} is called. + */ + protected void onServiceCreated() { + // empty default implementation + } + + /** + * Initializes the Ble Manager responsible for connecting to a single device. + * @return a new BleManager object + */ + @SuppressWarnings("rawtypes") + protected abstract LoggableBleManager initializeManager(); + + /** + * This method returns whether autoConnect option should be used. + * + * @return true to use autoConnect feature, false (default) otherwise. + */ + protected boolean shouldAutoConnect() { + return false; + } + + @Override + public int onStartCommand(final Intent intent, final int flags, final int startId) { + if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS)) + throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key"); + + final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI); + mLogSession = Logger.openSession(getApplicationContext(), logUri); + mDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME); + + Logger.i(mLogSession, "Service started"); + + final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS); + mBluetoothDevice = adapter.getRemoteDevice(deviceAddress); + + mBleManager.setLogger(mLogSession); + onServiceStarted(); + mBleManager.connect(mBluetoothDevice) + .useAutoConnect(shouldAutoConnect()) + .retry(3, 100) + .enqueue(); + return START_REDELIVER_INTENT; + } + + /** + * Called when the service has been started. The device name and address are set. + * The BLE Manager will try to connect to the device after this method finishes. + */ + protected void onServiceStarted() { + // empty default implementation + } + + @Override + public void onTaskRemoved(final Intent rootIntent) { + super.onTaskRemoved(rootIntent); + // This method is called when user removed the app from Recents. + // By default, the service will be killed and recreated immediately after that. + // However, all managed devices will be lost and devices will be disconnected. + stopSelf(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + // Unregister broadcast receivers + unregisterReceiver(mBluetoothStateBroadcastReceiver); + + // shutdown the manager + mBleManager.close(); + Logger.i(mLogSession, "Service destroyed"); + mBleManager = null; + mBluetoothDevice = null; + mDeviceName = null; + mLogSession = null; + mHandler = null; + } + + /** + * Method called when Bluetooth Adapter has been disabled. + */ + protected void onBluetoothDisabled() { + // empty default implementation + } + + /** + * This method is called when Bluetooth Adapter has been enabled and + * after the service was created if Bluetooth Adapter was enabled at that moment. + * This method could initialize all Bluetooth related features, for example open the GATT server. + */ + protected void onBluetoothEnabled() { + // empty default implementation + } + + @Override + public void onDeviceConnecting(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceConnected(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) { + // Notify user about changing the state to DISCONNECTING + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + /** + * This method should return false if the service needs to do some asynchronous work after if has disconnected from the device. + * In that case the {@link #stopService()} method must be called when done. + * @return true (default) to automatically stop the service when device is disconnected. False otherwise. + */ + protected boolean stopWhenDisconnected() { + return true; + } + + @Override + public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { + // Note 1: Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above + + // Note 2: if BleManager#shouldAutoConnect() for this device returned true, this callback will be + // invoked ONLY when user requested disconnection (using Disconnect button). If the device + // disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead. + + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + if (stopWhenDisconnected()) + stopService(); + } + + protected void stopService() { + // user requested disconnection. We must stop the service + Logger.v(mLogSession, "Stopping service..."); + stopSelf(); + } + + @Override + public void onLinkLossOccurred(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) { + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceReady(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_DEVICE_READY); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceNotSupported(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // no need for disconnecting, it will be disconnected by the manager automatically + } + + @Override + public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) { + final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_BATTERY_LEVEL, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBondingRequired(@NonNull final BluetoothDevice device) { + showToast(no.Reader.android.iisc.R.string.bonding); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBonded(@NonNull final BluetoothDevice device) { + showToast(no.Reader.android.iisc.R.string.bonding); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBondingFailed(@NonNull final BluetoothDevice device) { + showToast(no.Reader.android.iisc.R.string.bonding_failed); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) { + final Intent broadcast = new Intent(BROADCAST_ERROR); + broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); + broadcast.putExtra(EXTRA_ERROR_MESSAGE, message); + broadcast.putExtra(EXTRA_ERROR_CODE, errorCode); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId + * an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + mHandler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message + * a message to be shown + */ + protected void showToast(final String message) { + mHandler.post(() -> Toast.makeText(BleProfileService.this, message, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns the log session that can be used to append log entries. The method returns null if the nRF Logger app was not installed. It is safe to use logger when + * {@link #onServiceStarted()} has been called. + * + * @return the log session + */ + protected ILogSession getLogSession() { + return mLogSession; + } + + /** + * Returns the device address + * + * @return device address + */ + protected String getDeviceAddress() { + return mBluetoothDevice.getAddress(); + } + + /** + * Returns the Bluetooth device object + * + * @return bluetooth device + */ + protected BluetoothDevice getBluetoothDevice() { + return mBluetoothDevice; + } + + /** + * Returns the device name + * + * @return the device name + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Returns true if the device is connected to the sensor. + * + * @return true if device is connected to the sensor, false otherwise + */ + protected boolean isConnected() { + return mBleManager != null && mBleManager.isConnected(); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/BleProfileServiceReadyActivity.java b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileServiceReadyActivity.java new file mode 100644 index 0000000..72cab33 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/BleProfileServiceReadyActivity.java @@ -0,0 +1,626 @@ +package no.Reader.android.iisc.profile; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import androidx.annotation.NonNull; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.appcompat.app.AppCompatActivity; + +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LocalLogSession; +import no.nordicsemi.android.log.Logger; +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.scanner.ScannerFragment; +import no.Reader.android.iisc.DebugLogger; + +/** + *

+ * The {@link BleProfileServiceReadyActivity} activity is designed to be the base class for profile activities that uses services in order to connect to the + * device. When user press CONNECT button a service is created and the activity binds to it. The service tries to connect to the service and notifies the + * activity using Local Broadcasts ({@link LocalBroadcastManager}). See {@link BleProfileService} for messages. If the device is not in range it will listen for + * it and connect when it become visible. The service exists until user will press DISCONNECT button. + *

+ *

+ * When user closes the activity (f.e. by pressing Back button) while being connected, the Service remains working. It's still connected to the device or still + * listens for it. When entering back to the activity, activity will to bind to the service and refresh UI. + *

+ */ +@SuppressWarnings("unused") +public abstract class BleProfileServiceReadyActivity extends AppCompatActivity implements + ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks { + private static final String TAG = "BleProfileServiceReadyActivity"; + + private static final String SIS_DEVICE_NAME = "device_name"; + private static final String SIS_DEVICE = "device"; + private static final String LOG_URI = "log_uri"; + protected static final int REQUEST_ENABLE_BT = 2; + + private E mService; + + private TextView mDeviceNameView; + private Button mConnectButton; + + private ILogSession mLogSession; + private BluetoothDevice mBluetoothDevice; + private String mDeviceName; + + private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + // Check if the broadcast applies the connected device + if (!isBroadcastForThisDevice(intent)) + return; + + final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE); + final String action = intent.getAction(); + switch (action) { + case BleProfileService.BROADCAST_CONNECTION_STATE: { + final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED); + + switch (state) { + case BleProfileService.STATE_CONNECTED: { + mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME); + onDeviceConnected(bluetoothDevice); + break; + } + case BleProfileService.STATE_DISCONNECTED: { + onDeviceDisconnected(bluetoothDevice); + mDeviceName = null; + break; + } + case BleProfileService.STATE_LINK_LOSS: { + onLinkLossOccurred(bluetoothDevice); + break; + } + case BleProfileService.STATE_CONNECTING: { + onDeviceConnecting(bluetoothDevice); + break; + } + case BleProfileService.STATE_DISCONNECTING: { + onDeviceDisconnecting(bluetoothDevice); + break; + } + default: + // there should be no other actions + break; + } + break; + } + case BleProfileService.BROADCAST_SERVICES_DISCOVERED: { + final boolean primaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_PRIMARY, false); + final boolean secondaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_SECONDARY, false); + + if (primaryService) { + onServicesDiscovered(bluetoothDevice, secondaryService); + } else { + onDeviceNotSupported(bluetoothDevice); + } + break; + } + case BleProfileService.BROADCAST_DEVICE_READY: { + onDeviceReady(bluetoothDevice); + break; + } + case BleProfileService.BROADCAST_BOND_STATE: { + final int state = intent.getIntExtra(BleProfileService.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); + switch (state) { + case BluetoothDevice.BOND_BONDING: + onBondingRequired(bluetoothDevice); + break; + case BluetoothDevice.BOND_BONDED: + onBonded(bluetoothDevice); + break; + } + break; + } + case BleProfileService.BROADCAST_ERROR: { + final String message = intent.getStringExtra(BleProfileService.EXTRA_ERROR_MESSAGE); + final int errorCode = intent.getIntExtra(BleProfileService.EXTRA_ERROR_CODE, 0); + onError(bluetoothDevice, message, errorCode); + break; + } + } + } + }; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @SuppressWarnings("unchecked") + @Override + public void onServiceConnected(final ComponentName name, final IBinder service) { + final E bleService = mService = (E) service; + mBluetoothDevice = bleService.getBluetoothDevice(); + mLogSession = mService.getLogSession(); + Logger.d(mLogSession, "Activity bound to the service"); + onServiceBound(bleService); + + // Update UI + mDeviceName = bleService.getDeviceName(); + mDeviceNameView.setText(mDeviceName); + mConnectButton.setText(R.string.action_disconnect); + + // And notify user if device is connected + if (bleService.isConnected()) { + onDeviceConnected(mBluetoothDevice); + } else { + // If the device is not connected it means that either it is still connecting, + // or the link was lost and service is trying to connect to it (autoConnect=true). + onDeviceConnecting(mBluetoothDevice); + } + } + + @Override + public void onServiceDisconnected(final ComponentName name) { + // Note: this method is called only when the service is killed by the system, + // not when it stops itself or is stopped by the activity. + // It will be called only when there is critically low memory, in practice never + // when the activity is in foreground. + Logger.d(mLogSession, "Activity disconnected from the service"); + mDeviceNameView.setText(getDefaultDeviceName()); + mConnectButton.setText(R.string.action_connect); + + mService = null; + mDeviceName = null; + mBluetoothDevice = null; + mLogSession = null; + onServiceUnbound(); + } + }; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + // Restore the old log session + if (savedInstanceState != null) { + final Uri logUri = savedInstanceState.getParcelable(LOG_URI); + mLogSession = Logger.openSession(getApplicationContext(), logUri); + } + + // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service + onInitialize(savedInstanceState); + // The onCreateView class should... create the view + onCreateView(savedInstanceState); + + /*final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); +*/ + // Common nRF Toolbox view references are obtained here + setUpView(); + // View is ready to be used + onViewCreated(savedInstanceState); + + LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onStart() { + super.onStart(); + + /* + * If the service has not been started before, the following lines will not start it. + * However, if it's running, the Activity will bind to it and notified via mServiceConnection. + */ + final Intent service = new Intent(this, getServiceClass()); + // We pass 0 as a flag so the service will not be created if not exists. + bindService(service, mServiceConnection, 0); + + /* + * When user exited the UARTActivity while being connected, the log session is kept in + * the service. We may not get it before binding to it so in this case this event will + * not be logged (mLogSession is null until onServiceConnected(..) is called). + * It will, however, be logged after the orientation changes. + */ + } + + @Override + protected void onStop() { + super.onStop(); + + try { + // We don't want to perform some operations (e.g. disable Battery Level notifications) + // in the service if we are just rotating the screen. However, when the activity will + // disappear, we may want to disable some device features to reduce the battery + // consumption. + if (mService != null) + mService.setActivityIsChangingConfiguration(isChangingConfigurations()); + + unbindService(mServiceConnection); + mService = null; + + Logger.d(mLogSession, "Activity unbound from the service"); + onServiceUnbound(); + mDeviceName = null; + mBluetoothDevice = null; + mLogSession = null; + } catch (final IllegalArgumentException e) { + // do nothing, we were not connected to the sensor + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver); + } + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE); + intentFilter.addAction(BleProfileService.BROADCAST_SERVICES_DISCOVERED); + intentFilter.addAction(BleProfileService.BROADCAST_DEVICE_READY); + intentFilter.addAction(BleProfileService.BROADCAST_BOND_STATE); + intentFilter.addAction(BleProfileService.BROADCAST_ERROR); + return intentFilter; + } + + /** + * Called when activity binds to the service. The parameter is the object returned in {@link Service#onBind(Intent)} method in your service. The method is + * called when device gets connected or is created while sensor was connected before. You may use the binder as a sensor interface. + */ + protected abstract void onServiceBound(E binder); + + /** + * Called when activity unbinds from the service. You may no longer use this binder because the sensor was disconnected. This method is also called when you + * leave the activity being connected to the sensor in the background. + */ + protected abstract void onServiceUnbound(); + + /** + * Returns the service class for sensor communication. The service class must derive from {@link BleProfileService} in order to operate with this class. + * + * @return the service class + */ + protected abstract Class getServiceClass(); + + /** + * Returns the service interface that may be used to communicate with the sensor. This will return null if the device is disconnected from the + * sensor. + * + * @return the service binder or null + */ + protected E getService() { + return mService; + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, i.e. using {@link #setContentView(int)}. + * Use to obtain references to views. Connect/Disconnect button, the device name view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected void onViewCreated(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called after the view and the toolbar has been created. + */ + protected final void setUpView() { + // set GUI + // getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = findViewById(R.id.action_connect); + mDeviceNameView = findViewById(R.id.device_name); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(SIS_DEVICE_NAME, mDeviceName); + outState.putParcelable(SIS_DEVICE, mBluetoothDevice); + if (mLogSession != null) + outState.putParcelable(LOG_URI, mLogSession.getSessionUri()); + } + + @Override + protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME); + mBluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE); + } + + + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (mService == null) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID()); + } else { + mService.disconnect(); + } + } else { + showBLEDialog(); + } + } + + /** + * Returns the title resource id that will be used to create logger session. If 0 is returned (default) logger will not be used. + * + * @return the title resource id + */ + protected int getLoggerProfileTitle() { + return 0; + } + + /** + * This method may return the local log content provider authority if local log sessions are supported. + * + * @return local log session content provider URI + */ + protected Uri getLocalAuthorityLogger() { + return null; + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final int titleId = getLoggerProfileTitle(); + if (titleId > 0) { + mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); + // If nRF Logger is not installed we may want to use local logger + if (mLogSession == null && getLocalAuthorityLogger() != null) { + mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); + } + } + mBluetoothDevice = device; + mDeviceName = name; + + // The device may not be in the range but the service will try to connect to it if it reach it + Logger.d(mLogSession, "Creating service..."); + final Intent service = new Intent(this, getServiceClass()); + service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress()); + service.putExtra(BleProfileService.EXTRA_DEVICE_NAME, name); + if (mLogSession != null) + service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri()); + startService(service); + Logger.d(mLogSession, "Binding to the service..."); + bindService(service, mServiceConnection, 0); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnecting(final BluetoothDevice device) { + mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available)); + mConnectButton.setText(R.string.action_connecting); + } + + @Override + public void onDeviceConnected(final BluetoothDevice device) { + mDeviceNameView.setText(mDeviceName); + mConnectButton.setText(R.string.action_disconnect); + } + + @Override + public void onDeviceDisconnecting(final BluetoothDevice device) { + mConnectButton.setText(R.string.action_disconnecting); + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + + try { + Logger.d(mLogSession, "Unbinding from the service..."); + unbindService(mServiceConnection); + mService = null; + + Logger.d(mLogSession, "Activity unbound from the service"); + onServiceUnbound(); + mDeviceName = null; + mBluetoothDevice = null; + mLogSession = null; + } catch (final IllegalArgumentException e) { + // do nothing. This should never happen but does... + } + } + + @Override + public void onLinkLossOccurred(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // empty default implementation + } + + @Override + public void onDeviceReady(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingRequired(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBonded(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingFailed(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onError(final BluetoothDevice device, final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + } + + @Override + public void onDeviceNotSupported(final BluetoothDevice device) { + showToast(R.string.not_supported); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(() -> Toast.makeText(BleProfileServiceReadyActivity.this, message, Toast.LENGTH_LONG).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(() -> Toast.makeText(BleProfileServiceReadyActivity.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mService != null && mService.isConnected(); + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Checks the {@link BleProfileService#EXTRA_DEVICE} in the given intent and compares it with the connected BluetoothDevice object. + * @param intent intent received via a broadcast from the service + * @return true if the data in the intent apply to the connected device, false otherwise + */ + protected boolean isBroadcastForThisDevice(final Intent intent) { + final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE); + return mBluetoothDevice != null && mBluetoothDevice.equals(bluetoothDevice); + } + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter) { + final ScannerFragment dialog = ScannerFragment.getInstance(filter); + dialog.show(getSupportFragmentManager(), "scan_fragment"); + } + + /** + * Returns the log session. Log session is created when the device was selected using the {@link ScannerFragment} and released when user press DISCONNECT. + * + * @return the logger session or null + */ + protected ILogSession getLogSession() { + return mLogSession; + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/LoggableBleManager.java b/app/src/main/java/no/Reader/android/iisc/profile/LoggableBleManager.java new file mode 100644 index 0000000..4562a6c --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/LoggableBleManager.java @@ -0,0 +1,48 @@ +package no.Reader.android.iisc.profile; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import android.util.Log; + +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LogContract; +import no.nordicsemi.android.log.Logger; + +/** + * The manager that logs to nRF Logger. If nRF Logger is not installed, logs are ignored. + * + * @param the callbacks class. + */ +public abstract class LoggableBleManager extends BleManager { + private ILogSession mLogSession; + + /** + * The manager constructor. + *

+ * After constructing the manager, the callbacks object must be set with + * {@link #setGattCallbacks(BleManagerCallbacks)}. + * + * @param context the context. + */ + public LoggableBleManager(@NonNull final Context context) { + super(context); + } + + /** + * Sets the log session to log into. + * + * @param session nRF Logger log session to log inti, or null, if nRF Logger is not installed. + */ + public void setLogger(@Nullable final ILogSession session) { + mLogSession = session; + } + + @Override + public void log(final int priority, @NonNull final String message) { + Logger.log(mLogSession, LogContract.Log.Level.fromPriority(priority), message); + Log.println(priority, "BleManager", message); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java new file mode 100644 index 0000000..9626c15 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java @@ -0,0 +1,615 @@ +package no.Reader.android.iisc.profile.multiconnect; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import android.util.Log; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import no.Reader.android.iisc.profile.LoggableBleManager; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.utils.ILogger; +import no.nordicsemi.android.log.ILogSession; + +public abstract class BleMulticonnectProfileService extends Service implements BleManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "BleMultiProfileService"; + + public static final String BROADCAST_CONNECTION_STATE = "no.Reader.android.iisc.BROADCAST_CONNECTION_STATE"; + public static final String BROADCAST_SERVICES_DISCOVERED = "no.Reader.android.iisc.BROADCAST_SERVICES_DISCOVERED"; + public static final String BROADCAST_DEVICE_READY = "no.Reader.android.iisc.DEVICE_READY"; + public static final String BROADCAST_BOND_STATE = "no.Reader.android.iisc.BROADCAST_BOND_STATE"; + @Deprecated + public static final String BROADCAST_BATTERY_LEVEL = "no.Reader.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String BROADCAST_ERROR = "no.Reader.android.iisc.BROADCAST_ERROR"; + + public static final String EXTRA_DEVICE = "no.Reader.android.iisc.EXTRA_DEVICE"; + public static final String EXTRA_CONNECTION_STATE = "no.Reader.android.iisc.EXTRA_CONNECTION_STATE"; + public static final String EXTRA_BOND_STATE = "no.Reader.android.iisc.EXTRA_BOND_STATE"; + public static final String EXTRA_SERVICE_PRIMARY = "no.Reader.android.iisc.EXTRA_SERVICE_PRIMARY"; + public static final String EXTRA_SERVICE_SECONDARY = "no.Reader.android.iisc.EXTRA_SERVICE_SECONDARY"; + @Deprecated + public static final String EXTRA_BATTERY_LEVEL = "no.Reader.android.iisc.EXTRA_BATTERY_LEVEL"; + public static final String EXTRA_ERROR_MESSAGE = "no.Reader.android.iisc.EXTRA_ERROR_MESSAGE"; + public static final String EXTRA_ERROR_CODE = "no.Reader.android.iisc.EXTRA_ERROR_CODE"; + + public static final int STATE_LINK_LOSS = -1; + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTED = 1; + public static final int STATE_CONNECTING = 2; + public static final int STATE_DISCONNECTING = 3; + + private HashMap> bleManagers; + private List managedDevices; + private Handler handler; + + protected boolean bound; + private boolean activityIsChangingConfiguration; + + private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); + final int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF); + + switch (state) { + case BluetoothAdapter.STATE_ON: + // On older phones (tested on Nexus 4 with Android 5.0.1) the Bluetooth requires some time + // after it has been enabled before some operations can start. Starting the GATT server here + // without a delay is very likely to cause a DeadObjectException from BluetoothManager#openGattServer(...). + handler.postDelayed(() -> onBluetoothEnabled(), 600); + break; + case BluetoothAdapter.STATE_TURNING_OFF: + case BluetoothAdapter.STATE_OFF: + if (previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) + onBluetoothDisabled(); + break; + } + } + }; + + public class LocalBinder extends Binder implements ILogger, IDeviceLogger { + /** + * Returns an unmodifiable list of devices managed by the service. + * The returned devices do not need to be connected at tha moment. Each of them was however created + * using {@link #connect(BluetoothDevice)} method so they might have been connected before and disconnected. + * @return unmodifiable list of devices managed by the service + */ + public final List getManagedDevices() { + return Collections.unmodifiableList(managedDevices); + } + + /** + * Connects to the given device. If the device is already connected this method does nothing. + * @param device target Bluetooth device + */ + public void connect(final BluetoothDevice device) { + connect(device, null); + } + + /** + * Adds the given device to managed and stars connecting to it. If the device is already connected this method does nothing. + * @param device target Bluetooth device + * @param session log session that has to be used by the device + */ + @SuppressWarnings("unchecked") + public void connect(final BluetoothDevice device, final ILogSession session) { + // If a device is in managed devices it means that it's already connected, or was connected + // using autoConnect and the link was lost but Android is already trying to connect to it. + if (managedDevices.contains(device)) + return; + managedDevices.add(device); + + LoggableBleManager manager = bleManagers.get(device); + if (manager == null) { + bleManagers.put(device, manager = initializeManager()); + manager.setGattCallbacks(BleMulticonnectProfileService.this); + } + manager.setLogger(session); + manager.connect(device) + .retry(2, 100) + .useAutoConnect(shouldAutoConnect()) + .timeout(10000) + .fail((d, status) -> { + managedDevices.remove(device); + bleManagers.remove(device); + }) + .enqueue(); + } + + /** + * Disconnects the given device and removes the associated BleManager object. + * If the list of BleManagers is empty while the last activity unbinds from the service, + * the service will stop itself. + * @param device target device to disconnect and forget + */ + public void disconnect(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + if (manager != null && manager.isConnected()) { + manager.disconnect().enqueue(); + } + managedDevices.remove(device); + } + + /** + * Returns true if the device is connected to the sensor. + * @param device the target device + * @return true if device is connected to the sensor, false otherwise + */ + public final boolean isConnected(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + return manager != null && manager.isConnected(); + } + + /** + * Returns true if the device has finished initializing. + * @param device the target device + * @return true if device is connected to the sensor and has finished + * initializing. False otherwise. + */ + public final boolean isReady(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + return manager != null && manager.isReady(); + } + + /** + * Returns the connection state of given device. + * @param device the target device + * @return the connection state, as in {@link BleManager#getConnectionState()}. + */ + @SuppressWarnings("unused") + public final int getConnectionState(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + return manager != null ? manager.getConnectionState() : BluetoothGatt.STATE_DISCONNECTED; + } + + /** + * Returns the last received battery level value. + * @param device the device of which battery level should be returned + * @return battery value or -1 if no value was received or Battery Level characteristic was not found + * @deprecated Keep battery value in your manager instead. + */ + @SuppressWarnings("deprecation") + @Deprecated + public int getBatteryValue(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + if (manager != null) + return manager.getBatteryValue(); + return 0; + } + + /** + * Sets whether the bound activity if changing configuration or not. + * If false, we will turn off battery level notifications in onUnbind(..) method below. + * @param changing true if the bound activity is finishing + */ + @SuppressWarnings("WeakerAccess") + public final void setActivityIsChangingConfiguration(final boolean changing) { + activityIsChangingConfiguration = changing; + } + + @Override + public void log(@NonNull final BluetoothDevice device, final int level, final String message) { + final BleManager manager = bleManagers.get(device); + if (manager != null) + manager.log(level, message); + } + + @Override + public void log(@NonNull final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params) { + final BleManager manager = bleManagers.get(device); + if (manager != null) + manager.log(level, messageRes, params); + } + + @Override + public void log(final int level, @NonNull final String message) { + for (final BleManager manager : bleManagers.values()) + manager.log(level, message); + } + + @Override + public void log(final int level, @StringRes final int messageRes, final Object... params) { + for (final BleManager manager : bleManagers.values()) + manager.log(level, messageRes, params); + } + } + + /** + * Returns a handler that is created in onCreate(). + * The handler may be used to postpone execution of some operations or to run them in UI thread. + */ + protected Handler getHandler() { + return handler; + } + + /** + * This method returns whether autoConnect option should be used. + * + * @return true to use autoConnect feature, false (default) otherwise. + */ + protected boolean shouldAutoConnect() { + return false; + } + + /** + * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the bound activity. + * + * @return the service binder + */ + protected LocalBinder getBinder() { + // default implementation returns the basic binder. You can overwrite the LocalBinder with your own, wider implementation + return new LocalBinder(); + } + + @Override + public IBinder onBind(final Intent intent) { + bound = true; + return getBinder(); + } + + @Override + public final void onRebind(final Intent intent) { + bound = true; + + if (!activityIsChangingConfiguration) { + onRebind(); + } + } + + /** + * Called when the activity has rebound to the service after being recreated. + * This method is not called when the activity was killed to be recreated when the phone orientation changed + * if prior to being killed called {@link LocalBinder#setActivityIsChangingConfiguration(boolean)} with parameter true. + */ + protected void onRebind() { + // empty default implementation + } + + @Override + public final boolean onUnbind(final Intent intent) { + bound = false; + + if (!activityIsChangingConfiguration) { + if (!managedDevices.isEmpty()) { + onUnbind(); + } else { + // The last activity has disconnected from the service and there are no devices to manage. The service may be stopped. + stopSelf(); + } + } + + // We want the onRebind method be called if anything else binds to it again + return true; + } + + /** + * Called when the activity has unbound from the service before being finished. + * This method is not called when the activity is killed to be recreated when the phone orientation changed. + */ + protected void onUnbind() { + // empty default implementation + } + + @Override + public void onCreate() { + super.onCreate(); + + handler = new Handler(); + + // Initialize the map of BLE managers + bleManagers = new HashMap<>(); + managedDevices = new ArrayList<>(); + + // Register broadcast receivers + registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + + // Service has now been created + onServiceCreated(); + + // Call onBluetoothEnabled if Bluetooth enabled + final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter.isEnabled()) { + onBluetoothEnabled(); + } + } + + /** + * Called when the service has been created, before the {@link #onBluetoothEnabled()} is called. + */ + protected void onServiceCreated() { + // empty default implementation + } + + /** + * Initializes the Ble Manager responsible for connecting to a single device. + * @return a new BleManager object + */ + @SuppressWarnings("rawtypes") + protected abstract LoggableBleManager initializeManager(); + + @Override + public int onStartCommand(final Intent intent, final int flags, final int startId) { + onServiceStarted(); + // The service does not save addresses of managed devices. + // A bound activity will be required to add connections again. + return START_NOT_STICKY; + } + + /** + * Called when the service has been started. + */ + protected void onServiceStarted() { + // empty default implementation + } + + @Override + public void onTaskRemoved(final Intent rootIntent) { + super.onTaskRemoved(rootIntent); + // This method is called when user removed the app from Recents. + // By default, the service will be killed and recreated immediately after that. + // However, all managed devices will be lost and devices will be disconnected. + stopSelf(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + onServiceStopped(); + handler = null; + } + + /** + * Called when the service has been stopped. + */ + protected void onServiceStopped() { + // Unregister broadcast receivers + unregisterReceiver(bluetoothStateBroadcastReceiver); + + // The managers map may not be empty if the service was killed by the system + for (final BleManager manager : bleManagers.values()) { + // Service is being destroyed, no need to disconnect manually. + manager.close(); + manager.log(Log.INFO, "Service destroyed"); + } + bleManagers.clear(); + managedDevices.clear(); + bleManagers = null; + managedDevices = null; + } + + /** + * Method called when Bluetooth Adapter has been disabled. + */ + protected void onBluetoothDisabled() { + // do nothing, BleManagers have their own Bluetooth State broadcast received and will close themselves + } + + /** + * This method is called when Bluetooth Adapter has been enabled. It is also called + * after the service was created if Bluetooth Adapter was enabled at that moment. + * This method could initialize all Bluetooth related features, for example open the GATT server. + * Make sure you call super.onBluetoothEnabled() at this methods reconnects to + * devices that were connected before the Bluetooth was turned off. + */ + protected void onBluetoothEnabled() { + for (final BluetoothDevice device : managedDevices) { + final BleManager manager = bleManagers.get(device); + if (manager != null && !manager.isConnected()) + manager.connect(device).enqueue(); + } + } + + @Override + public void onDeviceConnecting(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING); + LocalBroadcastManager.getInstance(BleMulticonnectProfileService.this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceConnected(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { + // Note: if BleManager#shouldAutoConnect() for this device returned true, this callback will be + // invoked ONLY when user requested disconnection (using Disconnect button). If the device + // disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead. + + // We no longer want to keep the device in the service + managedDevices.remove(device); + // The BleManager is not removed from the HashMap in order to keep the device's log session. + // bleManagers.remove(device); + + // Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // When user disconnected the last device while the activity was not bound the service can be stopped + if (!bound && managedDevices.isEmpty()) { + stopSelf(); + } + } + + @Override + public void onLinkLossOccurred(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) { + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceReady(@NonNull final BluetoothDevice device) { + final Intent broadcast = new Intent(BROADCAST_DEVICE_READY); + broadcast.putExtra(EXTRA_DEVICE, device); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceNotSupported(@NonNull final BluetoothDevice device) { + // We don't like this device, remove it from both collections + managedDevices.remove(device); + bleManagers.remove(device); + + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // no need for disconnecting, it will be disconnected by the manager automatically + } + + @SuppressWarnings("deprecation") + @Override + public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) { + final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_BATTERY_LEVEL, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBondingRequired(@NonNull final BluetoothDevice device) { + showToast("bonding "); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBonded(@NonNull final BluetoothDevice device) { + showToast(" bonded "); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBondingFailed(@NonNull final BluetoothDevice device) { + showToast(" bonding_failed "); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) { + final Intent broadcast = new Intent(BROADCAST_ERROR); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_ERROR_MESSAGE, message); + broadcast.putExtra(EXTRA_ERROR_CODE, errorCode); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId + * an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + handler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message + * a message to be shown + */ + protected void showToast(final String message) { + handler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, message, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns the {@link BleManager} object associated with given device, or null if such has not been created. + * To create a BleManager call the {@link LocalBinder#connect(BluetoothDevice)} method must be called. + * @param device the target device + * @return the BleManager or null + */ + protected BleManager getBleManager(final BluetoothDevice device) { + return bleManagers.get(device); + } + + /** + * Returns unmodifiable list of all managed devices. They don't have to be connected at the moment. + * @return list of managed devices + */ + protected List getManagedDevices() { + return Collections.unmodifiableList(managedDevices); + } + + /** + * Returns a list of those managed devices that are connected at the moment. + * @return list of connected devices + */ + protected List getConnectedDevices() { + final List list = new ArrayList<>(); + for (BluetoothDevice device : managedDevices) { + final BleManager manager = bleManagers.get(device); + if (manager != null && manager.isConnected()) + list.add(device); + } + return Collections.unmodifiableList(list); + } + + /** + * Returns true if the device is connected to the sensor. + * @param device the target device + * @return true if device is connected to the sensor, false otherwise + */ + protected boolean isConnected(final BluetoothDevice device) { + final BleManager manager = bleManagers.get(device); + return manager != null && manager.isConnected(); + } +} \ No newline at end of file diff --git a/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java new file mode 100644 index 0000000..da6903d --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java @@ -0,0 +1,502 @@ +package no.Reader.android.iisc.profile.multiconnect; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LocalLogSession; +import no.nordicsemi.android.log.Logger; +import no.Reader.android.iisc.R; +import no.Reader.android.iisc.scanner.ScannerFragment; +import no.Reader.android.iisc.DebugLogger; + +/** + *

+ * The {@link BleMulticonnectProfileServiceReadyActivity} activity is designed to be the base class for profile activities that uses services in order to connect + * more than one device at the same time. A service extending {@link BleMulticonnectProfileService} is created when the activity is created, and the activity binds to it. + * The service returns a binder that may be used to connect, disconnect or manage devices, and notifies the + * activity using Local Broadcasts ({@link LocalBroadcastManager}). See {@link BleMulticonnectProfileService} for messages. If the device is not in range it will listen for + * it and connect when it become visible. The service exists until all managed devices have been disconnected and unmanaged and the last activity unbinds from it. + *

+ *

+ * When user closes the activity (e.g. by pressing Back button) while being connected, the Service remains working. It's remains connected to the devices or still + * listens for updates from them. When entering back to the activity, activity will to bind to the service and refresh UI. + *

+ */ +public abstract class BleMulticonnectProfileServiceReadyActivity extends AppCompatActivity implements + ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks { + private static final String TAG = "BleMulticonnectProfileServiceReadyActivity"; + + protected static final int REQUEST_ENABLE_BT = 2; + + private E mService; + private List mManagedDevices; + + private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleMulticonnectProfileService.EXTRA_DEVICE); + final String action = intent.getAction(); + switch (action) { + case BleMulticonnectProfileService.BROADCAST_CONNECTION_STATE: { + final int state = intent.getIntExtra(BleMulticonnectProfileService.EXTRA_CONNECTION_STATE, BleMulticonnectProfileService.STATE_DISCONNECTED); + + switch (state) { + case BleMulticonnectProfileService.STATE_CONNECTED: { + onDeviceConnected(bluetoothDevice); + break; + } + case BleMulticonnectProfileService.STATE_DISCONNECTED: { + onDeviceDisconnected(bluetoothDevice); + break; + } + case BleMulticonnectProfileService.STATE_LINK_LOSS: { + onLinkLossOccurred(bluetoothDevice); + break; + } + case BleMulticonnectProfileService.STATE_CONNECTING: { + onDeviceConnecting(bluetoothDevice); + break; + } + case BleMulticonnectProfileService.STATE_DISCONNECTING: { + onDeviceDisconnecting(bluetoothDevice); + break; + } + default: + // there should be no other actions + break; + } + break; + } + case BleMulticonnectProfileService.BROADCAST_SERVICES_DISCOVERED: { + final boolean primaryService = intent.getBooleanExtra(BleMulticonnectProfileService.EXTRA_SERVICE_PRIMARY, false); + final boolean secondaryService = intent.getBooleanExtra(BleMulticonnectProfileService.EXTRA_SERVICE_SECONDARY, false); + + if (primaryService) { + onServicesDiscovered(bluetoothDevice, secondaryService); + } else { + onDeviceNotSupported(bluetoothDevice); + } + break; + } + case BleMulticonnectProfileService.BROADCAST_DEVICE_READY: { + onDeviceReady(bluetoothDevice); + break; + } + case BleMulticonnectProfileService.BROADCAST_BOND_STATE: { + final int state = intent.getIntExtra(BleMulticonnectProfileService.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); + switch (state) { + case BluetoothDevice.BOND_BONDING: + onBondingRequired(bluetoothDevice); + break; + case BluetoothDevice.BOND_BONDED: + onBonded(bluetoothDevice); + break; + } + break; + } + case BleMulticonnectProfileService.BROADCAST_BATTERY_LEVEL: { + final int value = intent.getIntExtra(BleMulticonnectProfileService.EXTRA_BATTERY_LEVEL, -1); + if (value > 0) + onBatteryValueReceived(bluetoothDevice, value); + break; + } + case BleMulticonnectProfileService.BROADCAST_ERROR: { + final String message = intent.getStringExtra(BleMulticonnectProfileService.EXTRA_ERROR_MESSAGE); + final int errorCode = intent.getIntExtra(BleMulticonnectProfileService.EXTRA_ERROR_CODE, 0); + onError(bluetoothDevice, message, errorCode); + break; + } + } + } + }; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @SuppressWarnings("unchecked") + @Override + public void onServiceConnected(final ComponentName name, final IBinder service) { + final E bleService = mService = (E) service; + bleService.log(Log.DEBUG, "Activity bound to the service"); + mManagedDevices.addAll(bleService.getManagedDevices()); + onServiceBound(bleService); + + // and notify user if device is connected + for (final BluetoothDevice device : mManagedDevices) { + if (bleService.isConnected(device)) + onDeviceConnected(device); + } + } + + @Override + public void onServiceDisconnected(final ComponentName name) { + mService = null; + onServiceUnbound(); + } + }; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mManagedDevices = new ArrayList<>(); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service + onInitialize(savedInstanceState); + // The onCreateView class should... create the view + onCreateView(savedInstanceState); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + + // Common nRF Toolbox view references are obtained here + setUpView(); + // View is ready to be used + onViewCreated(savedInstanceState); + + LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onStart() { + super.onStart(); + + /* + * In comparison to BleProfileServiceReadyActivity this activity always starts the service when started. + * Connecting to a device is done by calling mService.connect(BluetoothDevice) method, not startService(...) like there. + * The service will stop itself when all devices it manages were disconnected and unmanaged and the last activity unbinds from it. + */ + final Intent service = new Intent(this, getServiceClass()); + startService(service); + bindService(service, mServiceConnection, 0); + } + + @Override + protected void onStop() { + super.onStop(); + + if (mService != null) { + // We don't want to perform some operations (e.g. disable Battery Level notifications) in the service if we are just rotating the screen. + // However, when the activity will disappear, we may want to disable some device features to reduce the battery consumption. + mService.setActivityIsChangingConfiguration(isChangingConfigurations()); + // Log it here as there is no callback when the service gets unbound + // and the mService will not be available later (the activity doesn't keep log sessions) + mService.log(Log.DEBUG, "Activity unbound from the service"); + } + + unbindService(mServiceConnection); + mService = null; + + onServiceUnbound(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver); + } + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_CONNECTION_STATE); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_SERVICES_DISCOVERED); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_DEVICE_READY); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_BOND_STATE); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_BATTERY_LEVEL); + intentFilter.addAction(BleMulticonnectProfileService.BROADCAST_ERROR); + return intentFilter; + } + + /** + * Called when activity binds to the service. The parameter is the object returned in {@link Service#onBind(Intent)} method in your service. + * It is safe to obtain managed devices now. + */ + protected abstract void onServiceBound(E binder); + + /** + * Called when activity unbinds from the service. You may no longer use this binder methods. + */ + protected abstract void onServiceUnbound(); + + /** + * Returns the service class for sensor communication. The service class must derive from {@link BleMulticonnectProfileService} in order to operate with this class. + * + * @return the service class + */ + protected abstract Class getServiceClass(); + + /** + * Returns the service interface that may be used to communicate with the sensor. This will return null if the device is disconnected from the + * sensor. + * + * @return the service binder or null + */ + protected E getService() { + return mService; + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, i.e. using {@link #setContentView(int)}. + * Use to obtain references to views. Connect/Disconnect button and the device name view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + protected void onViewCreated(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called after the view and the toolbar has been created. + */ + protected final void setUpView() { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + + + + + /** + * Called when user press ADD DEVICE button. See layout files -> onClick attribute. + */ + public void onAddDeviceClicked(final View view) { + if (isBLEEnabled()) { + showDeviceScanningDialog(getFilterUUID()); + } else { + showBLEDialog(); + } + } + + /** + * Returns the title resource id that will be used to create logger session. If 0 is returned (default) logger will not be used. + * + * @return the title resource id + */ + protected int getLoggerProfileTitle() { + return 0; + } + + /** + * This method may return the local log content provider authority if local log sessions are supported. + * + * @return local log session content provider URI + */ + protected Uri getLocalAuthorityLogger() { + return null; + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final int titleId = getLoggerProfileTitle(); + ILogSession logSession = null; + if (titleId > 0) { + logSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); + // If nRF Logger is not installed we may want to use local logger + if (logSession == null && getLocalAuthorityLogger() != null) { + logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); + } + } + + mService.connect(device, logSession); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnecting(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onDeviceDisconnecting(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onLinkLossOccurred(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + // empty default implementation + } + + @Override + public void onDeviceReady(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingRequired(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBonded(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onBondingFailed(final BluetoothDevice device) { + // empty default implementation + } + + @Override + public void onDeviceNotSupported(final BluetoothDevice device) { + showToast(R.string.not_supported); + } + + @Override + public final boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) { + // This method will never be called. + // Please see BleMulticonnectProfileService#shouldEnableBatteryLevelNotifications(BluetoothDevice) instead. + throw new UnsupportedOperationException("This method should not be called"); + } + + @Override + public void onBatteryValueReceived(final BluetoothDevice device, final int value) { + // empty default implementation + } + + @Override + public void onError(final BluetoothDevice device, final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(() -> Toast.makeText(BleMulticonnectProfileServiceReadyActivity.this, message, Toast.LENGTH_LONG).show()); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(() -> Toast.makeText(BleMulticonnectProfileServiceReadyActivity.this, messageResId, Toast.LENGTH_SHORT).show()); + } + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Returns unmodifiable list of managed devices. Managed device is a device the was selected on ScannerFragment until it's removed from the managed list. + * It does not have to be connected at that moment. + * @return unmodifiable list of managed devices + */ + protected List getManagedDevices() { + return Collections.unmodifiableList(mManagedDevices); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + * @param device the device to check if it's connected + */ + protected boolean isDeviceConnected(final BluetoothDevice device) { + return mService != null && mService.isConnected(device); + } + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter) { + final ScannerFragment dialog = ScannerFragment.getInstance(filter); + dialog.show(getSupportFragmentManager(), "scan_fragment"); + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/IDeviceLogger.java b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/IDeviceLogger.java new file mode 100644 index 0000000..2a67f5f --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/profile/multiconnect/IDeviceLogger.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.Reader.android.iisc.profile.multiconnect; + +import android.bluetooth.BluetoothDevice; +import androidx.annotation.StringRes; + +public interface IDeviceLogger { + /** + * Logs the given message with given log level into the device's log session. + * @param device the target device + * @param level the log level + * @param message the message to be logged + */ + void log(final BluetoothDevice device, final int level, final String message); + + /** + * Logs the given message with given log level into the device's log session. + * @param device the target device + * @param level the log level + * @param messageRes string resource id + * @param params additional (optional) parameters used to fill the message + */ + void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params); +} diff --git a/app/src/main/java/no/Reader/android/iisc/scanner/DeviceListAdapter.java b/app/src/main/java/no/Reader/android/iisc/scanner/DeviceListAdapter.java new file mode 100644 index 0000000..f158c24 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/scanner/DeviceListAdapter.java @@ -0,0 +1,193 @@ +package no.Reader.android.iisc.scanner; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import no.nordicsemi.android.support.v18.scanner.ScanResult; +import no.Reader.android.iisc.R; + +/** + * DeviceListAdapter class is list adapter for showing scanned Devices name, address and RSSI image based on RSSI values. + */ +public class DeviceListAdapter extends BaseAdapter { + private static final int TYPE_TITLE = 0; + private static final int TYPE_ITEM = 1; + private static final int TYPE_EMPTY = 2; + + private final ArrayList mListBondedValues = new ArrayList<>(); + private final ArrayList mListValues = new ArrayList<>(); + private final Context mContext; + + public DeviceListAdapter(final Context context) { + mContext = context; + } + + /** + * Sets a list of bonded devices. + * @param devices list of bonded devices. + */ + public void addBondedDevices(final Set devices) { + final List bondedDevices = mListBondedValues; + for (BluetoothDevice device : devices) { + bondedDevices.add(new ExtendedBluetoothDevice(device)); + } + notifyDataSetChanged(); + } + + /** + * Updates the list of not bonded devices. + * @param results list of results from the scanner + */ + public void update(final List results) { + for (final ScanResult result : results) { + final ExtendedBluetoothDevice device = findDevice(result); + if (device == null) { + mListValues.add(new ExtendedBluetoothDevice(result)); + } else { + device.name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null; + device.rssi = result.getRssi(); + } + } + notifyDataSetChanged(); + } + + private ExtendedBluetoothDevice findDevice(final ScanResult result) { + for (final ExtendedBluetoothDevice device : mListBondedValues) + if (device.matches(result)) + return device; + for (final ExtendedBluetoothDevice device : mListValues) + if (device.matches(result)) + return device; + return null; + } + + public void clearDevices() { + mListValues.clear(); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + final int bondedCount = mListBondedValues.size() + 1; // 1 for the title + final int availableCount = mListValues.isEmpty() ? 2 : mListValues.size() + 1; // 1 for title, 1 for empty text + if (bondedCount == 1) + return availableCount; + return bondedCount + availableCount; + } + + @Override + public Object getItem(int position) { + final int bondedCount = mListBondedValues.size() + 1; // 1 for the title + if (mListBondedValues.isEmpty()) { + if (position == 0) + return R.string.scanner_subtitle_not_bonded; + else + return mListValues.get(position - 1); + } else { + if (position == 0) + return R.string.scanner_subtitle_bonded; + if (position < bondedCount) + return mListBondedValues.get(position - 1); + if (position == bondedCount) + return R.string.scanner_subtitle_not_bonded; + return mListValues.get(position - bondedCount - 1); + } + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return getItemViewType(position) == TYPE_ITEM; + } + + @Override + public int getItemViewType(int position) { + if (position == 0) + return TYPE_TITLE; + + if (!mListBondedValues.isEmpty() && position == mListBondedValues.size() + 1) + return TYPE_TITLE; + + if (position == getCount() - 1 && mListValues.isEmpty()) + return TYPE_EMPTY; + + return TYPE_ITEM; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View oldView, ViewGroup parent) { + final LayoutInflater inflater = LayoutInflater.from(mContext); + final int type = getItemViewType(position); + + View view = oldView; + switch (type) { + case TYPE_EMPTY: + if (view == null) { + view = inflater.inflate(R.layout.device_list_empty, parent, false); + } + break; + case TYPE_TITLE: + if (view == null) { + view = inflater.inflate(R.layout.device_list_title, parent, false); + } + final TextView title = (TextView) view; + title.setText((Integer) getItem(position)); + break; + default: + if (view == null) { + view = inflater.inflate(R.layout.device_list_row, parent, false); + final ViewHolder holder = new ViewHolder(); + holder.name = view.findViewById(R.id.name); + holder.address = view.findViewById(R.id.address); + holder.rssi = view.findViewById(R.id.rssi); + view.setTag(holder); + } + + final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position); + final ViewHolder holder = (ViewHolder) view.getTag(); + final String name = device.name; + holder.name.setText(name != null ? name : mContext.getString(R.string.not_available)); + holder.address.setText(device.device.getAddress()); + if (!device.isBonded || device.rssi != ExtendedBluetoothDevice.NO_RSSI) { + final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f)); + holder.rssi.setImageLevel(rssiPercent); + holder.rssi.setVisibility(View.VISIBLE); + } else { + holder.rssi.setVisibility(View.GONE); + } + break; + } + + return view; + } + + private class ViewHolder { + private TextView name; + private TextView address; + private ImageView rssi; + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/scanner/ExtendedBluetoothDevice.java b/app/src/main/java/no/Reader/android/iisc/scanner/ExtendedBluetoothDevice.java new file mode 100644 index 0000000..2fd873e --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/scanner/ExtendedBluetoothDevice.java @@ -0,0 +1,32 @@ +package no.Reader.android.iisc.scanner; + +import android.bluetooth.BluetoothDevice; + +import no.nordicsemi.android.support.v18.scanner.ScanResult; + +public class ExtendedBluetoothDevice { + /* package */ static final int NO_RSSI = -1000; + public final BluetoothDevice device; + /** The name is not parsed by some Android devices, f.e. Sony Xperia Z1 with Android 4.3 (C6903). It needs to be parsed manually. */ + public String name; + public int rssi; + public boolean isBonded; + + public ExtendedBluetoothDevice(final ScanResult scanResult) { + this.device = scanResult.getDevice(); + this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null; + this.rssi = scanResult.getRssi(); + this.isBonded = false; + } + + public ExtendedBluetoothDevice(final BluetoothDevice device) { + this.device = device; + this.name = device.getName(); + this.rssi = NO_RSSI; + this.isBonded = true; + } + + public boolean matches(final ScanResult scanResult) { + return device.getAddress().equals(scanResult.getDevice().getAddress()); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/scanner/ScannerFragment.java b/app/src/main/java/no/Reader/android/iisc/scanner/ScannerFragment.java new file mode 100644 index 0000000..7d5bf5d --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/scanner/ScannerFragment.java @@ -0,0 +1,268 @@ +package no.Reader.android.iisc.scanner; + +import android.Manifest; +import android.app.Dialog; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.ParcelUuid; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.DialogFragment; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.ListView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat; +import no.nordicsemi.android.support.v18.scanner.ScanCallback; +import no.nordicsemi.android.support.v18.scanner.ScanFilter; +import no.nordicsemi.android.support.v18.scanner.ScanResult; +import no.nordicsemi.android.support.v18.scanner.ScanSettings; +import no.Reader.android.iisc.R; + +/** + * ScannerFragment class scan required BLE devices and shows them in a list. This class scans and filter + * devices with standard BLE Service UUID and devices with custom BLE Service UUID. It contains a + * list and a button to scan/cancel. There is a interface {@link OnDeviceSelectedListener} which is + * implemented by activity in order to receive selected device. The scanning will continue to scan + * for 5 seconds and then stop. + */ +public class ScannerFragment extends DialogFragment { + private final static String TAG = "ScannerFragment"; + + private final static String PARAM_UUID = "param_uuid"; + private final static long SCAN_DURATION = 5000; + + private final static int REQUEST_PERMISSION_REQ_CODE = 34; // any 8-bit number + + private BluetoothAdapter mBluetoothAdapter; + private OnDeviceSelectedListener mListener; + private DeviceListAdapter mAdapter; + private final Handler mHandler = new Handler(); + private Button mScanButton; + + private View mPermissionRationale; + + private ParcelUuid mUuid; + + private boolean mIsScanning = false; + + public static ScannerFragment getInstance(final UUID uuid) { + final ScannerFragment fragment = new ScannerFragment(); + + final Bundle args = new Bundle(); + if (uuid != null) + args.putParcelable(PARAM_UUID, new ParcelUuid(uuid)); + fragment.setArguments(args); + return fragment; + } + + /** + * Interface required to be implemented by activity. + */ + public interface OnDeviceSelectedListener { + /** + * Fired when user selected the device. + * + * @param device + * the device to connect to + * @param name + * the device name. Unfortunately on some devices {@link BluetoothDevice#getName()} + * always returns null, i.e. Sony Xperia Z1 (C6903) with Android 4.3. + * The name has to be parsed manually form the Advertisement packet. + */ + void onDeviceSelected(final BluetoothDevice device, final String name); + + /** + * Fired when scanner dialog has been cancelled without selecting a device. + */ + void onDialogCanceled(); + } + + /** + * This will make sure that {@link OnDeviceSelectedListener} interface is implemented by activity. + */ + @Override + public void onAttach(final Context context) { + super.onAttach(context); + try { + this.mListener = (OnDeviceSelectedListener) context; + } catch (final ClassCastException e) { + throw new ClassCastException(context.toString() + " must implement OnDeviceSelectedListener"); + } + } + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Bundle args = getArguments(); + if (args != null && args.containsKey(PARAM_UUID)) { + mUuid = args.getParcelable(PARAM_UUID); + } + + final BluetoothManager manager = (BluetoothManager) requireContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (manager != null) { + mBluetoothAdapter = manager.getAdapter(); + } + } + + @Override + public void onDestroyView() { + stopScan(); + super.onDestroyView(); + } + + @NonNull + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); + final View dialogView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_device_selection, null); + final ListView listview = dialogView.findViewById(android.R.id.list); + + listview.setEmptyView(dialogView.findViewById(android.R.id.empty)); + listview.setAdapter(mAdapter = new DeviceListAdapter(getActivity())); + + builder.setTitle(R.string.scanner_title); + final AlertDialog dialog = builder.setView(dialogView).create(); + listview.setOnItemClickListener((parent, view, position, id) -> { + stopScan(); + dialog.dismiss(); + final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) mAdapter.getItem(position); + mListener.onDeviceSelected(d.device, d.name); + }); + + mPermissionRationale = dialogView.findViewById(R.id.permission_rationale); // this is not null only on API23+ + + mScanButton = dialogView.findViewById(R.id.action_cancel); + mScanButton.setOnClickListener(v -> { + if (v.getId() == R.id.action_cancel) { + if (mIsScanning) { + dialog.cancel(); + } else { + startScan(); + } + } + }); + + addBoundDevices(); + if (savedInstanceState == null) + startScan(); + return dialog; + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + mListener.onDialogCanceled(); + } + + @Override + public void onRequestPermissionsResult(final int requestCode, final @NonNull String[] permissions, final @NonNull int[] grantResults) { + switch (requestCode) { + case REQUEST_PERMISSION_REQ_CODE: { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // We have been granted the Manifest.permission.ACCESS_COARSE_LOCATION permission. Now we may proceed with scanning. + startScan(); + } else { + mPermissionRationale.setVisibility(View.VISIBLE); + Toast.makeText(getActivity(), R.string.no_required_permission, Toast.LENGTH_SHORT).show(); + } + break; + } + } + } + + /** + * Scan for 5 seconds and then stop scanning when a BluetoothLE device is found then mLEScanCallback + * is activated This will perform regular scan for custom BLE Service UUID and then filter out. + * using class ScannerServiceParser + */ + private void startScan() { + // Since Android 6.0 we need to obtain either Manifest.permission.ACCESS_COARSE_LOCATION or Manifest.permission.ACCESS_FINE_LOCATION to be able to scan for + // Bluetooth LE devices. This is related to beacons as proximity devices. + // On API older than Marshmallow the following code does nothing. + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + // When user pressed Deny and still wants to use this functionality, show the rationale + if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) && mPermissionRationale.getVisibility() == View.GONE) { + mPermissionRationale.setVisibility(View.VISIBLE); + return; + } + + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_REQ_CODE); + return; + } + + // Hide the rationale message, we don't need it anymore. + if (mPermissionRationale != null) + mPermissionRationale.setVisibility(View.GONE); + + mAdapter.clearDevices(); + mScanButton.setText(R.string.scanner_action_cancel); + + final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner(); + final ScanSettings settings = new ScanSettings.Builder() + .setLegacy(false) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build(); + final List filters = new ArrayList<>(); + filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build()); + scanner.startScan(filters, settings, scanCallback); + mIsScanning = true; + mHandler.postDelayed(() -> { + if (mIsScanning) { + stopScan(); + } + }, SCAN_DURATION); + } + + /** + * Stop scan if user tap Cancel button + */ + private void stopScan() { + if (mIsScanning) { + mScanButton.setText(R.string.scanner_action_scan); + + final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner(); + scanner.stopScan(scanCallback); + + mIsScanning = false; + } + } + + private ScanCallback scanCallback = new ScanCallback() { + @Override + public void onScanResult(final int callbackType, final ScanResult result) { + // do nothing + } + + @Override + public void onBatchScanResults(final List results) { + mAdapter.update(results); + } + + @Override + public void onScanFailed(final int errorCode) { + // should never be called + } + }; + + private void addBoundDevices() { + final Set devices = mBluetoothAdapter.getBondedDevices(); + mAdapter.addBondedDevices(devices); + } +} diff --git a/app/src/main/java/no/Reader/android/iisc/widget/ForegroundRelativeLayout.java b/app/src/main/java/no/Reader/android/iisc/widget/ForegroundRelativeLayout.java new file mode 100644 index 0000000..d86bcf3 --- /dev/null +++ b/app/src/main/java/no/Reader/android/iisc/widget/ForegroundRelativeLayout.java @@ -0,0 +1,149 @@ +/************************************************************************************************************************************************* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ************************************************************************************************************************************************/ + +package no.Reader.android.iisc.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import android.os.Build; +import androidx.annotation.NonNull; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +import no.Reader.android.iisc.R; + + +public class ForegroundRelativeLayout extends RelativeLayout { + + private Drawable mForegroundSelector; + private Rect mRectPadding; + private boolean mUseBackgroundPadding = false; + + public ForegroundRelativeLayout(Context context) { + super(context); + } + + public ForegroundRelativeLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ForegroundRelativeLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundRelativeLayout, + defStyle, 0); + + final Drawable d = a.getDrawable(R.styleable.ForegroundRelativeLayout_foreground); + if (d != null) { + setForeground(d); + } + + a.recycle(); + + if (this.getBackground() instanceof NinePatchDrawable) { + final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground(); + mRectPadding = new Rect(); + if (npd.getPadding(mRectPadding)) { + mUseBackgroundPadding = true; + } + } + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + + if (mForegroundSelector != null && mForegroundSelector.isStateful()) { + mForegroundSelector.setState(getDrawableState()); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + if (mForegroundSelector != null) { + if (mUseBackgroundPadding) { + mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom); + } else { + mForegroundSelector.setBounds(0, 0, w, h); + } + } + } + + @Override + protected void dispatchDraw(@NonNull Canvas canvas) { + super.dispatchDraw(canvas); + + if (mForegroundSelector != null) { + mForegroundSelector.draw(canvas); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || (who == mForegroundSelector); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState(); + } + + public void setForeground(Drawable drawable) { + if (mForegroundSelector != drawable) { + if (mForegroundSelector != null) { + mForegroundSelector.setCallback(null); + unscheduleDrawable(mForegroundSelector); + } + + mForegroundSelector = drawable; + + if (drawable != null) { + setWillNotDraw(false); + drawable.setCallback(this); + if (drawable.isStateful()) { + drawable.setState(getDrawableState()); + } + } else { + setWillNotDraw(true); + } + requestLayout(); + invalidate(); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public void drawableHotspotChanged(float x, float y) { + super.drawableHotspotChanged(x, y); + if (mForegroundSelector != null) { + mForegroundSelector.setHotspot(x, y); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/anim/bottom_animation.xml b/app/src/main/res/anim/bottom_animation.xml new file mode 100644 index 0000000..7cd1b21 --- /dev/null +++ b/app/src/main/res/anim/bottom_animation.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/button_animation.xml b/app/src/main/res/anim/button_animation.xml new file mode 100644 index 0000000..9eed840 --- /dev/null +++ b/app/src/main/res/anim/button_animation.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/top_animation.xml b/app/src/main/res/anim/top_animation.xml new file mode 100644 index 0000000..a3fa2d9 --- /dev/null +++ b/app/src/main/res/anim/top_animation.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/color/button_color.xml b/app/src/main/res/color/button_color.xml new file mode 100644 index 0000000..2c87a8e --- /dev/null +++ b/app/src/main/res/color/button_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/menu_text.xml b/app/src/main/res/color/menu_text.xml new file mode 100644 index 0000000..c6d777f --- /dev/null +++ b/app/src/main/res/color/menu_text.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/drawable-hdpi/battery.png b/app/src/main/res/drawable-hdpi/battery.png new file mode 100644 index 0000000..dd83f9b Binary files /dev/null and b/app/src/main/res/drawable-hdpi/battery.png differ diff --git a/app/src/main/res/drawable-hdpi/download.png b/app/src/main/res/drawable-hdpi/download.png new file mode 100644 index 0000000..eccc9fb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/download.png differ diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000..236bff5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png differ diff --git a/app/src/main/res/drawable-hdpi/dst_logo.png b/app/src/main/res/drawable-hdpi/dst_logo.png new file mode 100644 index 0000000..a37fed2 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/dst_logo.png differ diff --git a/app/src/main/res/drawable-hdpi/finalback.png b/app/src/main/res/drawable-hdpi/finalback.png new file mode 100644 index 0000000..59faa8c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/finalback.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_bluetooth.png b/app/src/main/res/drawable-hdpi/ic_action_bluetooth.png new file mode 100644 index 0000000..fce1884 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_bluetooth.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_disconnect.png b/app/src/main/res/drawable-hdpi/ic_action_disconnect.png new file mode 100644 index 0000000..e64801e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_disconnect.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_cgms_feature.png b/app/src/main/res/drawable-hdpi/ic_cgms_feature.png new file mode 100644 index 0000000..6e05b92 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_cgms_feature.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_0_bar.png b/app/src/main/res/drawable-hdpi/ic_rssi_0_bar.png new file mode 100644 index 0000000..40d094f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_rssi_0_bar.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png b/app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png new file mode 100644 index 0000000..72b6996 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_2_bars.png b/app/src/main/res/drawable-hdpi/ic_rssi_2_bars.png new file mode 100644 index 0000000..dfa10ec Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_rssi_2_bars.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png b/app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png new file mode 100644 index 0000000..ae512db Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_stat_notify_template.png b/app/src/main/res/drawable-hdpi/ic_stat_notify_template.png new file mode 100644 index 0000000..fc09568 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_notify_template.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_template_feature.png b/app/src/main/res/drawable-hdpi/ic_template_feature.png new file mode 100644 index 0000000..fef8a41 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_template_feature.png differ diff --git a/app/src/main/res/drawable-hdpi/iisc_logo.png b/app/src/main/res/drawable-hdpi/iisc_logo.png new file mode 100644 index 0000000..84e56a3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/iisc_logo.png differ diff --git a/app/src/main/res/drawable-hdpi/negative.png b/app/src/main/res/drawable-hdpi/negative.png new file mode 100644 index 0000000..d0c8308 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/negative.png differ diff --git a/app/src/main/res/drawable-hdpi/positive.png b/app/src/main/res/drawable-hdpi/positive.png new file mode 100644 index 0000000..68776ea Binary files /dev/null and b/app/src/main/res/drawable-hdpi/positive.png differ diff --git a/app/src/main/res/drawable-hdpi/sample.png b/app/src/main/res/drawable-hdpi/sample.png new file mode 100644 index 0000000..c546a8d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/sample.png differ diff --git a/app/src/main/res/drawable-mdpi/download.png b/app/src/main/res/drawable-mdpi/download.png new file mode 100644 index 0000000..098e582 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/download.png differ diff --git a/app/src/main/res/drawable-mdpi/dst_logo.png b/app/src/main/res/drawable-mdpi/dst_logo.png new file mode 100644 index 0000000..60691db Binary files /dev/null and b/app/src/main/res/drawable-mdpi/dst_logo.png differ diff --git a/app/src/main/res/drawable-mdpi/finalback.png b/app/src/main/res/drawable-mdpi/finalback.png new file mode 100644 index 0000000..b45ba91 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/finalback.png differ diff --git a/app/src/main/res/drawable-mdpi/iisc_logo.png b/app/src/main/res/drawable-mdpi/iisc_logo.png new file mode 100644 index 0000000..1975345 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/iisc_logo.png differ diff --git a/app/src/main/res/drawable-mdpi/negative.png b/app/src/main/res/drawable-mdpi/negative.png new file mode 100644 index 0000000..25f7078 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/negative.png differ diff --git a/app/src/main/res/drawable-mdpi/positive.png b/app/src/main/res/drawable-mdpi/positive.png new file mode 100644 index 0000000..2971e2c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/positive.png differ diff --git a/app/src/main/res/drawable-mdpi/sample.png b/app/src/main/res/drawable-mdpi/sample.png new file mode 100644 index 0000000..cb0a1ba Binary files /dev/null and b/app/src/main/res/drawable-mdpi/sample.png differ diff --git a/app/src/main/res/drawable-v21/button.xml b/app/src/main/res/drawable-v21/button.xml new file mode 100644 index 0000000..4ce2cf2 --- /dev/null +++ b/app/src/main/res/drawable-v21/button.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_feature_bg.xml b/app/src/main/res/drawable-v21/ic_feature_bg.xml new file mode 100644 index 0000000..28a32b0 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_feature_bg.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-v21/ic_icon_button_background.xml b/app/src/main/res/drawable-v21/ic_icon_button_background.xml new file mode 100644 index 0000000..6b1e883 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_icon_button_background.xml @@ -0,0 +1,18 @@ + + + + diff --git a/app/src/main/res/drawable-xhdpi/app_total_commander.png b/app/src/main/res/drawable-xhdpi/app_total_commander.png new file mode 100644 index 0000000..406c6cc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/app_total_commander.png differ diff --git a/app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png b/app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png new file mode 100644 index 0000000..73488f3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png differ diff --git a/app/src/main/res/drawable-xhdpi/download.png b/app/src/main/res/drawable-xhdpi/download.png new file mode 100644 index 0000000..b1a3476 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/download.png differ diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000..fabe9d9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png differ diff --git a/app/src/main/res/drawable-xhdpi/dst_logo.png b/app/src/main/res/drawable-xhdpi/dst_logo.png new file mode 100644 index 0000000..36895d2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/dst_logo.png differ diff --git a/app/src/main/res/drawable-xhdpi/finalback.png b/app/src/main/res/drawable-xhdpi/finalback.png new file mode 100644 index 0000000..e82b3a3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/finalback.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png b/app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png new file mode 100644 index 0000000..920f5ca Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_disconnect.png b/app/src/main/res/drawable-xhdpi/ic_action_disconnect.png new file mode 100644 index 0000000..44d6145 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_disconnect.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_cgms_feature.png b/app/src/main/res/drawable-xhdpi/ic_cgms_feature.png new file mode 100644 index 0000000..c18519d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_cgms_feature.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_notify_template.png b/app/src/main/res/drawable-xhdpi/ic_stat_notify_template.png new file mode 100644 index 0000000..8b4925d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_notify_template.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_template_feature.png b/app/src/main/res/drawable-xhdpi/ic_template_feature.png new file mode 100644 index 0000000..ac88d4a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_template_feature.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_settings.png b/app/src/main/res/drawable-xhdpi/ic_uart_settings.png new file mode 100644 index 0000000..fe5fec4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_uart_settings.png differ diff --git a/app/src/main/res/drawable-xhdpi/iisc_logo.png b/app/src/main/res/drawable-xhdpi/iisc_logo.png new file mode 100644 index 0000000..c01a84a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/iisc_logo.png differ diff --git a/app/src/main/res/drawable-xhdpi/negative.png b/app/src/main/res/drawable-xhdpi/negative.png new file mode 100644 index 0000000..c79eae4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/negative.png differ diff --git a/app/src/main/res/drawable-xhdpi/positive.png b/app/src/main/res/drawable-xhdpi/positive.png new file mode 100644 index 0000000..0c3d7b4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/positive.png differ diff --git a/app/src/main/res/drawable-xhdpi/sample.png b/app/src/main/res/drawable-xhdpi/sample.png new file mode 100644 index 0000000..b3ee7dc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/sample.png differ diff --git a/app/src/main/res/drawable-xxhdpi/action_bar_shadow.9.png b/app/src/main/res/drawable-xxhdpi/action_bar_shadow.9.png new file mode 100644 index 0000000..40991c9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/action_bar_shadow.9.png differ diff --git a/app/src/main/res/drawable-xxhdpi/download.png b/app/src/main/res/drawable-xxhdpi/download.png new file mode 100644 index 0000000..2701570 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/download.png differ diff --git a/app/src/main/res/drawable-xxhdpi/dst_logo.png b/app/src/main/res/drawable-xxhdpi/dst_logo.png new file mode 100644 index 0000000..ea6e42d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/dst_logo.png differ diff --git a/app/src/main/res/drawable-xxhdpi/finalback.png b/app/src/main/res/drawable-xxhdpi/finalback.png new file mode 100644 index 0000000..0c468b0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/finalback.png differ diff --git a/app/src/main/res/drawable-xxhdpi/gradient.xml b/app/src/main/res/drawable-xxhdpi/gradient.xml new file mode 100644 index 0000000..b859849 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/gradient.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_normal.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_normal.png new file mode 100644 index 0000000..9e16b1f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_add_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_pressed.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_pressed.png new file mode 100644 index 0000000..e4b6217 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_add_pressed.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_bluetooth.png b/app/src/main/res/drawable-xxhdpi/ic_action_bluetooth.png new file mode 100644 index 0000000..860c758 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_bluetooth.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_clear_normal.png b/app/src/main/res/drawable-xxhdpi/ic_action_clear_normal.png new file mode 100644 index 0000000..c03cb87 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_clear_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_clear_pressed.png b/app/src/main/res/drawable-xxhdpi/ic_action_clear_pressed.png new file mode 100644 index 0000000..ed70b4e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_clear_pressed.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_disconnect.png b/app/src/main/res/drawable-xxhdpi/ic_action_disconnect.png new file mode 100644 index 0000000..035ff88 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_disconnect.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_download_normal.png b/app/src/main/res/drawable-xxhdpi/ic_action_download_normal.png new file mode 100644 index 0000000..bde2379 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_download_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_download_pressed.png b/app/src/main/res/drawable-xxhdpi/ic_action_download_pressed.png new file mode 100644 index 0000000..2d91bc3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_download_pressed.png differ diff --git a/app/src/main/res/drawable-xxhdpi/iisc_logo.png b/app/src/main/res/drawable-xxhdpi/iisc_logo.png new file mode 100644 index 0000000..2626870 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/iisc_logo.png differ diff --git a/app/src/main/res/drawable-xxhdpi/negative.png b/app/src/main/res/drawable-xxhdpi/negative.png new file mode 100644 index 0000000..ecffa4d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/negative.png differ diff --git a/app/src/main/res/drawable-xxhdpi/positive.png b/app/src/main/res/drawable-xxhdpi/positive.png new file mode 100644 index 0000000..6802859 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/positive.png differ diff --git a/app/src/main/res/drawable-xxhdpi/sample.png b/app/src/main/res/drawable-xxhdpi/sample.png new file mode 100644 index 0000000..359354c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/sample.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/download.png b/app/src/main/res/drawable-xxxhdpi/download.png new file mode 100644 index 0000000..1c08de3 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/download.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/dst_logo.png b/app/src/main/res/drawable-xxxhdpi/dst_logo.png new file mode 100644 index 0000000..a7e0369 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/dst_logo.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/finalback.png b/app/src/main/res/drawable-xxxhdpi/finalback.png new file mode 100644 index 0000000..405bc77 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/finalback.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_bluetooth.png b/app/src/main/res/drawable-xxxhdpi/ic_action_bluetooth.png new file mode 100644 index 0000000..90d8a34 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_bluetooth.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_disconnect.png b/app/src/main/res/drawable-xxxhdpi/ic_action_disconnect.png new file mode 100644 index 0000000..b650848 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_disconnect.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_battery_alert.png b/app/src/main/res/drawable-xxxhdpi/ic_battery_alert.png new file mode 100644 index 0000000..6dfdb8f Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_battery_alert.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_battery_full.png b/app/src/main/res/drawable-xxxhdpi/ic_battery_full.png new file mode 100644 index 0000000..3503f6f Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_battery_full.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/iisc_logo.png b/app/src/main/res/drawable-xxxhdpi/iisc_logo.png new file mode 100644 index 0000000..93cb815 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/iisc_logo.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/negative.png b/app/src/main/res/drawable-xxxhdpi/negative.png new file mode 100644 index 0000000..2803055 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/negative.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/positive.png b/app/src/main/res/drawable-xxxhdpi/positive.png new file mode 100644 index 0000000..af13df8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/positive.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/sample.png b/app/src/main/res/drawable-xxxhdpi/sample.png new file mode 100644 index 0000000..37bfdd8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/sample.png differ diff --git a/app/src/main/res/drawable/app_sm_logo.png b/app/src/main/res/drawable/app_sm_logo.png new file mode 100644 index 0000000..97b6eac Binary files /dev/null and b/app/src/main/res/drawable/app_sm_logo.png differ diff --git a/app/src/main/res/drawable/bg_circle.xml b/app/src/main/res/drawable/bg_circle.xml new file mode 100644 index 0000000..0235a9b --- /dev/null +++ b/app/src/main/res/drawable/bg_circle.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_list_row.xml b/app/src/main/res/drawable/bg_list_row.xml new file mode 100644 index 0000000..07aca4b --- /dev/null +++ b/app/src/main/res/drawable/bg_list_row.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/button.xml b/app/src/main/res/drawable/button.xml new file mode 100644 index 0000000..fe22380 --- /dev/null +++ b/app/src/main/res/drawable/button.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/button_n.xml b/app/src/main/res/drawable/button_n.xml new file mode 100644 index 0000000..0b90321 --- /dev/null +++ b/app/src/main/res/drawable/button_n.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/button_p.xml b/app/src/main/res/drawable/button_p.xml new file mode 100644 index 0000000..d79ca8a --- /dev/null +++ b/app/src/main/res/drawable/button_p.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/buttonshape.xml b/app/src/main/res/drawable/buttonshape.xml new file mode 100644 index 0000000..85525c7 --- /dev/null +++ b/app/src/main/res/drawable/buttonshape.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/green_circle.xml b/app/src/main/res/drawable/green_circle.xml new file mode 100644 index 0000000..687ffcc --- /dev/null +++ b/app/src/main/res/drawable/green_circle.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_action_add.xml b/app/src/main/res/drawable/ic_action_add.xml new file mode 100644 index 0000000..b5f0f25 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_add.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_action_clear.xml b/app/src/main/res/drawable/ic_action_clear.xml new file mode 100644 index 0000000..88047bc --- /dev/null +++ b/app/src/main/res/drawable/ic_action_clear.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_action_download.xml b/app/src/main/res/drawable/ic_action_download.xml new file mode 100644 index 0000000..e0953c2 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_download.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_baseline_graphic_eq_24.xml b/app/src/main/res/drawable/ic_baseline_graphic_eq_24.xml new file mode 100644 index 0000000..adb13fc --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_graphic_eq_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_home_24.xml b/app/src/main/res/drawable/ic_baseline_home_24.xml new file mode 100644 index 0000000..4c5e854 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_home_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_info_24.xml b/app/src/main/res/drawable/ic_baseline_info_24.xml new file mode 100644 index 0000000..654cfb3 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_info_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_post_add_24.xml b/app/src/main/res/drawable/ic_baseline_post_add_24.xml new file mode 100644 index 0000000..7218cc6 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_post_add_24.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_baseline_save_alt_24.xml b/app/src/main/res/drawable/ic_baseline_save_alt_24.xml new file mode 100644 index 0000000..ddb9d4d --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_save_alt_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery.xml b/app/src/main/res/drawable/ic_battery.xml new file mode 100644 index 0000000..afde310 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_feature_bg.xml b/app/src/main/res/drawable/ic_feature_bg.xml new file mode 100644 index 0000000..b06fc4d --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_bg_n.xml b/app/src/main/res/drawable/ic_feature_bg_n.xml new file mode 100644 index 0000000..35242a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg_n.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_bg_p.xml b/app/src/main/res/drawable/ic_feature_bg_p.xml new file mode 100644 index 0000000..9a567f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg_p.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg.xml b/app/src/main/res/drawable/ic_feature_small_bg.xml new file mode 100644 index 0000000..8134d3d --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg_n.xml b/app/src/main/res/drawable/ic_feature_small_bg_n.xml new file mode 100644 index 0000000..6137705 --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg_n.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg_p.xml b/app/src/main/res/drawable/ic_feature_small_bg_p.xml new file mode 100644 index 0000000..3361815 --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg_p.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_rssi_bar.xml b/app/src/main/res/drawable/ic_rssi_bar.xml new file mode 100644 index 0000000..e37a8b7 --- /dev/null +++ b/app/src/main/res/drawable/ic_rssi_bar.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/text_back.xml b/app/src/main/res/drawable/text_back.xml new file mode 100644 index 0000000..b155c77 --- /dev/null +++ b/app/src/main/res/drawable/text_back.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/fontstyle.ttf b/app/src/main/res/font/fontstyle.ttf new file mode 100644 index 0000000..0ac5e51 Binary files /dev/null and b/app/src/main/res/font/fontstyle.ttf differ diff --git a/app/src/main/res/layout-land/activity_feature_gls.xml b/app/src/main/res/layout-land/activity_feature_gls.xml new file mode 100644 index 0000000..04f13ca --- /dev/null +++ b/app/src/main/res/layout-land/activity_feature_gls.xml @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +