diff --git a/app/build.gradle b/app/build.gradle index 062b33f..2228dce 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,7 +92,7 @@ dependencies { implementation 'com.github.nutes-uepb:simple-ble-scanner:v1.0.1' // Firebase SDK for Google Analytics - implementation 'com.google.firebase:firebase-analytics:17.2.1' + implementation 'com.google.firebase:firebase-analytics:17.2.2' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' // Logs diff --git a/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/ConnectionUtils.java b/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/ConnectionUtils.java new file mode 100644 index 0000000..1474599 --- /dev/null +++ b/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/ConnectionUtils.java @@ -0,0 +1,46 @@ +package br.edu.uepb.nutes.ocariot.utils; + +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Provides routines for checking connection with internet and bluetooth. + * + * @author Douglas Rafael + * @version 0.1 + * @copyright Copyright (c) 2017, NUTES/UEPB + */ +public class ConnectionUtils { + /** + * Checks if the device supports bluetooth. + * + * @return true for device supports bluetooth or false otherwise. + */ + public static boolean isSupportedBluetooth() { + return BluetoothAdapter.getDefaultAdapter() != null; + } + + /** + * Checks if bluetooth is enabled. + * + * @return true to enabled or false otherwise. + */ + public static boolean bluetoothIsEnabled() { + return BluetoothAdapter.getDefaultAdapter() != null && + BluetoothAdapter.getDefaultAdapter().isEnabled(); + } + + /** + * Checks if the device has an internet connection. + * + * @param context + * @return boolean + */ + public static boolean isNetworkAvailable(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnectedOrConnecting()); + } +} diff --git a/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/DialogLoading.java b/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/DialogLoading.java index 8625d52..f948125 100644 --- a/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/DialogLoading.java +++ b/app/src/main/java/br/edu/uepb/nutes/ocariot/utils/DialogLoading.java @@ -3,6 +3,7 @@ import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentManager; +import android.app.FragmentTransaction; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -12,6 +13,7 @@ import androidx.annotation.Nullable; import br.edu.uepb.nutes.ocariot.R; +import timber.log.Timber; /** * Dialog Loading. @@ -80,12 +82,21 @@ public void show(FragmentManager fragmentManager) { } } + @Override + public void show(FragmentManager manager, String tag) { + try { + super.show(manager, tag); + } catch (IllegalStateException e) { + Timber.d(e); + } + } + public void close() { if (fragmentManager == null) return; Fragment dialogFragment = fragmentManager.findFragmentByTag(DIALOG_TAG); - if (dialogFragment != null && this.isVisible()) { - this.dismiss(); + if (dialogFragment != null && super.isVisible()) { + super.dismissAllowingStateLoss(); } } } diff --git a/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/fragment/IotFragment.java b/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/fragment/IotFragment.java index 3268373..26483d7 100644 --- a/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/fragment/IotFragment.java +++ b/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/fragment/IotFragment.java @@ -55,6 +55,7 @@ import br.edu.uepb.nutes.ocariot.service.HRManager; import br.edu.uepb.nutes.ocariot.service.HRManagerCallback; import br.edu.uepb.nutes.ocariot.utils.AlertMessage; +import br.edu.uepb.nutes.ocariot.utils.ConnectionUtils; import br.edu.uepb.nutes.ocariot.utils.DateUtils; import br.edu.uepb.nutes.simpleblescanner.SimpleBleScanner; import br.edu.uepb.nutes.simpleblescanner.SimpleScannerCallback; @@ -82,9 +83,9 @@ public class IotFragment extends Fragment implements View.OnClickListener, HRMan private ObjectAnimator heartAnimation; private int minHR; private int maxHR; - private int avgHR; private int sumHR; private int totalHR; + private DecimalFormat df = new DecimalFormat("#.#"); // We need this variable to lock and unlock loading more. // We should not charge more when a request has already been made. @@ -197,7 +198,7 @@ public void onStart() { public void onResume() { super.onResume(); loadDataOcariot(); - if (bluetoothIsAvailable()) { + if (ConnectionUtils.bluetoothIsEnabled()) { mBoxEnableBluetooth.setVisibility(View.GONE); if (!hasLocationPermissions()) { requestLocationPermission(); @@ -212,7 +213,7 @@ public void onResume() { public void onStop() { super.onStop(); mContext.unregisterReceiver(mBluetoothReceiver); - if (bluetoothIsAvailable()) mScanner.stopScan(); + if (ConnectionUtils.bluetoothIsEnabled()) mScanner.stopScan(); } @Override @@ -285,16 +286,15 @@ private void populateView(List weights) { mBoxNoData.setVisibility(View.GONE); mBoxWeight.setVisibility(View.VISIBLE); - Weight lastWeight = weights.get(0); - DecimalFormat df = new DecimalFormat("#.#"); - mWeight.setText(Html.fromHtml(df.format(lastWeight.getValue()) + + mWeight.setText(Html.fromHtml(df.format(weights.get(0).getValue()) .concat("") - .concat(lastWeight.getUnit()) + .concat(weights.get(0).getUnit()) .concat("")) ); - if (lastWeight.getBodyFat() != null) { - mBodyFat.setText(Html.fromHtml(df.format(lastWeight.getBodyFat()) + if (weights.get(0).getBodyFat() != null) { + mBodyFat.setText(Html.fromHtml(df.format(weights.get(0).getBodyFat()) .concat("%")) ); } else { @@ -304,10 +304,9 @@ private void populateView(List weights) { double weightSum = 0d; for (Weight weight : weights) weightSum += weight.getValue(); - double average = weightSum / weights.size(); - mWeightAverage.setText(Html.fromHtml(df.format(average) + mWeightAverage.setText(Html.fromHtml(df.format(weightSum / weights.size()) .concat("") - .concat(lastWeight.getUnit()) + .concat(weights.get(0).getUnit()) .concat("")) ); mBoxNoData.setVisibility(View.GONE); @@ -373,7 +372,7 @@ private void updateViewHR(int hr, String timestamp) { // Update summary mMinHRTextView.setText(String.valueOf(minHR)); mMaxHRTextView.setText(String.valueOf(maxHR)); - mAvgHRTextView.setText(String.valueOf(avgHR)); + mAvgHRTextView.setText(String.valueOf(sumHR / totalHR)); }); } @@ -481,16 +480,6 @@ public void onClick(View v) { } } - /** - * check if bluetooth is enabled. - * - * @return boolean - */ - private boolean bluetoothIsAvailable() { - return BluetoothAdapter.getDefaultAdapter() != null && - BluetoothAdapter.getDefaultAdapter().isEnabled(); - } - /** * Checks whether the location permission was given. * @@ -524,7 +513,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis requestLocationPermission(); return; } - if (bluetoothIsAvailable()) { + if (ConnectionUtils.bluetoothIsEnabled()) { mScanner.stopScan(); mScanner.startScan(mScannerCallback); } @@ -563,7 +552,6 @@ public void onMeasurementReceived(@NonNull BluetoothDevice device, int heartRate sumHR += heartRate; minHR = heartRate < minHR ? heartRate : minHR; maxHR = heartRate > maxHR ? heartRate : maxHR; - avgHR = sumHR / totalHR; } updateViewHR(heartRate, timestamp); } diff --git a/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/preference/SettingsFragment.java b/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/preference/SettingsFragment.java index 001227f..5b10011 100644 --- a/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/preference/SettingsFragment.java +++ b/app/src/main/java/br/edu/uepb/nutes/ocariot/view/ui/preference/SettingsFragment.java @@ -23,6 +23,7 @@ import br.edu.uepb.nutes.ocariot.data.repository.local.pref.AppPreferencesHelper; import br.edu.uepb.nutes.ocariot.data.repository.remote.ocariot.OcariotNetRepository; import br.edu.uepb.nutes.ocariot.utils.AlertMessage; +import br.edu.uepb.nutes.ocariot.utils.ConnectionUtils; import br.edu.uepb.nutes.ocariot.utils.DateUtils; import br.edu.uepb.nutes.ocariot.utils.DialogLoading; import br.edu.uepb.nutes.ocariot.utils.FirebaseLogEvent; @@ -348,26 +349,7 @@ private void publishFitBitAuth(UserAccess userAccess) { * Force a new Fitbit sync. */ private void fitBitSync() { - if (!mChild.isFitbitAccessValid()) { - mAlertMessage.show(mContext.getResources().getString(R.string.alert_title_no_token_fitbit), - mContext.getResources().getString(R.string.alert_no_token_fitbit, mChild.getUsername()), - R.color.colorDanger, R.drawable.ic_warning_dark, 15000, true, - new AlertMessage.AlertMessageListener() { - @Override - public void onHideListener() { - // not implemented! - } - - @Override - public void onClickListener() { - if (mUserAccess.getSubjectType().equals(User.Type.FAMILY)) { - return; - } - openFitbitAuth(); - } - }); - return; - } + if (!checkCanSync()) return; mDisposable.add( OcariotNetRepository.getInstance() @@ -375,7 +357,7 @@ public void onClickListener() { .doOnSubscribe(disposable -> { if (!mDialogSync.isVisible()) mDialogSync.show(getFragmentManager()); }) - .doAfterTerminate(() -> mDialogSync.close()) + .doFinally(() -> mDialogSync.close()) .subscribe( fitBitSync -> { mChild.setLastSync(DateUtils.getCurrentDatetimeUTC()); @@ -392,6 +374,32 @@ public void onClickListener() { ); } + private boolean checkCanSync() { + if (!mChild.isFitbitAccessValid()) { + mAlertMessage.show(mContext.getResources().getString(R.string.alert_title_no_token_fitbit), + mContext.getResources().getString(R.string.alert_no_token_fitbit, mChild.getUsername()), + R.color.colorDanger, R.drawable.ic_warning_dark, 15000, true, + new AlertMessage.AlertMessageListener() { + @Override + public void onHideListener() { + // not implemented! + } + + @Override + public void onClickListener() { + if (mUserAccess.getSubjectType().equals(User.Type.FAMILY)) return; + openFitbitAuth(); + } + }); + return false; + } else if (!ConnectionUtils.isNetworkAvailable(mContext)) { + mAlertMessage.show(R.string.title_connection_error, R.string.error_connection, + R.color.colorDanger, R.drawable.ic_warning_dark); + return false; + } + return true; + } + /** * Revokes the Fitbit access token. */ diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 0e66bfb..77ad523 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -118,10 +118,10 @@ Sincronize dados de serviços externos com a plataforma OCARIoT. Sincronizando Sincronizando dados Fitbit da criança \"%s\" com a plataforma OCARIoT… - Ocorreu um erro ao tentar sincronizar os dados do Fitbit do criança "%s" com a plataforma OCARIoT.\nPor favor, tente novamente mais tarde… - Os dados do Fitbit da criança "%s" foram sincronizados com sucesso com a plataforma OCARIoT. + Ocorreu um erro ao tentar sincronizar os dados Fitbit da criança "%s" com a plataforma OCARIoT.\nPor favor, tente novamente mais tarde… + Os dados Fitbit da criança "%s" foram sincronizados com sucesso com a plataforma OCARIoT. Última sinc: %s - Ocorreu um erro ao tentar recuperar token de acesso do Fitbit.\nPor favor, tente mais tarde… + Ocorreu um erro ao tentar recuperar o token de acesso Fitbit.\nPor favor, tente mais tarde… Problema na autenticação!