diff --git a/src/it/reyboz/bustorino/backend/DBStatusManager.java b/src/it/reyboz/bustorino/backend/DBStatusManager.java index 6eed4b5..127abc4 100644 --- a/src/it/reyboz/bustorino/backend/DBStatusManager.java +++ b/src/it/reyboz/bustorino/backend/DBStatusManager.java @@ -1,90 +1,90 @@ /* BusTO - Backend components Copyright (C) 2019 Fabio Mazza This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package it.reyboz.bustorino.backend; import android.content.Context; import android.content.SharedPreferences; import android.util.Log; import it.reyboz.bustorino.R; /** * Class to handle app status modifications, e.g. database is being updated or not */ public class DBStatusManager { private static String PREFERENCES_NAME;// = "it.reyboz.bustorino.statusPreferences"; private String DB_UPDATING; private SharedPreferences preferences; private SharedPreferences.OnSharedPreferenceChangeListener prefListener; private OnDBUpdateStatusChangeListener dbUpdateListener; public DBStatusManager(Context context, OnDBUpdateStatusChangeListener listener) { Context thecon = context.getApplicationContext(); this.preferences = thecon.getSharedPreferences(context.getString(R.string.mainSharedPreferences),Context.MODE_PRIVATE); DB_UPDATING = context.getString(R.string.databaseUpdatingPref); PREFERENCES_NAME = context.getString(R.string.mainSharedPreferences); dbUpdateListener = listener; //this.prefListeners = new ArrayList<>(); prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Log.d("BUSTO-PrefListener", "Changed key " + key + " in the sharedPref"); - if (key.equals(DB_UPDATING)) { + if (dbUpdateListener!=null && key.equals(DB_UPDATING)) { dbUpdateListener.onDBStatusChanged(sharedPreferences.getBoolean(DB_UPDATING, dbUpdateListener.defaultStatusValue())); } } }; } public boolean isDBUpdating(boolean defaultvalue){ if (preferences == null) //preferences = thecon.getSharedPreferences(PREFERENCES_NAME,Context.MODE_PRIVATE); { //This should NOT HAPPEN Log.e("BUSTO_Pref","Preference reference is null"); return false; } else { return preferences.getBoolean(DB_UPDATING,defaultvalue); } } public void registerListener(){ if(prefListener!=null) preferences.registerOnSharedPreferenceChangeListener(prefListener); } public void unregisterListener(){ if(prefListener!=null) preferences.unregisterOnSharedPreferenceChangeListener(prefListener); } public void setDbUpdating(boolean value){ final SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean(DB_UPDATING,value); editor.apply(); } public interface OnDBUpdateStatusChangeListener { void onDBStatusChanged(boolean updating); boolean defaultStatusValue(); } } diff --git a/src/it/reyboz/bustorino/middleware/DBUpdateWorker.java b/src/it/reyboz/bustorino/middleware/DBUpdateWorker.java index a6c5c1f..d1cbe59 100644 --- a/src/it/reyboz/bustorino/middleware/DBUpdateWorker.java +++ b/src/it/reyboz/bustorino/middleware/DBUpdateWorker.java @@ -1,137 +1,139 @@ package it.reyboz.bustorino.middleware; +import android.annotation.SuppressLint; import android.app.Notification; import android.content.Context; import android.content.SharedPreferences; import android.util.Log; import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.work.*; import it.reyboz.bustorino.R; import it.reyboz.bustorino.backend.Fetcher; import it.reyboz.bustorino.backend.Notifications; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static android.content.Context.MODE_PRIVATE; public class DBUpdateWorker extends Worker{ public static final String ERROR_CODE_KEY ="Error_Code"; public static final String ERROR_REASON_KEY = "ERROR_REASON"; public static final int ERROR_FETCHING_VERSION = 4; public static final int ERROR_DOWNLOADING_STOPS = 5; public static final int ERROR_DOWNLOADING_LINES = 6; public static final String SUCCESS_REASON_KEY = "SUCCESS_REASON"; public static final int SUCCESS_NO_ACTION_NEEDED = 9; public static final int SUCCESS_UPDATE_DONE = 1; private int notifi_ID=62341; public static final String FORCED_UPDATE = "FORCED-UPDATE"; public static final String DEBUG_TAG = "Busto-UpdateWorker"; public DBUpdateWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } + @SuppressLint("RestrictedApi") @NonNull @Override public Result doWork() { //register Notification channel final Context con = getApplicationContext(); Notifications.createDefaultNotificationChannel(con); final SharedPreferences shPr = con.getSharedPreferences(con.getString(R.string.mainSharedPreferences),MODE_PRIVATE); - final int current_DB_version = shPr.getInt(DatabaseUpdate.DB_VERSION_KEY,-1); + final int current_DB_version = shPr.getInt(DatabaseUpdate.DB_VERSION_KEY,-10); final int new_DB_version = DatabaseUpdate.getNewVersion(); final boolean isUpdateCompulsory = getInputData().getBoolean(FORCED_UPDATE,false); final int notificationID = showNotification(); Log.d(DEBUG_TAG, "Have previous version: "+current_DB_version +" and new version "+new_DB_version); Log.d(DEBUG_TAG, "Update compulsory: "+isUpdateCompulsory); if (new_DB_version < 0){ //there has been an error final Data out = new Data.Builder().putInt(ERROR_REASON_KEY, ERROR_FETCHING_VERSION) .putInt(ERROR_CODE_KEY,new_DB_version).build(); cancelNotification(notificationID); return Result.failure(out); } //we got a good version if (current_DB_version >= new_DB_version && !isUpdateCompulsory) { //don't need to update cancelNotification(notificationID); return Result.success(new Data.Builder(). putInt(SUCCESS_REASON_KEY, SUCCESS_NO_ACTION_NEEDED).build()); } //start the real update AtomicReference resultAtomicReference = new AtomicReference<>(); DatabaseUpdate.setDBUpdatingFlag(con, shPr,true); final DatabaseUpdate.Result resultUpdate = DatabaseUpdate.performDBUpdate(con,resultAtomicReference); DatabaseUpdate.setDBUpdatingFlag(con, shPr,false); if (resultUpdate != DatabaseUpdate.Result.DONE){ Fetcher.result result = resultAtomicReference.get(); final Data.Builder dataBuilder = new Data.Builder(); switch (resultUpdate){ case ERROR_STOPS_DOWNLOAD: dataBuilder.put(ERROR_REASON_KEY, ERROR_DOWNLOADING_STOPS); break; case ERROR_LINES_DOWNLOAD: dataBuilder.put(ERROR_REASON_KEY, ERROR_DOWNLOADING_LINES); break; } cancelNotification(notificationID); return Result.failure(dataBuilder.build()); } Log.d(DEBUG_TAG, "Update finished successfully!"); //update the version in the shared preference final SharedPreferences.Editor editor = shPr.edit(); editor.putInt(DatabaseUpdate.DB_VERSION_KEY, new_DB_version); editor.apply(); cancelNotification(notificationID); return Result.success(new Data.Builder().putInt(SUCCESS_REASON_KEY, SUCCESS_UPDATE_DONE).build()); } public static Constraints getWorkConstraints(){ return new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresCharging(false).build(); } public static WorkRequest newFirstTimeWorkRequest(){ return new OneTimeWorkRequest.Builder(DBUpdateWorker.class) .setBackoffCriteria(BackoffPolicy.LINEAR, 15, TimeUnit.SECONDS) //.setInputData(new Data.Builder().putBoolean()) .build(); } private int showNotification(){ final NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), Notifications.DEFAULT_CHANNEL_ID) .setContentTitle("Libre BusTO - Updating Database") .setProgress(0,0,true) .setPriority(NotificationCompat.PRIORITY_LOW); builder.setSmallIcon(R.drawable.ic_star_filled); final NotificationManagerCompat notifcManager = NotificationManagerCompat.from(getApplicationContext()); final int notification_ID = 32198; notifcManager.notify(notification_ID,builder.build()); return notification_ID; } private void cancelNotification(int notificationID){ final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext()); notificationManager.cancel(notificationID); } } diff --git a/src/it/reyboz/bustorino/middleware/GeneralActivity.java b/src/it/reyboz/bustorino/middleware/GeneralActivity.java index 7a2381d..b6cc81c 100644 --- a/src/it/reyboz/bustorino/middleware/GeneralActivity.java +++ b/src/it/reyboz/bustorino/middleware/GeneralActivity.java @@ -1,131 +1,135 @@ package it.reyboz.bustorino.middleware; import android.Manifest; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.NetworkInfo; import com.google.android.material.snackbar.Snackbar; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; import java.util.HashMap; import it.reyboz.bustorino.R; /** * Activity class that contains all the generally useful methods */ public abstract class GeneralActivity extends AppCompatActivity { final static protected int PERMISSION_REQUEST_POSITION = 33; final static protected String LOCATION_PERMISSION_GIVEN = "loc_permission"; final static protected int STORAGE_PERMISSION_REQ = 291; final static protected int PERMISSION_OK = 0; final static protected int PERMISSION_ASKING = 11; final static protected int PERMISSION_NEG_CANNOT_ASK = -3; final static private String DEBUG_TAG = "BusTO-GeneralAct"; /* * Permission stuff */ protected HashMap permissionDoneRunnables = new HashMap<>(); protected HashMap permissionAsked = new HashMap<>(); protected void setOption(String optionName, boolean value) { SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit(); editor.putBoolean(optionName, value); editor.commit(); } protected boolean getOption(String optionName, boolean optDefault) { SharedPreferences preferences = getPreferences(MODE_PRIVATE); return preferences.getBoolean(optionName, optDefault); } + + protected SharedPreferences getMainSharedPreferences(){ + return getSharedPreferences(getString(R.string.mainSharedPreferences),MODE_PRIVATE); + } public void hideKeyboard() { View view = getCurrentFocus(); if (view != null) { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } public boolean isConnected() { ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected(); } public void showToastMessage(int messageID, boolean short_lenght) { final int length = short_lenght ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG; Toast.makeText(getApplicationContext(), messageID, length).show(); } public void assertLocationPermissions() { if(ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_POSITION); } } public int askForPermissionIfNeeded(String permission, int requestID){ if(ContextCompat.checkSelfPermission(getApplicationContext(),permission)==PackageManager.PERMISSION_GRANTED){ return PERMISSION_OK; } //need to ask for the permission //consider scenario when we have already asked for permission boolean alreadyAsked = false; Integer num_trials = 0; synchronized (this){ if (permissionAsked.containsKey(permission)){ num_trials = permissionAsked.get(permission); if (num_trials != null && num_trials > 3) alreadyAsked = true; } } Log.d(DEBUG_TAG,"Already asked for permission: "+permission+" -> "+num_trials); if(!alreadyAsked){ ActivityCompat.requestPermissions(this,new String[]{permission}, requestID); synchronized (this){ if (num_trials!=null){ permissionAsked.put(permission, num_trials+1); } } return PERMISSION_ASKING; } else { return PERMISSION_NEG_CANNOT_ASK; } } public void createSnackbar(int ViewID, String message,int duration){ Snackbar.make(findViewById(ViewID),message,duration); } /* METHOD THAT MIGHT BE USEFUL LATER public void assertPermissions(String[] permissions){ ArrayList permissionstoRequest = new ArrayList<>(); for(int i=0;i