From acbe0fe6b9bcb9523323795b70623f43e5f13089 Mon Sep 17 00:00:00 2001 From: muthash Date: Thu, 14 Mar 2019 12:44:05 +0300 Subject: [PATCH 1/2] feat(Cache daily logs): Daily logs should be temporarily cached for a day - checkin/checkout an asset - cache logs for at least 24 hours --- app/build.gradle | 8 +++ .../com.andela.art.room.ArtDatabase/1.json | 45 ++++++++++++ .../andela/art/checkin/CheckInActivity.java | 27 ++++++- .../main/java/com/andela/art/room/ArtDao.java | 22 ++++++ .../java/com/andela/art/room/ArtDatabase.java | 38 ++++++++++ .../com/andela/art/room/CheckInEntity.java | 70 +++++++++++++++++++ .../andela/art/room/CheckInRepository.java | 54 ++++++++++++++ 7 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 app/schemas/com.andela.art.room.ArtDatabase/1.json create mode 100644 app/src/main/java/com/andela/art/room/ArtDao.java create mode 100644 app/src/main/java/com/andela/art/room/ArtDatabase.java create mode 100644 app/src/main/java/com/andela/art/room/CheckInEntity.java create mode 100644 app/src/main/java/com/andela/art/room/CheckInRepository.java diff --git a/app/build.gradle b/app/build.gradle index 56cbf02..1883a30 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,6 +19,11 @@ android { dataBinding { enabled true } + javaCompileOptions { + annotationProcessorOptions { + arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] + } + } } signingConfigs { release { @@ -132,6 +137,9 @@ dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.16.0' implementation 'com.android.support:cardview-v7:26.1.0' + + implementation "android.arch.persistence.room:runtime:1.1.1" + annotationProcessor "android.arch.persistence.room:compiler:1.1.1" } apply plugin: 'com.google.gms.google-services' diff --git a/app/schemas/com.andela.art.room.ArtDatabase/1.json b/app/schemas/com.andela.art.room.ArtDatabase/1.json new file mode 100644 index 0000000..eae7324 --- /dev/null +++ b/app/schemas/com.andela.art.room.ArtDatabase/1.json @@ -0,0 +1,45 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "c893151612dbb54edd1f763ed5e5060c", + "entities": [ + { + "tableName": "checkIn", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serialNumber` INTEGER NOT NULL, `logStatus` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serialNumber", + "columnName": "serialNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "logStatus", + "columnName": "logStatus", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c893151612dbb54edd1f763ed5e5060c\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/andela/art/checkin/CheckInActivity.java b/app/src/main/java/com/andela/art/checkin/CheckInActivity.java index d410704..93dd8dc 100644 --- a/app/src/main/java/com/andela/art/checkin/CheckInActivity.java +++ b/app/src/main/java/com/andela/art/checkin/CheckInActivity.java @@ -7,6 +7,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; +import android.widget.Toast; import com.andela.art.R; import com.andela.art.checkin.injection.CheckInModule; @@ -14,6 +15,8 @@ import com.andela.art.databinding.ActivityCheckInBinding; import com.andela.art.models.Asset; import com.andela.art.models.Asignee; +import com.andela.art.room.CheckInEntity; +import com.andela.art.room.CheckInRepository; import com.andela.art.root.ApplicationComponent; import com.andela.art.root.ApplicationModule; import com.andela.art.root.ArtApplication; @@ -36,6 +39,8 @@ public class CheckInActivity extends BaseMenuActivity implements CheckInView { Asignee user; Bundle bundle; private View mProgressView; + private CheckInRepository mRepository; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -152,7 +157,7 @@ public void initializeCheckInComponent() { } /** - * Call the check in method in presenter. + * Call the check in method in presenter and save status in DB. * * @param id - asset serial number * @param logType - check in status @@ -166,5 +171,25 @@ public void callCheckin(Integer id, String logType) { status = "Checkin"; } presenter.checkIn(id, status); + saveCheckIn(id, status); + } + + /** + * Save status in DB. + * + * @param id - asset serial number + * @param logType - check in status + */ + public void saveCheckIn(Integer id, String logType) { + CheckInEntity checkInEntity = new CheckInEntity(); + checkInEntity.setSerialNumber(id); + checkInEntity.setLogStatus(logType); + + mRepository = new CheckInRepository(getApplication()); + mRepository.insert(checkInEntity); + + Toast.makeText(getApplicationContext(), + "CheckIn data added to the database successfully", + Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/andela/art/room/ArtDao.java b/app/src/main/java/com/andela/art/room/ArtDao.java new file mode 100644 index 0000000..edce763 --- /dev/null +++ b/app/src/main/java/com/andela/art/room/ArtDao.java @@ -0,0 +1,22 @@ +package com.andela.art.room; + +import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Insert; +import android.arch.persistence.room.OnConflictStrategy; + + +/** + * The Room Magic is in this file, where you map a Java method call to an SQL query. + * Use @Insert(onConflict = OnConflictStrategy.REPLACE) to update a row. + */ + +@Dao +public interface ArtDao { + + /** + * Add items into the database. + * @param checkInEntity - CheckInEntity + */ + @Insert + void insertCheckIn(CheckInEntity checkInEntity); +} diff --git a/app/src/main/java/com/andela/art/room/ArtDatabase.java b/app/src/main/java/com/andela/art/room/ArtDatabase.java new file mode 100644 index 0000000..ee3f398 --- /dev/null +++ b/app/src/main/java/com/andela/art/room/ArtDatabase.java @@ -0,0 +1,38 @@ +package com.andela.art.room; + +import android.arch.persistence.room.Database; +import android.arch.persistence.room.Room; +import android.arch.persistence.room.RoomDatabase; +import android.content.Context; + +/** + * This is the backend. The Art database. This used to be done by the OpenHelper. + */ + +@Database(entities = {CheckInEntity.class}, version = 1) +public abstract class ArtDatabase extends RoomDatabase { + + private static volatile ArtDatabase instance; + + /** + * Data Access Object. + * @return transaction status + */ + public abstract ArtDao mArtDao(); + + /** + * Get database to ensure atomic access to the variable. + * @param context - Context + * @return instance - database instance + */ + static ArtDatabase getDatabase(final Context context) { + synchronized (ArtDatabase.class) { + if (instance == null) { + instance = Room.databaseBuilder(context.getApplicationContext(), + ArtDatabase.class, "artdb").build(); + } + } + return instance; + } + +} diff --git a/app/src/main/java/com/andela/art/room/CheckInEntity.java b/app/src/main/java/com/andela/art/room/CheckInEntity.java new file mode 100644 index 0000000..57e37bc --- /dev/null +++ b/app/src/main/java/com/andela/art/room/CheckInEntity.java @@ -0,0 +1,70 @@ +package com.andela.art.room; + +import android.arch.persistence.room.Entity; +import android.arch.persistence.room.PrimaryKey; + +/** + * A basic class representing an entity that is a row in a three-column database table. + * + * @ Entity - You must annotate the class as an entity and supply a table name if not class name. + * @ PrimaryKey - You must identify the primary key. + * + */ + +@Entity(tableName = "checkIn") +public class CheckInEntity { + @PrimaryKey(autoGenerate = true) + private int id; + + private int serialNumber; + + private String logStatus; + + /** + * Id status getter. + * @return id - int + */ + public int getId() { + return id; + } + + /** + * Id status setter. + * @param id - int + */ + public void setId(int id) { + this.id = id; + } + + /** + * SerialNumber status getter. + * @return serialNumber - int + */ + public int getSerialNumber() { + return serialNumber; + } + + /** + * SerialNumber status setter. + * @param serialNumber - int + */ + public void setSerialNumber(int serialNumber) { + this.serialNumber = serialNumber; + } + + /** + * Log status getter. + * @return logStatus - String + */ + public String getLogStatus() { + return logStatus; + } + + /** + * LogStatus status setter. + * @param logStatus - string + */ + public void setLogStatus(String logStatus) { + this.logStatus = logStatus; + } +} diff --git a/app/src/main/java/com/andela/art/room/CheckInRepository.java b/app/src/main/java/com/andela/art/room/CheckInRepository.java new file mode 100644 index 0000000..87914a3 --- /dev/null +++ b/app/src/main/java/com/andela/art/room/CheckInRepository.java @@ -0,0 +1,54 @@ +package com.andela.art.room; + +import android.app.Application; +import android.os.AsyncTask; + +/** + * Abstracted Repository as promoted by the Architecture Guide. + * https://developer.android.com/topic/libraries/architecture/guide.html + */ + +@SuppressWarnings("PMD.ImmutableField") +public class CheckInRepository { + private ArtDao mArtDao; + + /** + * Check in repository constructor. + * @param application - Application. + */ + public CheckInRepository(Application application) { + ArtDatabase db = ArtDatabase.getDatabase(application); + mArtDao = db.mArtDao(); + } + + /** + * You must call this on a non-UI thread or your app will crash. + * @param mCheckInEntity - CheckInEntity. + */ + public void insert(CheckInEntity mCheckInEntity) { + new InsertAsyncTask(mArtDao).execute(mCheckInEntity); + } + + /** + * non-UI thread to insert data into the DB. + */ + private static class InsertAsyncTask extends AsyncTask { + + private ArtDao mAsyncTaskDao; + + /** + * InsertAsyncTask constructor. + * @param dao - ArtDao. + */ + InsertAsyncTask(ArtDao dao) { + mAsyncTaskDao = dao; + } + + + @Override + protected Void doInBackground(CheckInEntity... checkInEntities) { + mAsyncTaskDao.insertCheckIn(checkInEntities[0]); + return null; + } + } +} From 6176328e7ed5d9b1ec348f308c8273c90368cce6 Mon Sep 17 00:00:00 2001 From: Kalela Date: Mon, 25 Mar 2019 13:06:11 +0300 Subject: [PATCH 2/2] feature(cache logs): Push checkin/checkout data in cache to the api - Push data to api when network is available [Delivers: 163817425] --- .../andela/art/checkin/CheckInActivity.java | 10 + .../main/java/com/andela/art/room/ArtDao.java | 19 +- .../andela/art/room/CheckInRepository.java | 52 ++++ .../res/layout/cached_activity_check_in.xml | 256 ++++++++++++++++++ 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/layout/cached_activity_check_in.xml diff --git a/app/src/main/java/com/andela/art/checkin/CheckInActivity.java b/app/src/main/java/com/andela/art/checkin/CheckInActivity.java index 93dd8dc..f816506 100644 --- a/app/src/main/java/com/andela/art/checkin/CheckInActivity.java +++ b/app/src/main/java/com/andela/art/checkin/CheckInActivity.java @@ -22,6 +22,7 @@ import com.andela.art.root.ArtApplication; import com.andela.art.root.BaseMenuActivity; import com.andela.art.securitydashboard.presentation.SecurityDashboardActivity; +import com.andela.art.utils.NetworkUtil; import com.squareup.picasso.Picasso; import java.util.Locale; import javax.inject.Inject; @@ -40,12 +41,19 @@ public class CheckInActivity extends BaseMenuActivity implements CheckInView { Bundle bundle; private View mProgressView; private CheckInRepository mRepository; + public NetworkUtil networkUtil = new NetworkUtil(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_check_in); + mRepository = new CheckInRepository(getApplication()); + if (!networkUtil.isNetworkAvailable(this)) { + //TODO: Should be different layout for offline devices + binding = DataBindingUtil.setContentView(this, R.layout.cached_activity_check_in); + } + mProgressView = findViewById(R.id.check_in_view_progressbar); applicationComponent = ((ArtApplication) getApplication()) .applicationComponent(); @@ -60,6 +68,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { setSupportActionBar(binding.checkInToolbar); binding.checkInToolbar.setTitleTextAppearance(this, R.style.CheckInTitle); presenter.attachView(this); + mRepository.setPresenter(presenter); + mRepository.query(); displayDetails(); } diff --git a/app/src/main/java/com/andela/art/room/ArtDao.java b/app/src/main/java/com/andela/art/room/ArtDao.java index edce763..8f724dd 100644 --- a/app/src/main/java/com/andela/art/room/ArtDao.java +++ b/app/src/main/java/com/andela/art/room/ArtDao.java @@ -1,8 +1,11 @@ package com.andela.art.room; import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Delete; import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; +import android.arch.persistence.room.Query; + +import java.util.List; /** @@ -19,4 +22,18 @@ public interface ArtDao { */ @Insert void insertCheckIn(CheckInEntity checkInEntity); + + /** + * Get checkin data. + * @return Return list of checkIn entities. + */ + @Query("SELECT * FROM checkIn") + List getAllCheckInData(); + + /** + * Delete all Check In Records. + * @param checkInEntity CheckInEntity + */ + @Delete + void deleteAllRecords(List checkInEntity); } diff --git a/app/src/main/java/com/andela/art/room/CheckInRepository.java b/app/src/main/java/com/andela/art/room/CheckInRepository.java index 87914a3..5085efd 100644 --- a/app/src/main/java/com/andela/art/room/CheckInRepository.java +++ b/app/src/main/java/com/andela/art/room/CheckInRepository.java @@ -3,6 +3,10 @@ import android.app.Application; import android.os.AsyncTask; +import com.andela.art.checkin.CheckInPresenter; + +import java.util.List; + /** * Abstracted Repository as promoted by the Architecture Guide. * https://developer.android.com/topic/libraries/architecture/guide.html @@ -11,6 +15,15 @@ @SuppressWarnings("PMD.ImmutableField") public class CheckInRepository { private ArtDao mArtDao; + private CheckInPresenter presenter; + + /** + * Set presenter value. + * @param presenter CheckinPresenter + */ + public void setPresenter(CheckInPresenter presenter) { + this.presenter = presenter; + } /** * Check in repository constructor. @@ -29,6 +42,13 @@ public void insert(CheckInEntity mCheckInEntity) { new InsertAsyncTask(mArtDao).execute(mCheckInEntity); } + /** + * + */ + public void query() { + new QueryAsyncTask(mArtDao).execute(); + } + /** * non-UI thread to insert data into the DB. */ @@ -51,4 +71,36 @@ protected Void doInBackground(CheckInEntity... checkInEntities) { return null; } } + + /** + * Non-UI thread to query data from the DB. + */ + private class QueryAsyncTask extends AsyncTask { + + private ArtDao mAsyncTaskDao; + + /** + * Constructor. + * @param mArtDao ArtDao. + */ + QueryAsyncTask(ArtDao mArtDao) { + mAsyncTaskDao = mArtDao; + } + + @Override + protected Void doInBackground(Void... voids) { + List checkInData = mAsyncTaskDao.getAllCheckInData(); + if (checkInData.isEmpty()) { + //Do nothing + return null; + } else { + presenter.checkIn(checkInData.get(0).getId(), //NOPMD + checkInData.get(0).getLogStatus()); //NOPMD + mAsyncTaskDao.deleteAllRecords(checkInData); + + } + return null; + } + } + } diff --git a/app/src/main/res/layout/cached_activity_check_in.xml b/app/src/main/res/layout/cached_activity_check_in.xml new file mode 100644 index 0000000..85b08c8 --- /dev/null +++ b/app/src/main/res/layout/cached_activity_check_in.xml @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +