diff --git a/app/build.gradle b/app/build.gradle index 5f71d96..d950c41 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,11 +48,12 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') testImplementation 'junit:junit:4.13' - implementation 'androidx.appcompat:appcompat:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'com.google.android.material:material:1.2.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.journeyapps:zxing-android-embedded:4.1.0' - implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "com.android.support:support-compat:28.0.0" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a1578f..7d86f18 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="net.foucry.pilldroid"> + medicaments = new LinkedList(); private static final String TAG = DBHelper.class.getName(); @@ -213,16 +216,15 @@ class DBHelper extends SQLiteOpenHelper { /** * - * @return a List of All medicaments presents in database + * @return a Sorted and updated by dateEndOfStock List of All medicaments presents in database */ List getAllDrugs() { - List medicaments = new LinkedList(); // Build the query String query = "SELECT * FROM " + TABLE_DRUG; - // Get reference to readable DB (tutorial parle de writable, mais bof... on verra) + // Get reference to readable DB SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(query, null); @@ -252,6 +254,21 @@ class DBHelper extends SQLiteOpenHelper { } cursor.close(); + + Medicament currentMedicament = null; + for (int position = 0 ; position < getCount() ; position++ ) { + currentMedicament = getItem(position); + currentMedicament.newStock(currentMedicament.getStock()); + updateDrug(currentMedicament); + } + + Collections.sort(medicaments, new Comparator() { + @Override + public int compare(Medicament lhs, Medicament rhs) { + return lhs.getDateEndOfStock().compareTo(rhs.getDateEndOfStock()); + } + }); + Log.d(TAG, "getAllDrugs " + medicaments.toString()); return medicaments; @@ -276,6 +293,7 @@ class DBHelper extends SQLiteOpenHelper { values.put(KEY_ADMIN, medicament.getMode_administration()); values.put(KEY_PRES, medicament.getPresentation()); values.put(KEY_STOCK, medicament.getStock()); + values.put(KEY_PRISE, medicament.getPrise()); Log.d(TAG, "values are " +values.toString()); // Update row @@ -326,6 +344,11 @@ class DBHelper extends SQLiteOpenHelper { mCount.close(); return count; } + + public Medicament getItem(int position) { + return medicaments.get(position); + } + boolean isMedicamentExist(String cip13) { boolean value = false; try { diff --git a/app/src/main/java/net/foucry/pilldroid/MedicamentListActivity.java b/app/src/main/java/net/foucry/pilldroid/MedicamentListActivity.java index 6ad09e6..727b753 100644 --- a/app/src/main/java/net/foucry/pilldroid/MedicamentListActivity.java +++ b/app/src/main/java/net/foucry/pilldroid/MedicamentListActivity.java @@ -3,12 +3,12 @@ package net.foucry.pilldroid; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; -import android.app.PendingIntent; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.BitmapFactory; +import android.icu.util.Calendar; import android.os.Bundle; import android.os.SystemClock; import androidx.annotation.NonNull; @@ -29,6 +29,16 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.zxing.client.android.Intents; +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; + import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; @@ -55,7 +65,6 @@ import static net.foucry.pilldroid.Utils.intRandomExclusive; */ public class MedicamentListActivity extends AppCompatActivity { - private static final String CHANNEL_ID = "MedicamentCHANEL"; /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet * device. @@ -92,17 +101,12 @@ public class MedicamentListActivity extends AppCompatActivity { private SimpleItemRecyclerViewAdapter mAdapter; - public int getCount() { - return medicaments.size(); - } - public Medicament getItem(int position) { return medicaments.get(position); } public void constructMedsList() { - Medicament currentMedicament; dbHelper = new DBHelper(getApplicationContext()); if (!(medicaments == null)) { @@ -112,19 +116,6 @@ public class MedicamentListActivity extends AppCompatActivity { } medicaments = dbHelper.getAllDrugs(); - Collections.sort(medicaments, new Comparator() { - @Override - public int compare(Medicament lhs, Medicament rhs) { - return lhs.getDateEndOfStock().compareTo(rhs.getDateEndOfStock()); - } - }); - - for (int position = 0 ; position < this.getCount() ; position++ ) { - currentMedicament = this.getItem(position); - currentMedicament.newStock(currentMedicament.getStock()); - dbHelper.updateDrug(currentMedicament); - } - View mRecyclerView = findViewById(R.id.medicament_list); assert mRecyclerView != null; setupRecyclerView((RecyclerView) mRecyclerView); @@ -227,8 +218,11 @@ public class MedicamentListActivity extends AppCompatActivity { public void onPause() { super.onPause(); + scheduleJob(); + } - newStockCalculation(); + public void onResume() { + super.onResume(); } /** scanNow @@ -240,40 +234,11 @@ public class MedicamentListActivity extends AppCompatActivity { new IntentIntegrator(this).setOrientationLocked(false).setCaptureActivity(CustomScannerActivity.class).initiateScan(); } - /** - * Calculation of newStock - */ - public void newStockCalculation() { - Calendar calendar = Calendar.getInstance(); - Date now = calendar.getTime(); - - long dateSchedule; - - Medicament firstMedicament = null; - - try { - firstMedicament = medicaments.get(0); - } - catch (Exception ignored){} - - if (firstMedicament != null) { - Date dateAlert = UtilDate.removeDaysToDate(firstMedicament.getAlertThreshold(), firstMedicament.getDateEndOfStock()); - - if (dateAlert.getTime() < now.getTime()) { - dateSchedule = now.getTime() + 50000; // If dateAlert < now we schedule an alert for now + 5 seconds (3600000 pour 1 heure)[in prod define delay] - } else { - dateSchedule = dateAlert.getTime(); // If dateAlert > now we use dateAlert as scheduleDate - } - - long delay = dateSchedule - now.getTime(); - scheduleNotification(getNotification(getString(R.string.notification_text)), delay); - - Log.d(TAG, "Notification scheduled for " + UtilDate.convertDate(dateSchedule)); - } - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + Log.d(TAG, "REQUEST_CODE = " + requestCode + " RESULT_CODE = " + resultCode); + if (requestCode != CUSTOMIZED_REQUEST_CODE && requestCode != IntentIntegrator.REQUEST_CODE) { // This is important, otherwise the result will not be passed to the fragment super.onActivityResult(requestCode, resultCode, data); @@ -407,41 +372,27 @@ public class MedicamentListActivity extends AppCompatActivity { recyclerView.setAdapter(mAdapter); } - private void scheduleNotification(Notification notification, long delay) { - Log.d(TAG, "scheduleNotification delay == " + delay); + public void scheduleJob() { + Calendar calendar = Calendar.getInstance(); + Date now = calendar.getTime(); - Intent notificationIntent = new Intent(this, NotificationPublisher.class); - notificationIntent.putExtra(NOTIFICATION_ID, 1); - notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification); - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - long futureInMillis = SystemClock.elapsedRealtime() + 30000; - AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); - if (alarmManager != null) { - alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent); + ComponentName componentName = new ComponentName(this, PillDroidJobService.class); + JobInfo info = new JobInfo.Builder(24560, componentName) + .setPersisted(true) + .setPeriodic(15 *60 *1000) + .build(); + JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE); + int resultCode = scheduler.schedule(info); + if (resultCode == JobScheduler.RESULT_SUCCESS) { + Log.d(TAG, ("Job scheduled " + UtilDate.convertDate(now.getTime()+15 * 60*1000))); + } else { + Log.d(TAG, "Job scheduling failed"); } } - - private Notification getNotification(String content) { - Log.d(TAG, "content = " + content); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) - .setContentTitle(getAppName()) - .setContentText(content) - .setSmallIcon(R.drawable.ic_pill) - .setAutoCancel(true) - .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), - R.drawable.ic_launcher)); - return builder.build(); - } - - private String getAppName() { - PackageManager packageManager = getApplicationContext().getPackageManager(); - ApplicationInfo applicationInfo = null; - try { - applicationInfo = packageManager.getApplicationInfo(this.getPackageName(), 0); - } catch (final PackageManager.NameNotFoundException ignored) {} - return (String)((applicationInfo != null) ? packageManager.getApplicationLabel(applicationInfo) : "???"); + public void cancelJob(View v) { + JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE); + scheduler.cancel(24560); + Log.d(TAG, "Job cancelled"); } /** @@ -462,7 +413,7 @@ public class MedicamentListActivity extends AppCompatActivity { notifyDataSetChanged(); dbHelper.addDrug(scannedMedoc); } else { - Toast.makeText(getApplicationContext(), "aleready in the database", Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), "already in the database", Toast.LENGTH_SHORT).show(); } } @@ -524,8 +475,7 @@ public class MedicamentListActivity extends AppCompatActivity { Context context = v.getContext(); Intent intent = new Intent(context, MedicamentDetailActivity.class); intent.putExtra("medicament", medicamentCourant); - int requestCode =1; - startActivityForResult(intent, requestCode); + startActivityForResult(intent, CUSTOMIZED_REQUEST_CODE); } } }); @@ -577,4 +527,4 @@ editText.addTextChangeListener( new TextWatcher() { } }); - */ \ No newline at end of file + */ diff --git a/app/src/main/java/net/foucry/pilldroid/NotificationPublisher.java b/app/src/main/java/net/foucry/pilldroid/NotificationPublisher.java index 55a832b..aacec21 100644 --- a/app/src/main/java/net/foucry/pilldroid/NotificationPublisher.java +++ b/app/src/main/java/net/foucry/pilldroid/NotificationPublisher.java @@ -1,35 +1,105 @@ package net.foucry.pilldroid; -import android.app.Notification; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.VibrationEffect; -import android.os.Vibrator; +import android.media.RingtoneManager; +import android.net.Uri; import android.util.Log; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + /** * Created by jfoucry on 6/23/16. + * Publish notification */ + + public class NotificationPublisher extends BroadcastReceiver { - private static String TAG = NotificationPublisher.class.getName(); - public static String NOTIFICATION_ID = "notification-id"; - public static String NOTIFICATION = "notification"; + private static final String TAG = NotificationPublisher.class.getName(); + public static String NOTIFICATION_ID = "notification_id"; + public static String KEY_MESSAGE = "key_message"; + public static String KEY_TITLE = "key_title"; + public static String KEY_EXPAND = "key_expand"; + public static String KEY_SOUND = "key_sound"; + public static String KEY_MULTIPLE = "key_multiple"; + public static String APP_NAME = "PillDroid"; + + /** + * onReceive notification + * @param Context context + * @param Intent intent + */ + @Override public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Receive notification"); + Log.d(TAG, "Receive notification"); - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + int notificationId = intent.getIntExtra(NOTIFICATION_ID, 0); + String message = intent.getStringExtra(KEY_MESSAGE); + String title = intent.getStringExtra(KEY_TITLE); + boolean isEnabledExpand = intent.getBooleanExtra(KEY_EXPAND, false); + boolean isEnableSound = intent.getBooleanExtra(KEY_SOUND, false); + boolean isEnabledMultiple = intent.getBooleanExtra(KEY_MULTIPLE, false); - Notification notification = intent.getParcelableExtra(NOTIFICATION); - int id = intent.getIntExtra(NOTIFICATION_ID,0); - if (notificationManager != null) { - notificationManager.notify(id, notification); + String channel_id = createNotificationChannel(context); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channel_id) + .setSmallIcon(R.drawable.ic_pill) + .setContentTitle(context.getString(R.string.app_name)) + .setContentText(context.getString(R.string.pharmacy)) + .setChannelId(APP_NAME) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(context.getString(R.string.pharmacy))) + .setAutoCancel(true) + .setPriority(NotificationCompat.PRIORITY_DEFAULT); + + if (isEnableSound) { + Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + builder.setSound(alarmSound); } - Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - assert vibrator != null; - vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)); + + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + + // notificationId is a unique int for each notification that you must define + notificationManager.notify(notificationId, builder.build()); } -} + + /** + * createNotificationChannelid for android API >= 28 + * @param Context context + * @return String channel_id + */ + public static String createNotificationChannel(Context context) { + + Log.d(TAG, "start create notification channel"); + // The id of the channel. + String channelId = "Channel_id"; + + // The user-visible name of the channel. + CharSequence channelName = context.getString(R.string.app_name); + // The user-visible description of the channel. + String channelDescription = "Pilldroid Alert"; + int channelImportance = NotificationManager.IMPORTANCE_DEFAULT; + // int channelLockscreenVisibility = Notification.; + + // Initializes NotificationChannel. + NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, + channelImportance); + notificationChannel.setDescription(channelDescription); + notificationChannel.enableVibration(true); + // notificationChannel.setLockscreenVisibility(channelLockscreenVisibility); + + // Adds NotificationChannel to system. Attempting to create an existing notification + // channel with its original values performs no operation, so it's safe to perform the + // below sequence. + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + assert notificationManager != null; + notificationManager.createNotificationChannel(notificationChannel); + + return channelId; + } +} \ No newline at end of file diff --git a/app/src/main/java/net/foucry/pilldroid/PillDroidJobService.java b/app/src/main/java/net/foucry/pilldroid/PillDroidJobService.java index c913ac6..db8c8fa 100644 --- a/app/src/main/java/net/foucry/pilldroid/PillDroidJobService.java +++ b/app/src/main/java/net/foucry/pilldroid/PillDroidJobService.java @@ -1,43 +1,134 @@ package net.foucry.pilldroid; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.job.JobParameters; import android.app.job.JobService; -import android.os.Message; -import android.os.Handler; +import android.icu.util.Calendar; import android.util.Log; -import android.widget.Toast; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import java.util.Date; +import java.util.List; /** * Created by jacques on 17/09/16. */ + public class PillDroidJobService extends JobService { - private static final String TAG = "JobService"; + private static final String TAG = JobService.class.getName(); + private boolean jobCancelled = false; + private String CHANNEL_ID = "pillDroid"; + private DBHelper dbHelper = new DBHelper(this); - private Handler mJobHandler = new Handler(new Handler.Callback() { - @Override - public boolean handleMessage(Message msg) { -// Toast.makeText( getApplicationContext(), "PillDroid - Calcul nouveau stocks", Toast.LENGTH_SHORT).show(); -// MedicamentListActivity.newStockCalculation(getApplicationContext()); - - jobFinished( (JobParameters) msg.obj,false); - return true; - } - }); @Override - public boolean onStartJob (JobParameters params) { - Log.i(TAG, "on Start Job: " + params.getJobId()); - mJobHandler.sendMessage(Message.obtain(mJobHandler, 1,params)); - return false; + public boolean onStartJob(JobParameters params) { + Log.d(TAG, "Job started"); + createNotificationChannel(); + doBackgroundWork(params); + + return true; } + /** + * Grab sorted list of medicaments + * test dateAlert of the first of the list + * if dateAlert < now + * schedule notification + * @param JobParameters params + */ + private void doBackgroundWork(final JobParameters params) { + + if (jobCancelled) { + return; + } + List medicaments = dbHelper.getAllDrugs(); + + Calendar calendar = Calendar.getInstance(); + Date now = calendar.getTime(); + + long dateSchedule; + + Medicament firstMedicament = null; + + try { + firstMedicament = medicaments.get(0); + } + catch (Exception ignored){} + + if (firstMedicament != null) { + Date dateAlert = UtilDate.removeDaysToDate(firstMedicament.getAlertThreshold(), firstMedicament.getDateEndOfStock()); + + if (dateAlert.getTime() < now.getTime()) { + dateSchedule = now.getTime() + 120000; // If dateAlert < now we schedule an alert for now + 120 seconds + } else { + dateSchedule = dateAlert.getTime(); // If dateAlert > now we use dateAlert as scheduleDate + } + + long delay = dateSchedule - now.getTime(); + scheduleNotification(delay); + } + + Log.d(TAG, "Job finished"); + jobFinished(params, false); + } + + @Override public boolean onStopJob(JobParameters params) { - mJobHandler.removeMessages(1); - return false; + Log.d(TAG, "Job cancelled before completion"); + jobCancelled = true; + return true; } + /** + * Schedule Notification for the delay + * @param Context context + * @param long delay - date for the notification in millisecond + */ + private void scheduleNotification(long delay) { + Log.d(TAG, "scheduleNotification delay == " + delay); + createNotificationChannel(); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_pill) + .setContentTitle(getString(R.string.app_name)) + .setContentText(getString(R.string.pharmacy)) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setAutoCancel(true); -} + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + int notificationId = 666; + notificationManager.notify(notificationId, builder.build()); + } + + /** + * createNotificationChannelid for android API >= 28 + */ + private void createNotificationChannel() { + + Log.d(TAG, "start create notification channel"); + CharSequence name = getString(R.string.channel_name); + String description = getString(R.string.channel_description); + int importance = NotificationManager.IMPORTANCE_DEFAULT; + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); + channel.setDescription(description); + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + NotificationManager notificationManager = getSystemService(NotificationManager.class); + try { + notificationManager.createNotificationChannel(channel); + } catch (Exception e) { + // This will catch any exception, because they are all descended from Exception + Log.e(TAG, e.toString()); + //At the level Exception Class handle the error in Exception Table + // Exception Create That Error Object and throw it + //E.g: FileNotFoundException ,etc + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/foucry/pilldroid/UtilDate.java b/app/src/main/java/net/foucry/pilldroid/UtilDate.java index 145ff2b..28dd297 100644 --- a/app/src/main/java/net/foucry/pilldroid/UtilDate.java +++ b/app/src/main/java/net/foucry/pilldroid/UtilDate.java @@ -15,11 +15,11 @@ import java.util.Locale; class UtilDate { private static final String TAG = UtilDate.class.getName(); + /** - * * @param aDate anydate * @return date the same date as input but at noon (12:00:00) - * + *

* set date time at Noon */ static Date dateAtNoon(Date aDate) { @@ -34,12 +34,12 @@ class UtilDate { return calendar.getTime(); } + /** - * * @param days number of days to remove to the ate * @param date date before day removing * @return date - * + *

* Substract days to date and return a new date */ static Date removeDaysToDate(int days, Date date) { @@ -51,10 +51,9 @@ class UtilDate { } /** - * * @param date Date to be converted * @return String of the converted date - * + *

* Convert a date to a String using a SimpleDateFormat */ static String date2String(Date date, DateFormat dateFormat) { @@ -68,23 +67,21 @@ class UtilDate { } /** - * - * @param dateString string representing a Date to be conveted - * @return date Date after convertion - * + * @param dateString string representing a Date to be converted + * @return date Date after conversion + *

* Convert String date into Date */ static Date string2Date(String dateString) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.FRANCE); ParsePosition pos = new ParsePosition(0); - return dateFormat.parse(dateString,pos); + return dateFormat.parse(dateString, pos); } /** - * * @param date start date * @return int numbers of days between date and today - * + *

* Number of days between date (older than today) and today */ static int nbOfDaysBetweenDateAndToday(Date date) { diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 7cff479..1819058 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -22,9 +22,10 @@ Vue de détail Scanner un code barre de médicament Save - Toggle Flash - Enter cip 13 here.. + Allumez/Eteindre le Flash + Entrez le code CIP 13 ici… Enter CIP 13 Saisissez le code CIP13 avec le clavier Vous devez passer à la pharmacie - \ No newline at end of file + +