diff --git a/.idea/misc.xml b/.idea/misc.xml index dc44dda..b0c7b20 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -29,7 +29,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index 42fbd3d..6bd997a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { applicationId "com.uam.wmi.findmytutor" minSdkVersion 22 targetSdkVersion 27 - versionCode 58 + versionCode 66 versionName "1.0.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -75,4 +75,6 @@ dependencies { // spinner loaders library implementation 'com.github.ybq:Android-SpinKit:1.2.0' + // rx binding + implementation 'com.jakewharton.rxbinding:rxbinding:0.3.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 60022b5..9f3de6a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,7 +13,6 @@ - diff --git a/app/src/main/java/com/uam/wmi/findmytutor/FindMyTutor.java b/app/src/main/java/com/uam/wmi/findmytutor/FindMyTutor.java index 3c2eabf..2df6238 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/FindMyTutor.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/FindMyTutor.java @@ -6,8 +6,9 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import com.uam.wmi.findmytutor.utils.Const; +import com.uam.wmi.findmytutor.utils.MapUtils; +import com.uam.wmi.findmytutor.utils.PrefUtils; -import static org.acra.ReportField.*; import org.acra.ACRA; import org.acra.annotation.AcraLimiter; import org.acra.annotation.AcraNotification; @@ -16,18 +17,32 @@ import org.acra.config.HttpSenderConfigurationBuilder; import org.acra.config.ToastConfigurationBuilder; import org.acra.data.StringFormat; import org.acra.sender.HttpSender; + import java.util.HashMap; import java.util.Map; +import static org.acra.ReportField.ANDROID_VERSION; +import static org.acra.ReportField.BUILD_CONFIG; +import static org.acra.ReportField.CUSTOM_DATA; +import static org.acra.ReportField.LOGCAT; +import static org.acra.ReportField.PHONE_MODEL; +import static org.acra.ReportField.REPORT_ID; +import static org.acra.ReportField.SHARED_PREFERENCES; +import static org.acra.ReportField.STACK_TRACE; +import static org.acra.ReportField.USER_APP_START_DATE; +import static org.acra.ReportField.USER_CRASH_DATE; + @AcraNotification(resText = R.string.notification_text, resTitle = R.string.notification_title, resChannelName = R.string.notification_channel) @AcraLimiter(failedReportLimit = 2) public class FindMyTutor extends Application { + @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); + //super.attachBaseContext(LocaleHelper.onAttach(base)); // ACRA core CoreConfigurationBuilder builder = new CoreConfigurationBuilder(this) @@ -43,16 +58,17 @@ public class FindMyTutor extends Application { ToastConfigurationBuilder.class ).setResText(R.string.acra_toast_text); + SharedPreferences sharedPreferences = base.getSharedPreferences("com.uam.wmi.findmytutor_preferences", Context.MODE_PRIVATE); Map header = new HashMap(); String token = sharedPreferences.getString("API_KEY", "KEY_EMPTY"); - header.put("Authorization","Bearer " + token); + header.put("Authorization", "Bearer " + token); // Api POST builder.getPluginConfigurationBuilder( HttpSenderConfigurationBuilder.class // ).setUri("http://192.168.0.15:3000/api/acra") - ).setUri(Const.BASE_URL +"api/Feedback/autoFeedback") + ).setUri(Const.BASE_URL + "api/Feedback/autoFeedback") .setHttpMethod(HttpSender.Method.POST) .setHttpHeaders(header) .setEnabled(true); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java index ab0acf7..19a6dac 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java @@ -38,6 +38,7 @@ import com.uam.wmi.findmytutor.utils.ActiveFragment; import com.uam.wmi.findmytutor.utils.FeedbackUtils; import com.uam.wmi.findmytutor.utils.LocaleHelper; import com.uam.wmi.findmytutor.utils.LocaleUtils; +import com.uam.wmi.findmytutor.utils.MapUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RxSearchObservable; @@ -126,17 +127,9 @@ public abstract class BaseActivity if(PrefUtils.isBackgroundLocationServiceRunning(getApplicationContext())) { stopBackgroundLocalizationTask(); } + logout(); - storeBackgroundLocationStatus(getApplication(), false); - PrefUtils.storeIsLoggedIn(getApplicationContext(), false); - Intent i = getBaseContext().getPackageManager() - .getLaunchIntentForPackage(getBaseContext().getPackageName()); - if (i != null) { - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - } - startActivity(i); - finish(); } else if (itemName.equals(getResources().getString(R.string.navigation_item_feedback))) { feedbackUtils.showNoteDialog("FEEDBACK"); @@ -165,6 +158,21 @@ public abstract class BaseActivity } } + + protected void logout(){ + storeBackgroundLocationStatus(getApplication(), false); + PrefUtils.storeIsLoggedIn(getApplicationContext(), false); + PrefUtils.setBatteryExlusionInfoStatus(getApplicationContext(), true); + + Intent i = getBaseContext().getPackageManager() + .getLaunchIntentForPackage(getBaseContext().getPackageName()); + if (i != null) { + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + } + startActivity(i); + finish(); + } + protected void checkPermissions() { final List missingPermissions = new ArrayList(); @@ -419,7 +427,7 @@ public abstract class BaseActivity sharingFragment = SharingFragment.newInstance(); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.activity_content, sharingFragment); - ft.addToBackStack(null); + //ft.addToBackStack(null); ft.commit(); } @@ -429,7 +437,7 @@ public abstract class BaseActivity userListFragment = UsersListFragment.newInstance(); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.activity_content, userListFragment); - ft.addToBackStack(null); + //ft.addToBackStack(null); ft.commit(); } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java index 91cc203..5e833d7 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java @@ -68,6 +68,7 @@ import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.observers.DisposableObserver; import io.reactivex.observers.DisposableSingleObserver; @@ -153,7 +154,6 @@ public class BlackList extends AppCompatActivity { })); addToBlackListFab.setOnClickListener(this::showFabDialog); - handleSwitch(); } @@ -173,34 +173,29 @@ public class BlackList extends AppCompatActivity { } private void fetchBlackListedUsers() { - prevSize = blacklistedUsers.size(); - blacklistedUsers.clear(); - disposable.add(getListOfBlacklistedUsers(tutorId) - .doOnSubscribe(t -> didFetched = false) + .doOnSubscribe(this::handleDoOnSubscribe) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .flatMap((Function, Observable>) Observable::fromIterable) - .flatMap((Function>) this::getUserObservable) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(User user) { - blacklistedUsers.add(user); - } + .flatMap(Observable::fromIterable) + .flatMap(this::getUserObservable) + .subscribe(user -> blacklistedUsers.add(user), this::handleError,this::handleComplete)); + } - @Override - public void onError(Throwable e) { - showError(e); - didFetched = false; - } + private void handleDoOnSubscribe(Disposable disposable) { + prevSize = blacklistedUsers.size(); + blacklistedUsers.clear(); + didFetched = false; + } - @Override - public void onComplete() { - Collections.sort(blacklistedUsers, (a, b) -> sortByUserName(a,b)); - didFetched = true; - refreshUI(); - } - })); + private void handleComplete() { + Collections.sort(blacklistedUsers, this::sortByUserName); + didFetched = true; + refreshUI(); + } + private void handleError(Throwable e){ + showError(e); + didFetched = false; } private void refreshUI(){ @@ -262,10 +257,8 @@ public class BlackList extends AppCompatActivity { ); } - private void handleAddUser(User user) { Toast.makeText(this, R.string.add_user_to_list, Snackbar.LENGTH_LONG).show(); - blacklistedUsers.clear(); fetchBlackListedUsers(); } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java index d865b1c..d49dc60 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java @@ -3,7 +3,6 @@ package com.uam.wmi.findmytutor.activity; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; @@ -28,7 +27,7 @@ import com.uam.wmi.findmytutor.model.ValidateUser; import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.service.LdapService; import com.uam.wmi.findmytutor.service.UserService; -import com.uam.wmi.findmytutor.utils.LocaleHelper; +import com.uam.wmi.findmytutor.utils.MapUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RestApiHelper; @@ -41,8 +40,7 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; -public class -LoginActivity extends AppCompatActivity { +public class LoginActivity extends AppCompatActivity { private AutoCompleteTextView mLoginNameView; private EditText mPasswordView; @@ -52,11 +50,6 @@ LoginActivity extends AppCompatActivity { private UserService userService; private CompositeDisposable disposable = new CompositeDisposable(); - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleHelper.onAttach(base)); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -157,9 +150,9 @@ LoginActivity extends AppCompatActivity { private void loginProcess(String email, String password) { ValidateUser user = new ValidateUser(email, password); - // LdapUser fakeUser = new LdapUser(email, password,"wmi","tutor",email,"Fałszywy",email); + // LdapUser fakeUser = new LdapUser(email, password,"wmi","tutor",email,"Fałszywy",email); disposable.add(ldapService.validate(user) - //disposable.add(ldapService.fakeValidate(fakeUser) + //disposable.add(ldapService.fakeValidate(fakeUser) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::handleResponse, this::handleError)); @@ -198,6 +191,7 @@ LoginActivity extends AppCompatActivity { getUserProfile(userId.asString()); + Intent data = new Intent(); String txt = "Main Activity"; data.setData(Uri.parse(txt)); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java index b9ab207..7746779 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java @@ -127,6 +127,7 @@ public class MapActivity extends BaseActivity mStatusChecker = () -> { try { if (shouldFetchNewCoords) { + checkIfUsesCanBeTutor(); fetchTopCoords(); } } finally { @@ -145,7 +146,11 @@ public class MapActivity extends BaseActivity handleBackgroundTaskLifeCycle(); manualLocationUtils = new ManualLocationUtils(MapActivity.this); approximatedLocalization = new ApproximatedLocalization(MapUtils.loadJsonFromAsset(getApplicationContext(), "building.geojson")); - MapUtils.BatteryOptimizationsExceptionCheck(this); + + if(isTutor){ + MapUtils.BatteryOptimizationsExceptionCheck(this); + } + } @Override @@ -404,6 +409,30 @@ Log.e("LOCALE",PrefUtils.getLocale(getApplicationContext())); PrefUtils.putCurrentManualLocation(getApplicationContext(), resp.getPredefinedCoordinateId()); } + + private void checkIfUsesCanBeTutor(){ + disposable.add( + userService.getSelf(myId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableSingleObserver() { + @Override + public void onSuccess(User user) { + boolean tutorFromBackend = user.getTitle().equals("tutor"); + + if(tutorFromBackend != PrefUtils.getIsTutor(getApplicationContext())){ + logout(); + } + } + + @Override + public void onError(Throwable e) { + showError(e); + } + })); + + } + private void fetchTopCoords() { disposable.add( diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java index da66372..878b5b1 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java @@ -155,7 +155,6 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere public void onError(Throwable e) { Toast.makeText(getApplicationContext(), R.string.error_location_fetch, Toast.LENGTH_SHORT).show(); } - })); } @@ -250,7 +249,6 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere return true; }); - /** Button 'choose from map' button listener **/ manualLocationButton.setOnPreferenceChangeListener((preference, o) -> { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java index e988305..855f0cb 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java @@ -23,6 +23,7 @@ import android.widget.Toast; import com.uam.wmi.findmytutor.R; import com.uam.wmi.findmytutor.utils.LocaleHelper; +import com.uam.wmi.findmytutor.utils.MapUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; import java.util.Locale; @@ -31,6 +32,11 @@ public class StartupActivity extends AppCompatActivity { private static final int AUTHENTICATION_REQUEST_CODE = 666; String currentLang; + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(LocaleHelper.onAttach(base)); + } + @Override protected void onCreate(Bundle savedInstanceState) { @@ -43,8 +49,8 @@ public class StartupActivity extends AppCompatActivity { finish(); } else { Intent loginIntent = new Intent(this, LoginActivity.class); -// Intent loginIntent = new Intent(this, ScrollingActivity.class); startActivityForResult(loginIntent, AUTHENTICATION_REQUEST_CODE); + } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java index 73034da..7ab81f7 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java @@ -66,28 +66,6 @@ public class TutorTab extends AppCompatActivity { private RecyclerView.LayoutManager dutyHoursLayoutManager; private TutorTabViewModel newTab; - - - public boolean isEmailValid(String email) - { - String regExpn = - "^(([\\w-]+\\.)+[\\w-]+|([a-zA-Z]{1}|[\\w-]{2,}))@" - +"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" - +"[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\." - +"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" - +"[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|" - +"([a-zA-Z]+[\\w-]+\\.)+[a-zA-Z]{2,4})$"; - - CharSequence inputStr = email; - - Pattern pattern = Pattern.compile(regExpn,Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher(inputStr); - - if(matcher.matches()) - return true; - else - return false; - } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -118,8 +96,6 @@ public class TutorTab extends AppCompatActivity { getTutorTab(); -// findViewById(R.id.contentTutorTabInfoImageButton).setOnClickListener(v-> InfoHelperUtils.infoPopUp(v,R.layout.info_popup_tutor_tab)); - userName.setText(String.format("%s %s", PrefUtils.getUserFirstName(getApplicationContext()), PrefUtils.getUserLastName(getApplicationContext()))); disposable.add( @@ -236,7 +212,6 @@ public class TutorTab extends AppCompatActivity { }else{ userEmail.setError(getString(R.string.error_invalid_email)); } - }); } @@ -286,7 +261,6 @@ public class TutorTab extends AppCompatActivity { Toast.makeText(getApplicationContext(), "Network error " + error.getMessage(), Toast.LENGTH_SHORT).show(); - Log.e("WMI SUCC", String.valueOf(error)); } @@ -309,5 +283,21 @@ public class TutorTab extends AppCompatActivity { super.attachBaseContext(LocaleHelper.onAttach(base)); } + public boolean isEmailValid(String email) + { + String regExpn = + "^(([\\w-]+\\.)+[\\w-]+|([a-zA-Z]{1}|[\\w-]{2,}))@" + +"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" + +"[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\." + +"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" + +"[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|" + +"([a-zA-Z]+[\\w-]+\\.)+[a-zA-Z]{2,4})$"; + CharSequence inputStr = email; + + Pattern pattern = Pattern.compile(regExpn,Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(inputStr); + + return matcher.matches(); + } } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java index 7ecd1a3..ea2bbd2 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java @@ -66,6 +66,7 @@ import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.observers.DisposableObserver; import io.reactivex.observers.DisposableSingleObserver; @@ -321,6 +322,7 @@ public class UsersListFragment extends Fragment { tutorsList.addAll(users); mAdapter.notifyDataSetChanged(); toggleEmptyNotes(); + fetchTopCords(); } @Override @@ -438,6 +440,35 @@ public class UsersListFragment extends Fragment { } } + + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + private void fetchTopCords(){ + disposable.add( + coordinateService.getTopCoordinates() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::addTimestamps,this::showError)); + } + + private void addTimestamps(List coordinates) { + for (Coordinate crd : + coordinates) { + Long ts = crd.getTimeStamp(); + tutorsTimeStamps.put(crd.getUserId(), getDate(ts)); + } + + mAdapter.notifyDataSetChanged(); + } + + private String getDate(long time) { + Calendar cal = Calendar.getInstance(Locale.ENGLISH); + cal.setTimeInMillis(time); + return DateFormat.format("HH:mm dd/MM", cal).toString(); + } + @Override public void onDestroy() { super.onDestroy(); @@ -460,54 +491,4 @@ public class UsersListFragment extends Fragment { super.onStop(); } - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - } - - private Observable> getListOfActiveUsers() { - return userService.getAllActiveTutors() - .toObservable() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - } - - private Observable getCoordinateObservable(User user) { - return coordinateService - .getTopCoordinateByUserId(user.getId()) - .toObservable() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - } - - private void fetchTopCords(){ - tutorsTimeStamps.clear(); - disposable.add(getListOfActiveUsers() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .flatMap((Function, Observable>) Observable::fromIterable) - .flatMap((Function>) this::getCoordinateObservable) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(Coordinate coordinate) { - Long ts = coordinate.getTimeStamp(); - tutorsTimeStamps.put(coordinate.getUserId(), getDate(ts)); - } - - @Override - public void onError(Throwable e) {showError(e);} - - @Override - public void onComplete() { - Log.e("USERS", String.valueOf(tutorsTimeStamps)); - mAdapter.notifyDataSetChanged(); - } - })); - } - - private String getDate(long time) { - Calendar cal = Calendar.getInstance(Locale.ENGLISH); - cal.setTimeInMillis(time); - String date = DateFormat.format("HH:mm dd/MM", cal).toString(); - return date; - } } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java index 485b8f0..7490af9 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java @@ -58,6 +58,7 @@ import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; @@ -162,34 +163,29 @@ public class WhiteList extends AppCompatActivity { } private void fetchWhiteListedUsers() { - prevSize = whitelistedUsers.size(); - whitelistedUsers.clear(); - disposable.add(getListOfWhitelistedUsers(tutorId) - .doOnSubscribe(t -> didFetched = false) + .doOnSubscribe(this::handleDoOnSubscribe) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .flatMap((Function, Observable>) Observable::fromIterable) - .flatMap((Function>) this::getUserObservable) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(User user) { - whitelistedUsers.add(user); - } + .flatMap(Observable::fromIterable) + .flatMap(this::getUserObservable) + .subscribe(user -> whitelistedUsers.add(user), this::handleError,this::handleComplete)); + } - @Override - public void onError(Throwable e) { - showError(e); - didFetched = false; - } + private void handleDoOnSubscribe(Disposable disposable) { + prevSize = whitelistedUsers.size(); + whitelistedUsers.clear(); + didFetched = false; + } - @Override - public void onComplete() { - Collections.sort(whitelistedUsers, (a, b) -> sortByUserName(a, b)); - didFetched = true; - refreshUI(); - } - })); + private void handleComplete() { + Collections.sort(whitelistedUsers, this::sortByUserName); + didFetched = true; + refreshUI(); + } + private void handleError(Throwable e){ + showError(e); + didFetched = false; } private void refreshUI() { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/adapters/TutorsListAdapter.java b/app/src/main/java/com/uam/wmi/findmytutor/adapters/TutorsListAdapter.java index 2a147c8..cda7aec 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/adapters/TutorsListAdapter.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/adapters/TutorsListAdapter.java @@ -1,3 +1,4 @@ +/* package com.uam.wmi.findmytutor.adapters; import android.content.Context; @@ -46,6 +47,7 @@ public class TutorsListAdapter extends RecyclerView.Adapter { + + private Context context; + private List tutorsList; + private HashMap tutorsTimeStamps; + + public TutorsListAdapter(Context context, List tutors, HashMap tutorsTimeStamps) { + this.context = context; + this.tutorsList = tutors; + this.tutorsTimeStamps = tutorsTimeStamps; + } + @NonNull + @Override + public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.tutor_list_row, parent, false); + + return new MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { + Drawable image = null; + User tutor = tutorsList.get(position); + + holder.firstName.setText(String.format("%s %s", tutor.getFirstName(), tutor.getLastName())); + String ts = tutorsTimeStamps.get(tutor.getId()); + + if (tutor.isIsOnline()) { + image = context.getResources().getDrawable(R.drawable.user_list_online); + holder.lastSeen.setText(R.string.available_now); + holder.lastSeen.setVisibility(View.VISIBLE); + holder.loader.setVisibility(View.GONE); + } else if(tutor.isIsActive()){ + image = context.getResources().getDrawable(R.drawable.user_list_offline); + + if (ts != null){ + holder.lastSeen.setText(R.string.last_sign); + holder.lastSeen.append(String.format(": %s", ts)); + holder.loader.setVisibility(View.GONE); + } + } else { + image = context.getResources().getDrawable(R.drawable.user_list_off); + + if(ts == null){ + holder.lastSeen.setText(R.string.never_logged_in); + }else{ + holder.lastSeen.setText(R.string.last_sign); + holder.lastSeen.append(String.format(": %s", ts)); + } holder.loader.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java index ad6a5f0..a374c44 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java @@ -34,9 +34,11 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.uam.wmi.findmytutor.model.Coordinate; import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.utils.ApproximatedLocalization; +import com.uam.wmi.findmytutor.utils.Const; import com.uam.wmi.findmytutor.utils.MapUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.SharingLevel; +import com.uam.wmi.findmytutor.utils.WifiUtils; import org.apache.commons.collections4.queue.CircularFifoQueue; @@ -122,6 +124,12 @@ public class BackgroundLocalizationService extends Service { mCurrentLocation = locationResult.getLastLocation(); sendCoordinateToBackend(mCurrentLocation); changeBackgroundMode(); + + //Restart service when a user started using presence in GPS mode and wmi is currently available + if (WifiUtils.checkIfUserIsInRangeOfWmiWifi(getApplicationContext()) + && PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.PRESENCE.toString())) { + restartService(); + } } } }; @@ -140,22 +148,60 @@ public class BackgroundLocalizationService extends Service { startForeground(1001, notification); } - if (!stopService && !PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { - createFusedLocationClient(); - } else if (!stopService && - PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { - mStatusChecker = () -> { - try { - sendCoordinateToBackend(fakeLoc); - } finally { - mHandler.postDelayed(mStatusChecker, notify_interval); - } - }; + if (!stopService) { + if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.PRESENCE.toString())) { + if (WifiUtils.checkIfUserIsInRangeOfWmiWifi(getApplicationContext())) { + Location presenceFakeLoc = new Location(""); - AsyncTask.execute(mStatusChecker); + presenceFakeLoc.setLatitude(Const.presenceLatitude); + presenceFakeLoc.setLongitude(Const.presenceLongitude); + presenceFakeLoc.setAltitude(0); + createPresenceLooper(presenceFakeLoc); + } else { + createFusedLocationClient(); + } + } else if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.EXACT.toString()) + || PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.APPROXIMATED.toString()) + ) { + createFusedLocationClient(); + } else if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { + Location manualFakeLoc = new Location(""); + + manualFakeLoc.setLatitude(0); + manualFakeLoc.setLongitude(0); + manualFakeLoc.setAltitude(0); + createLowBatteryLooper(manualFakeLoc); + } } } + private void createLowBatteryLooper(Location fakeLoc) { + mStatusChecker = () -> { + try { + sendCoordinateToBackend(fakeLoc); + } finally { + mHandler.postDelayed(mStatusChecker, notify_interval); + } + }; + AsyncTask.execute(mStatusChecker); + } + + private void createPresenceLooper(Location fakeLoc) { + mStatusChecker = () -> { + try { + if (WifiUtils.checkIfUserIsInRangeOfWmiWifi(getApplicationContext())) { + sendCoordinateToBackend(fakeLoc); + } else { + restartService(); + } + } finally { + mHandler.postDelayed(mStatusChecker, notify_interval); + } + }; + AsyncTask.execute(mStatusChecker); + } + + private void createFusedLocationClient() { Integer saveMode = Long.valueOf(notify_interval).compareTo(Long.valueOf(offlineBackgroundLocationInterval)); @@ -294,7 +340,7 @@ public class BackgroundLocalizationService extends Service { latitude = location.getLatitude(); longitude = location.getLongitude(); altitude = location.getAltitude(); - Log.e(TAG,"TASK" + latitude + " " + longitude); + Log.e(TAG, "TASK" + latitude + " " + longitude); approximatedLocalization = new ApproximatedLocalization(MapUtils.loadJsonFromAsset(getApplicationContext(), "building.geojson")); approximatedBuildingPart = approximatedLocalization.getNameOfBuildingPart(Point.fromLngLat(longitude, latitude)); } @@ -307,6 +353,7 @@ public class BackgroundLocalizationService extends Service { if (locationLevel.equals(SharingLevel.PRESENCE.toString())) { if (!MapUtils.checkIfCoordinateIsValid(latitude, longitude)) { + coordinatesHistory.add(fakeLoc); return null; } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java index f4092b4..afe0b2c 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java @@ -39,6 +39,9 @@ public interface UserService { @GET("api/users/tutors/active") Single > getAllActiveTutors(); + + + @GET("api/users/tutors/offline") Single > getAllOfflineTutors(); @@ -60,6 +63,9 @@ public interface UserService { @GET("api/users/{id}") Single getUserById(@Path("id") String userID); + @GET("api/users/self/{id}") + Single getSelf(@Path("id") String userID); + @PUT("api/users/{id}") Completable updateUserByID(@Path("id") String userID, @Body User user); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java index f7aaacf..cf4abe9 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java @@ -20,5 +20,7 @@ public class Const { public final static Range outsideLatitudeRange = Range.create(52.4651, 52.468837); public final static Range outsideLongitudeRange = Range.create(16.9186, 16.936004); public final static List validApproximatedLocations = Arrays.asList("Skrzydło B", "Skrzydło A", "Aule", "Łącznik", "Biblioteka", "Hol", "Unknown"); + public final static String WMI_SSID_NAME = "wmi"; } + diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/MapUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/MapUtils.java index 200da07..f44ee42 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/MapUtils.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/MapUtils.java @@ -3,12 +3,9 @@ package com.uam.wmi.findmytutor.utils; import android.animation.TypeEvaluator; import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.location.Location; import android.net.Uri; -import android.os.Build; -import android.os.PowerManager; import android.provider.Settings; import com.mapbox.mapboxsdk.camera.CameraPosition; @@ -25,6 +22,7 @@ import java.io.InputStream; import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; import static com.uam.wmi.findmytutor.utils.Const.outsideLatitudeRange; import static com.uam.wmi.findmytutor.utils.Const.outsideLongitudeRange; +import static com.uam.wmi.findmytutor.utils.PrefUtils.shouldBatteryExclusionBeShown; public class MapUtils { @@ -90,6 +88,26 @@ public class MapUtils { return Const.buildingLatitudeRange.contains(latitude) && Const.buildingLongitudeRange.contains(longitude); } + public static void BatteryOptimizationsExceptionCheck(Context context) { + if (shouldBatteryExclusionBeShown(getApplicationContext())) { + PrefUtils.setBatteryExlusionInfoStatus(getApplicationContext(), false); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.batter_exclusions_title); + builder.setMessage(R.string.batter_exclusions_message) + .setPositiveButton(R.string.ok, (dialog, id) -> { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", getApplicationContext().getPackageName(), null); + intent.setData(uri); + context.startActivity(intent); + }) + .setNegativeButton(R.string.cancel, (dialog, id) -> { + + }).show(); + } + } + // Function for marker animation public static class LatLngEvaluator implements TypeEvaluator { // Method is used to interpolate the marker animation. @@ -106,28 +124,4 @@ public class MapUtils { } } - public static void BatteryOptimizationsExceptionCheck(Context context) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (!pm.isIgnoringBatteryOptimizations(context.getPackageName())) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.batter_exclusions_title); - builder.setMessage(R.string.batter_exclusions_message) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Intent intent = new Intent(); - intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); - intent.setData(Uri.parse("package:" + getApplicationContext().getPackageName())); - context.startActivity(intent); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User cancelled the dialog - } - }).show(); - } - } - } - } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java index 2ae7c57..131227c 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java @@ -243,4 +243,13 @@ public class PrefUtils { return getSharedPreferences(context).getBoolean("whitelisting", false); } + public static Boolean shouldBatteryExclusionBeShown(Context context) { + return getSharedPreferences(context).getBoolean("show_battery_exclusion", false); + } + + public static void setBatteryExlusionInfoStatus(Context context, Boolean flag) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("show_battery_exclusion", flag); + editor.apply(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/WifiUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/WifiUtils.java new file mode 100644 index 0000000..ae02ba6 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/WifiUtils.java @@ -0,0 +1,30 @@ +package com.uam.wmi.findmytutor.utils; + +import android.content.Context; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.util.Log; + +import java.util.Objects; + +public class WifiUtils { + + public static String getWifiName(Context context) { + WifiManager manager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (Objects.requireNonNull(manager).isWifiEnabled()) { + WifiInfo wifiInfo = manager.getConnectionInfo(); + if (wifiInfo != null) { + NetworkInfo.DetailedState state = WifiInfo.getDetailedStateOf(wifiInfo.getSupplicantState()); + if (state == NetworkInfo.DetailedState.CONNECTED || state == NetworkInfo.DetailedState.OBTAINING_IPADDR) { + return wifiInfo.getSSID(); + } + } + } + return null; + } + + public static Boolean checkIfUserIsInRangeOfWmiWifi(Context context) { + return Objects.equals(getWifiName(context), Const.WMI_SSID_NAME); + } +} diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index a96ee0c..b192e97 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -4,13 +4,13 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:fontFamily="@font/lato_regular" android:gravity="center_horizontal" android:orientation="vertical" - android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" - android:fontFamily="@font/lato_regular" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".activity.LoginActivity"> @@ -61,10 +61,7 @@ app:passwordToggleEnabled="true" android:layout_height="wrap_content"> - - - - -