2019-02-13 20:43:30 +01:00
/ * Copyright ( C ) 2015 - 2019 Andreas Shimokawa , Carsten Pfeiffer , Daniele
Gobbetti , Martin , Matthieu Baerts , Normano64 , Pavel Elagin , Taavi Eomäe
2017-03-10 14:53:19 +01:00
This file is part of Gadgetbridge .
Gadgetbridge is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Gadgetbridge 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 Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>. */
2015-05-01 09:36:10 +02:00
package nodomain.freeyourgadget.gadgetbridge ;
2016-05-20 21:49:25 +02:00
import android.annotation.TargetApi ;
2015-05-01 09:36:10 +02:00
import android.app.Application ;
2018-02-14 21:27:24 +01:00
import android.app.NotificationChannel ;
2016-05-19 23:58:13 +02:00
import android.app.NotificationManager ;
2016-05-19 16:34:59 +02:00
import android.app.NotificationManager.Policy ;
2018-05-16 19:03:06 +02:00
import android.bluetooth.BluetoothAdapter ;
2015-05-01 09:36:10 +02:00
import android.content.Context ;
2015-12-07 23:33:32 +01:00
import android.content.Intent ;
2018-05-16 19:03:06 +02:00
import android.content.IntentFilter ;
2015-05-23 00:45:12 +02:00
import android.content.SharedPreferences ;
2017-10-19 21:52:38 +02:00
import android.content.pm.ApplicationInfo ;
import android.content.pm.PackageInfo ;
import android.content.pm.PackageManager ;
2017-07-31 22:49:05 +02:00
import android.content.res.Configuration ;
2016-04-23 23:24:56 +02:00
import android.content.res.Resources ;
2016-05-19 16:34:59 +02:00
import android.database.Cursor ;
2016-05-13 23:47:47 +02:00
import android.database.sqlite.SQLiteDatabase ;
2016-05-19 16:34:59 +02:00
import android.net.Uri ;
2015-06-06 00:10:38 +02:00
import android.os.Build ;
import android.os.Build.VERSION ;
2015-05-23 00:45:12 +02:00
import android.preference.PreferenceManager ;
2016-05-19 16:34:59 +02:00
import android.provider.ContactsContract.PhoneLookup ;
2015-06-21 10:18:41 +02:00
import android.util.Log ;
2016-04-23 23:24:56 +02:00
import android.util.TypedValue ;
2015-05-23 00:45:12 +02:00
2015-05-13 23:15:20 +02:00
import java.io.File ;
2015-07-08 23:03:34 +02:00
import java.io.IOException ;
2015-09-25 00:53:40 +02:00
import java.util.HashSet ;
2016-11-24 21:11:28 +01:00
import java.util.List ;
2017-07-31 22:49:05 +02:00
import java.util.Locale ;
2017-04-22 16:59:55 +02:00
import java.util.Set ;
2015-08-03 01:17:02 +02:00
import java.util.concurrent.TimeUnit ;
import java.util.concurrent.locks.Lock ;
import java.util.concurrent.locks.ReentrantLock ;
2015-05-13 23:15:20 +02:00
2019-01-26 15:52:40 +01:00
import androidx.localbroadcastmanager.content.LocalBroadcastManager ;
2015-08-03 01:17:02 +02:00
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler ;
2016-08-27 22:51:00 +02:00
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper ;
2016-05-16 23:54:51 +02:00
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper ;
2016-06-18 23:35:34 +02:00
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager ;
2016-04-17 19:52:51 +02:00
import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster ;
2018-05-16 19:03:06 +02:00
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothStateChangeReceiver ;
2016-11-24 21:11:28 +01:00
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice ;
2015-08-21 00:58:18 +02:00
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService ;
2016-02-02 17:33:24 +01:00
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser ;
2015-08-21 00:58:18 +02:00
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService ;
2017-04-19 13:23:13 +02:00
import nodomain.freeyourgadget.gadgetbridge.service.NotificationCollectorMonitorService ;
2017-09-03 01:02:31 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils ;
2015-07-08 23:03:34 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils ;
2015-08-22 01:08:46 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.GB ;
2016-04-28 23:17:13 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs ;
2016-01-09 16:07:22 +01:00
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue ;
2016-04-25 23:18:55 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.Prefs ;
2015-05-30 17:28:03 +02:00
2018-02-14 21:27:24 +01:00
import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_ID ;
2015-10-26 23:32:03 +01:00
/ * *
* Main Application class that initializes and provides access to certain things like
* logging and DB access .
* /
2015-05-01 09:36:10 +02:00
public class GBApplication extends Application {
2015-08-03 01:17:02 +02:00
// Since this class must not log to slf4j, we use plain android.util.Log
private static final String TAG = " GBApplication " ;
2016-08-27 22:51:00 +02:00
public static final String DATABASE_NAME = " Gadgetbridge " ;
2015-05-01 09:36:10 +02:00
private static GBApplication context ;
2015-08-16 00:17:16 +02:00
private static final Lock dbLock = new ReentrantLock ( ) ;
2015-08-21 00:58:18 +02:00
private static DeviceService deviceService ;
2015-09-25 00:53:40 +02:00
private static SharedPreferences sharedPrefs ;
2016-02-02 17:33:24 +01:00
private static final String PREFS_VERSION = " shared_preferences_version " ;
//if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version
2016-02-21 13:04:32 +01:00
private static final int CURRENT_PREFS_VERSION = 2 ;
2016-01-09 16:07:22 +01:00
private static LimitedQueue mIDSenderLookup = new LimitedQueue ( 16 ) ;
2016-04-25 23:18:55 +02:00
private static Prefs prefs ;
2016-04-28 23:17:13 +02:00
private static GBPrefs gbPrefs ;
2016-06-14 20:13:08 +02:00
private static LockHandler lockHandler ;
2016-05-20 22:04:30 +02:00
/ * *
* Note : is null on Lollipop and Kitkat
* /
2016-05-19 23:58:13 +02:00
private static NotificationManager notificationManager ;
2015-05-01 09:36:10 +02:00
2015-12-07 23:33:32 +01:00
public static final String ACTION_QUIT
= " nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit " ;
2017-07-31 22:49:05 +02:00
public static final String ACTION_LANGUAGE_CHANGE = " nodomain.freeyourgadget.gadgetbridge.gbapplication.action.language_change " ;
2017-04-27 07:52:11 +02:00
private static GBApplication app ;
2016-05-26 23:46:21 +02:00
private static Logging logging = new Logging ( ) {
@Override
protected String createLogDirectory ( ) throws IOException {
2017-04-27 07:52:11 +02:00
if ( GBEnvironment . env ( ) . isLocalTest ( ) ) {
return System . getProperty ( Logging . PROP_LOGFILES_DIR ) ;
} else {
File dir = FileUtils . getExternalFilesDir ( ) ;
return dir . getAbsolutePath ( ) ;
}
2016-05-26 23:46:21 +02:00
}
} ;
2017-07-31 22:49:05 +02:00
private static Locale language ;
2016-12-07 23:13:51 +01:00
private DeviceManager deviceManager ;
2018-05-16 19:03:06 +02:00
private BluetoothStateChangeReceiver bluetoothStateChangeReceiver ;
2015-12-07 23:33:32 +01:00
2016-07-08 22:35:52 +02:00
public static void quit ( ) {
GB . log ( " Quitting Gadgetbridge... " , GB . INFO , null ) ;
Intent quitIntent = new Intent ( GBApplication . ACTION_QUIT ) ;
LocalBroadcastManager . getInstance ( context ) . sendBroadcast ( quitIntent ) ;
GBApplication . deviceService ( ) . quit ( ) ;
2015-12-07 23:33:32 +01:00
}
2015-05-01 09:36:10 +02:00
public GBApplication ( ) {
context = this ;
2015-07-25 00:07:33 +02:00
// don't do anything here, add it to onCreate instead
2015-05-01 09:36:10 +02:00
}
2017-04-27 07:52:11 +02:00
public static Logging getLogging ( ) {
return logging ;
}
2015-08-21 00:58:18 +02:00
protected DeviceService createDeviceService ( ) {
2015-08-22 01:08:46 +02:00
return new GBDeviceService ( this ) ;
2015-08-21 00:58:18 +02:00
}
2015-05-13 23:15:20 +02:00
@Override
public void onCreate ( ) {
2017-04-27 07:52:11 +02:00
app = this ;
2015-05-13 23:15:20 +02:00
super . onCreate ( ) ;
2016-08-25 00:00:53 +02:00
if ( lockHandler ! = null ) {
// guard against multiple invocations (robolectric)
return ;
}
2015-09-25 00:53:40 +02:00
sharedPrefs = PreferenceManager . getDefaultSharedPreferences ( context ) ;
2016-04-25 23:18:55 +02:00
prefs = new Prefs ( sharedPrefs ) ;
2016-04-28 23:17:13 +02:00
gbPrefs = new GBPrefs ( prefs ) ;
2015-09-25 00:53:40 +02:00
2017-04-27 07:57:37 +02:00
if ( ! GBEnvironment . isEnvironmentSetup ( ) ) {
GBEnvironment . setupEnvironment ( GBEnvironment . createDeviceEnvironment ( ) ) ;
// setup db after the environment is set up, but don't do it in test mode
// in test mode, it's done individually, see TestBase
setupDatabase ( ) ;
}
2015-07-25 00:07:33 +02:00
// don't do anything here before we set up logging, otherwise
// slf4j may be implicitly initialized before we properly configured it.
2016-04-18 00:20:40 +02:00
setupLogging ( isFileLoggingEnabled ( ) ) ;
2015-10-07 23:32:58 +02:00
2016-02-02 17:33:24 +01:00
if ( getPrefsFileVersion ( ) ! = CURRENT_PREFS_VERSION ) {
migratePrefs ( getPrefsFileVersion ( ) ) ;
}
2015-10-07 23:32:58 +02:00
setupExceptionHandler ( ) ;
2015-06-05 21:46:56 +02:00
2016-06-18 23:35:34 +02:00
deviceManager = new DeviceManager ( this ) ;
2017-07-31 22:49:05 +02:00
String language = prefs . getString ( " language " , " default " ) ;
2017-07-31 23:00:02 +02:00
setLanguage ( language ) ;
2016-06-18 23:35:34 +02:00
2015-10-03 23:26:36 +02:00
deviceService = createDeviceService ( ) ;
2018-06-18 20:38:37 +02:00
loadAppsNotifBlackList ( ) ;
loadAppsPebbleBlackList ( ) ;
2017-08-18 10:30:19 +02:00
loadCalendarsBlackList ( ) ;
2015-12-07 23:33:32 +01:00
2016-05-19 23:58:13 +02:00
if ( isRunningMarshmallowOrLater ( ) ) {
2016-05-20 22:04:30 +02:00
notificationManager = ( NotificationManager ) context . getSystemService ( Context . NOTIFICATION_SERVICE ) ;
2017-04-19 13:23:13 +02:00
//the following will ensure the notification manager is kept alive
2018-02-14 21:27:24 +01:00
if ( isRunningOreoOrLater ( ) ) {
NotificationChannel channel = notificationManager . getNotificationChannel ( NOTIFICATION_CHANNEL_ID ) ;
if ( channel = = null ) {
channel = new NotificationChannel ( NOTIFICATION_CHANNEL_ID ,
getString ( R . string . notification_channel_name ) ,
NotificationManager . IMPORTANCE_LOW ) ;
notificationManager . createNotificationChannel ( channel ) ;
}
2018-05-16 19:03:06 +02:00
bluetoothStateChangeReceiver = new BluetoothStateChangeReceiver ( ) ;
registerReceiver ( bluetoothStateChangeReceiver , new IntentFilter ( BluetoothAdapter . ACTION_STATE_CHANGED ) ) ;
2018-02-14 21:27:24 +01:00
}
2017-04-19 13:23:13 +02:00
startService ( new Intent ( this , NotificationCollectorMonitorService . class ) ) ;
2016-05-19 23:58:13 +02:00
}
2015-05-13 23:15:20 +02:00
}
2016-11-24 21:11:28 +01:00
@Override
public void onTrimMemory ( int level ) {
super . onTrimMemory ( level ) ;
if ( level > = TRIM_MEMORY_BACKGROUND ) {
if ( ! hasBusyDevice ( ) ) {
DBHelper . clearSession ( ) ;
}
}
}
/ * *
* Returns true if at least a single device is busy , e . g synchronizing activity data
* or something similar .
* Note : busy is not the same as connected or initialized !
* /
private boolean hasBusyDevice ( ) {
List < GBDevice > devices = getDeviceManager ( ) . getDevices ( ) ;
2016-12-07 23:13:51 +01:00
for ( GBDevice device : devices ) {
2016-11-24 21:11:28 +01:00
if ( device . isBusy ( ) ) {
return true ;
}
}
2016-11-25 14:53:12 +01:00
return false ;
2016-11-24 21:11:28 +01:00
}
2016-05-26 23:46:21 +02:00
public static void setupLogging ( boolean enabled ) {
logging . setupLogging ( enabled ) ;
}
2018-08-28 14:03:57 +02:00
public static String getLogPath ( ) {
return logging . getLogPath ( ) ;
}
2015-10-07 23:32:58 +02:00
private void setupExceptionHandler ( ) {
LoggingExceptionHandler handler = new LoggingExceptionHandler ( Thread . getDefaultUncaughtExceptionHandler ( ) ) ;
Thread . setDefaultUncaughtExceptionHandler ( handler ) ;
}
2015-05-23 00:45:12 +02:00
public static boolean isFileLoggingEnabled ( ) {
2016-04-25 23:18:55 +02:00
return prefs . getBoolean ( " log_to_file " , false ) ;
2015-05-23 00:45:12 +02:00
}
2017-01-08 15:51:56 +01:00
public static boolean minimizeNotification ( ) {
return prefs . getBoolean ( " minimize_priority " , false ) ;
}
2017-04-27 07:52:11 +02:00
public void setupDatabase ( ) {
DaoMaster . OpenHelper helper ;
GBEnvironment env = GBEnvironment . env ( ) ;
if ( env . isTest ( ) ) {
helper = new DaoMaster . DevOpenHelper ( this , null , null ) ;
} else {
helper = new DBOpenHelper ( this , DATABASE_NAME , null ) ;
}
2016-04-17 19:52:51 +02:00
SQLiteDatabase db = helper . getWritableDatabase ( ) ;
DaoMaster daoMaster = new DaoMaster ( db ) ;
2016-06-14 20:13:08 +02:00
if ( lockHandler = = null ) {
lockHandler = new LockHandler ( ) ;
}
lockHandler . init ( daoMaster , helper ) ;
2016-04-17 19:52:51 +02:00
}
2015-05-01 09:36:10 +02:00
public static Context getContext ( ) {
return context ;
}
2015-05-30 17:28:03 +02:00
2015-10-26 23:32:03 +01:00
/ * *
* Returns the facade for talking to devices . Devices are managed by
* an Android Service and this facade provides access to its functionality .
*
* @return the facade for talking to the service / devices .
* /
2015-08-21 00:58:18 +02:00
public static DeviceService deviceService ( ) {
return deviceService ;
}
2015-08-03 01:17:02 +02:00
/ * *
* Returns the DBHandler instance for reading / writing or throws GBException
* when that was not successful
* If acquiring was successful , callers must call # releaseDB when they
* are done ( from the same thread that acquired the lock !
2016-12-07 23:13:51 +01:00
* < p >
2016-06-14 20:13:08 +02:00
* Callers must not hold a reference to the returned instance because it
* will be invalidated at some point .
*
2015-08-03 01:17:02 +02:00
* @return the DBHandler
* @throws GBException
2015-09-24 14:45:21 +02:00
* @see # releaseDB ( )
2015-08-03 01:17:02 +02:00
* /
public static DBHandler acquireDB ( ) throws GBException {
try {
if ( dbLock . tryLock ( 30 , TimeUnit . SECONDS ) ) {
2016-05-16 23:00:04 +02:00
return lockHandler ;
2015-08-03 01:17:02 +02:00
}
} catch ( InterruptedException ex ) {
Log . i ( TAG , " Interrupted while waiting for DB lock " ) ;
}
throw new GBException ( " Unable to access the database. " ) ;
}
/ * *
* Releases the database lock .
2015-09-24 14:45:21 +02:00
*
2015-08-03 01:17:02 +02:00
* @throws IllegalMonitorStateException if the current thread is not owning the lock
* @see # acquireDB ( )
* /
public static void releaseDB ( ) {
dbLock . unlock ( ) ;
2015-05-30 17:28:03 +02:00
}
2016-04-14 16:44:44 +02:00
2015-06-06 00:10:38 +02:00
public static boolean isRunningLollipopOrLater ( ) {
return VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP ;
}
2015-09-25 00:53:40 +02:00
2016-05-19 16:34:59 +02:00
public static boolean isRunningMarshmallowOrLater ( ) {
return VERSION . SDK_INT > = Build . VERSION_CODES . M ;
}
2018-04-12 22:06:45 +02:00
public static boolean isRunningNougatOrLater ( ) {
return VERSION . SDK_INT > = Build . VERSION_CODES . N ;
}
2016-05-19 16:34:59 +02:00
2018-02-14 21:27:24 +01:00
public static boolean isRunningOreoOrLater ( ) {
return VERSION . SDK_INT > = Build . VERSION_CODES . O ;
}
2016-05-19 23:58:13 +02:00
private static boolean isPrioritySender ( int prioritySenders , String number ) {
if ( prioritySenders = = Policy . PRIORITY_SENDERS_ANY ) {
return true ;
} else {
Uri uri = Uri . withAppendedPath ( PhoneLookup . CONTENT_FILTER_URI , Uri . encode ( number ) ) ;
String [ ] projection = new String [ ] { PhoneLookup . _ID , PhoneLookup . STARRED } ;
Cursor cursor = context . getContentResolver ( ) . query ( uri , projection , null , null , null ) ;
boolean exists = false ;
int starred = 0 ;
try {
2016-05-20 22:04:30 +02:00
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
2016-05-19 23:58:13 +02:00
exists = true ;
starred = cursor . getInt ( cursor . getColumnIndexOrThrow ( PhoneLookup . STARRED ) ) ;
}
} finally {
if ( cursor ! = null ) {
cursor . close ( ) ;
}
2016-05-19 16:34:59 +02:00
}
2016-05-19 23:58:13 +02:00
if ( prioritySenders = = Policy . PRIORITY_SENDERS_CONTACTS & & exists ) {
return true ;
} else if ( prioritySenders = = Policy . PRIORITY_SENDERS_STARRED & & starred = = 1 ) {
return true ;
2016-05-19 16:34:59 +02:00
}
2016-05-19 23:58:13 +02:00
return false ;
2016-05-19 16:34:59 +02:00
}
2016-05-19 23:58:13 +02:00
}
2016-05-20 21:49:25 +02:00
@TargetApi ( Build . VERSION_CODES . M )
2016-05-19 23:58:13 +02:00
public static boolean isPriorityNumber ( int priorityType , String number ) {
NotificationManager . Policy notificationPolicy = notificationManager . getNotificationPolicy ( ) ;
2016-12-07 23:13:51 +01:00
if ( priorityType = = Policy . PRIORITY_CATEGORY_MESSAGES ) {
2016-05-19 23:58:13 +02:00
if ( ( notificationPolicy . priorityCategories & Policy . PRIORITY_CATEGORY_MESSAGES ) = = Policy . PRIORITY_CATEGORY_MESSAGES ) {
return isPrioritySender ( notificationPolicy . priorityMessageSenders , number ) ;
}
} else if ( priorityType = = Policy . PRIORITY_CATEGORY_CALLS ) {
if ( ( notificationPolicy . priorityCategories & Policy . PRIORITY_CATEGORY_CALLS ) = = Policy . PRIORITY_CATEGORY_CALLS ) {
return isPrioritySender ( notificationPolicy . priorityCallSenders , number ) ;
}
2016-05-19 16:34:59 +02:00
}
return false ;
}
2016-05-20 21:49:25 +02:00
@TargetApi ( Build . VERSION_CODES . M )
2016-05-19 23:58:13 +02:00
public static int getGrantedInterruptionFilter ( ) {
if ( prefs . getBoolean ( " notification_filter " , false ) & & GBApplication . isRunningMarshmallowOrLater ( ) ) {
if ( notificationManager . isNotificationPolicyAccessGranted ( ) ) {
return notificationManager . getCurrentInterruptionFilter ( ) ;
}
}
return NotificationManager . INTERRUPTION_FILTER_ALL ;
}
2018-06-18 20:38:37 +02:00
private static HashSet < String > apps_notification_blacklist = null ;
2017-04-22 16:59:55 +02:00
2018-06-18 20:38:37 +02:00
public static boolean appIsNotifBlacklisted ( String packageName ) {
if ( apps_notification_blacklist = = null ) {
GB . log ( " appIsNotifBlacklisted: apps_notification_blacklist is null! " , GB . INFO , null ) ;
2017-05-21 21:02:23 +02:00
}
2018-06-18 20:38:37 +02:00
return apps_notification_blacklist ! = null & & apps_notification_blacklist . contains ( packageName ) ;
2017-04-22 16:59:55 +02:00
}
2018-06-18 20:38:37 +02:00
public static void setAppsNotifBlackList ( Set < String > packageNames ) {
2017-04-22 16:59:55 +02:00
if ( packageNames = = null ) {
2018-06-18 20:38:37 +02:00
GB . log ( " Set null apps_notification_blacklist " , GB . INFO , null ) ;
apps_notification_blacklist = new HashSet < > ( ) ;
2017-04-22 16:59:55 +02:00
} else {
2018-06-18 20:38:37 +02:00
apps_notification_blacklist = new HashSet < > ( packageNames ) ;
2017-04-22 16:59:55 +02:00
}
2018-06-18 20:38:37 +02:00
GB . log ( " New apps_notification_blacklist has " + apps_notification_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
saveAppsNotifBlackList ( ) ;
2017-04-22 16:59:55 +02:00
}
2015-09-25 00:53:40 +02:00
2018-06-18 20:38:37 +02:00
private static void loadAppsNotifBlackList ( ) {
GB . log ( " Loading apps_notification_blacklist " , GB . INFO , null ) ;
apps_notification_blacklist = ( HashSet < String > ) sharedPrefs . getStringSet ( GBPrefs . PACKAGE_BLACKLIST , null ) ;
if ( apps_notification_blacklist = = null ) {
apps_notification_blacklist = new HashSet < > ( ) ;
2015-09-25 00:53:40 +02:00
}
2018-06-18 20:38:37 +02:00
GB . log ( " Loaded apps_notification_blacklist has " + apps_notification_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
2015-09-25 00:53:40 +02:00
}
2018-06-18 20:38:37 +02:00
private static void saveAppsNotifBlackList ( ) {
GB . log ( " Saving apps_notification_blacklist with " + apps_notification_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
2015-09-25 00:53:40 +02:00
SharedPreferences . Editor editor = sharedPrefs . edit ( ) ;
2018-06-18 20:38:37 +02:00
if ( apps_notification_blacklist . isEmpty ( ) ) {
2017-04-22 16:59:55 +02:00
editor . putStringSet ( GBPrefs . PACKAGE_BLACKLIST , null ) ;
2015-09-25 00:53:40 +02:00
} else {
2018-06-18 20:38:37 +02:00
Prefs . putStringSet ( editor , GBPrefs . PACKAGE_BLACKLIST , apps_notification_blacklist ) ;
2015-09-25 00:53:40 +02:00
}
editor . apply ( ) ;
}
2018-06-18 20:38:37 +02:00
public static void addAppToNotifBlacklist ( String packageName ) {
if ( apps_notification_blacklist . add ( packageName ) ) {
saveAppsNotifBlackList ( ) ;
2015-09-25 00:53:40 +02:00
}
}
2018-06-18 20:38:37 +02:00
public static synchronized void removeFromAppsNotifBlacklist ( String packageName ) {
GB . log ( " Removing from apps_notification_blacklist: " + packageName , GB . INFO , null ) ;
apps_notification_blacklist . remove ( packageName ) ;
saveAppsNotifBlackList ( ) ;
2017-08-18 10:30:19 +02:00
}
2018-06-18 20:38:37 +02:00
private static HashSet < String > apps_pebblemsg_blacklist = null ;
public static boolean appIsPebbleBlacklisted ( String sender ) {
if ( apps_pebblemsg_blacklist = = null ) {
GB . log ( " appIsPebbleBlacklisted: apps_pebblemsg_blacklist is null! " , GB . INFO , null ) ;
}
return apps_pebblemsg_blacklist ! = null & & apps_pebblemsg_blacklist . contains ( sender ) ;
}
public static void setAppsPebbleBlackList ( Set < String > packageNames ) {
if ( packageNames = = null ) {
GB . log ( " Set null apps_pebblemsg_blacklist " , GB . INFO , null ) ;
apps_pebblemsg_blacklist = new HashSet < > ( ) ;
} else {
apps_pebblemsg_blacklist = new HashSet < > ( packageNames ) ;
}
GB . log ( " New apps_pebblemsg_blacklist has " + apps_pebblemsg_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
saveAppsPebbleBlackList ( ) ;
}
private static void loadAppsPebbleBlackList ( ) {
GB . log ( " Loading apps_pebblemsg_blacklist " , GB . INFO , null ) ;
apps_pebblemsg_blacklist = ( HashSet < String > ) sharedPrefs . getStringSet ( GBPrefs . PACKAGE_PEBBLEMSG_BLACKLIST , null ) ;
if ( apps_pebblemsg_blacklist = = null ) {
apps_pebblemsg_blacklist = new HashSet < > ( ) ;
}
GB . log ( " Loaded apps_pebblemsg_blacklist has " + apps_pebblemsg_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
}
private static void saveAppsPebbleBlackList ( ) {
GB . log ( " Saving apps_pebblemsg_blacklist with " + apps_pebblemsg_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
SharedPreferences . Editor editor = sharedPrefs . edit ( ) ;
if ( apps_pebblemsg_blacklist . isEmpty ( ) ) {
editor . putStringSet ( GBPrefs . PACKAGE_PEBBLEMSG_BLACKLIST , null ) ;
} else {
Prefs . putStringSet ( editor , GBPrefs . PACKAGE_PEBBLEMSG_BLACKLIST , apps_pebblemsg_blacklist ) ;
}
editor . apply ( ) ;
}
public static void addAppToPebbleBlacklist ( String packageName ) {
if ( apps_pebblemsg_blacklist . add ( packageNameToPebbleMsgSender ( packageName ) ) ) {
saveAppsPebbleBlackList ( ) ;
}
}
public static synchronized void removeFromAppsPebbleBlacklist ( String packageName ) {
GB . log ( " Removing from apps_pebblemsg_blacklist: " + packageName , GB . INFO , null ) ;
apps_pebblemsg_blacklist . remove ( packageNameToPebbleMsgSender ( packageName ) ) ;
saveAppsPebbleBlackList ( ) ;
}
public static String packageNameToPebbleMsgSender ( String packageName ) {
if ( " eu.siacs.conversations " . equals ( packageName ) ) {
return ( " Conversations " ) ;
} else if ( " net.osmand.plus " . equals ( packageName ) ) {
return ( " OsmAnd " ) ;
}
return packageName ;
}
2017-08-18 10:30:19 +02:00
private static HashSet < String > calendars_blacklist = null ;
public static boolean calendarIsBlacklisted ( String calendarDisplayName ) {
if ( calendars_blacklist = = null ) {
GB . log ( " calendarIsBlacklisted: calendars_blacklist is null! " , GB . INFO , null ) ;
}
return calendars_blacklist ! = null & & calendars_blacklist . contains ( calendarDisplayName ) ;
}
public static void setCalendarsBlackList ( Set < String > calendarNames ) {
if ( calendarNames = = null ) {
2018-06-18 20:38:37 +02:00
GB . log ( " Set null apps_notification_blacklist " , GB . INFO , null ) ;
2017-08-18 10:30:19 +02:00
calendars_blacklist = new HashSet < > ( ) ;
} else {
calendars_blacklist = new HashSet < > ( calendarNames ) ;
}
GB . log ( " New calendars_blacklist has " + calendars_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
saveCalendarsBlackList ( ) ;
}
public static void addCalendarToBlacklist ( String calendarDisplayName ) {
if ( calendars_blacklist . add ( calendarDisplayName ) ) {
saveCalendarsBlackList ( ) ;
}
}
public static void removeFromCalendarBlacklist ( String calendarDisplayName ) {
calendars_blacklist . remove ( calendarDisplayName ) ;
saveCalendarsBlackList ( ) ;
}
private static void loadCalendarsBlackList ( ) {
GB . log ( " Loading calendars_blacklist " , GB . INFO , null ) ;
calendars_blacklist = ( HashSet < String > ) sharedPrefs . getStringSet ( GBPrefs . CALENDAR_BLACKLIST , null ) ;
if ( calendars_blacklist = = null ) {
calendars_blacklist = new HashSet < > ( ) ;
}
GB . log ( " Loaded calendars_blacklist has " + calendars_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
}
private static void saveCalendarsBlackList ( ) {
GB . log ( " Saving calendars_blacklist with " + calendars_blacklist . size ( ) + " entries " , GB . INFO , null ) ;
SharedPreferences . Editor editor = sharedPrefs . edit ( ) ;
if ( calendars_blacklist . isEmpty ( ) ) {
editor . putStringSet ( GBPrefs . CALENDAR_BLACKLIST , null ) ;
} else {
Prefs . putStringSet ( editor , GBPrefs . CALENDAR_BLACKLIST , calendars_blacklist ) ;
}
editor . apply ( ) ;
2015-09-25 00:53:40 +02:00
}
2015-12-08 23:42:58 +01:00
/ * *
2016-08-31 17:35:28 +02:00
* Deletes both the old Activity database and the new one recreates it with empty tables .
2015-12-14 23:31:31 +01:00
*
2015-12-08 23:42:58 +01:00
* @return true on successful deletion
* /
2016-08-27 22:55:00 +02:00
public static synchronized boolean deleteActivityDatabase ( Context context ) {
2016-05-13 23:47:47 +02:00
// TODO: flush, close, reopen db
2016-05-17 00:51:00 +02:00
if ( lockHandler ! = null ) {
lockHandler . closeDb ( ) ;
}
2017-02-23 22:44:44 +01:00
boolean result = deleteOldActivityDatabase ( context ) ;
2016-08-27 22:51:00 +02:00
result & = getContext ( ) . deleteDatabase ( DATABASE_NAME ) ;
2015-12-08 23:42:58 +01:00
return result ;
}
2015-12-14 23:31:31 +01:00
2016-08-31 17:35:28 +02:00
/ * *
* Deletes the legacy ( pre 0 . 12 ) Activity database
*
* @return true on successful deletion
* /
public static synchronized boolean deleteOldActivityDatabase ( Context context ) {
DBHelper dbHelper = new DBHelper ( context ) ;
boolean result = true ;
2017-02-23 22:44:44 +01:00
if ( dbHelper . existsDB ( " ActivityDatabase " ) ) {
result = getContext ( ) . deleteDatabase ( " ActivityDatabase " ) ;
2016-08-31 17:35:28 +02:00
}
return result ;
}
2016-02-02 17:33:24 +01:00
private int getPrefsFileVersion ( ) {
2016-02-21 13:04:32 +01:00
try {
return Integer . parseInt ( sharedPrefs . getString ( PREFS_VERSION , " 0 " ) ) ; //0 is legacy
} catch ( Exception e ) {
//in version 1 this was an int
return 1 ;
}
2016-02-02 17:33:24 +01:00
}
private void migratePrefs ( int oldVersion ) {
2016-02-21 13:04:32 +01:00
SharedPreferences . Editor editor = sharedPrefs . edit ( ) ;
2016-02-29 20:54:39 +01:00
switch ( oldVersion ) {
2016-02-02 17:33:24 +01:00
case 0 :
String legacyGender = sharedPrefs . getString ( " mi_user_gender " , null ) ;
String legacyHeight = sharedPrefs . getString ( " mi_user_height_cm " , null ) ;
2018-03-30 15:38:29 +02:00
String legacyWeight = sharedPrefs . getString ( " mi_user_weight_kg " , null ) ;
2016-02-29 20:54:39 +01:00
String legacyYOB = sharedPrefs . getString ( " mi_user_year_of_birth " , null ) ;
if ( legacyGender ! = null ) {
2016-02-02 17:33:24 +01:00
int gender = " male " . equals ( legacyGender ) ? 1 : " female " . equals ( legacyGender ) ? 0 : 2 ;
2016-02-21 13:04:32 +01:00
editor . putString ( ActivityUser . PREF_USER_GENDER , Integer . toString ( gender ) ) ;
2016-02-02 17:33:24 +01:00
editor . remove ( " mi_user_gender " ) ;
}
2016-02-29 20:54:39 +01:00
if ( legacyHeight ! = null ) {
2016-02-02 17:33:24 +01:00
editor . putString ( ActivityUser . PREF_USER_HEIGHT_CM , legacyHeight ) ;
editor . remove ( " mi_user_height_cm " ) ;
}
2018-03-30 15:38:29 +02:00
if ( legacyWeight ! = null ) {
editor . putString ( ActivityUser . PREF_USER_WEIGHT_KG , legacyWeight ) ;
2016-02-02 17:33:24 +01:00
editor . remove ( " mi_user_weight_kg " ) ;
}
2016-02-29 20:54:39 +01:00
if ( legacyYOB ! = null ) {
2016-02-02 17:33:24 +01:00
editor . putString ( ActivityUser . PREF_USER_YEAR_OF_BIRTH , legacyYOB ) ;
editor . remove ( " mi_user_year_of_birth " ) ;
}
2016-02-21 13:04:32 +01:00
editor . putString ( PREFS_VERSION , Integer . toString ( CURRENT_PREFS_VERSION ) ) ;
2016-02-02 17:33:24 +01:00
break ;
2016-02-21 13:04:32 +01:00
case 1 :
2016-02-21 16:46:48 +01:00
//migrate the integer version of gender introduced in version 1 to a string value, needed for the way Android accesses the shared preferences
int legacyGender_1 = 2 ;
try {
legacyGender_1 = sharedPrefs . getInt ( ActivityUser . PREF_USER_GENDER , 2 ) ;
} catch ( Exception e ) {
Log . e ( TAG , " Could not access legacy activity gender " , e ) ;
2016-02-21 13:04:32 +01:00
}
2016-02-21 16:46:48 +01:00
editor . putString ( ActivityUser . PREF_USER_GENDER , Integer . toString ( legacyGender_1 ) ) ;
//also silently migrate the version to a string value
2016-02-21 13:04:32 +01:00
editor . putString ( PREFS_VERSION , Integer . toString ( CURRENT_PREFS_VERSION ) ) ;
break ;
2016-02-02 17:33:24 +01:00
}
2016-04-14 16:15:58 +02:00
editor . apply ( ) ;
2016-02-02 17:33:24 +01:00
}
2017-07-31 23:00:02 +02:00
public static void setLanguage ( String lang ) {
2017-07-31 22:49:05 +02:00
if ( lang . equals ( " default " ) ) {
2017-07-31 23:00:02 +02:00
language = Resources . getSystem ( ) . getConfiguration ( ) . locale ;
2017-07-31 22:49:05 +02:00
} else {
language = new Locale ( lang ) ;
}
2017-09-03 01:02:31 +02:00
updateLanguage ( language ) ;
}
2017-07-31 22:49:05 +02:00
2017-09-03 01:02:31 +02:00
public static void updateLanguage ( Locale locale ) {
AndroidUtils . setLanguage ( context , locale ) ;
2017-07-31 23:00:02 +02:00
2017-07-31 22:49:05 +02:00
Intent intent = new Intent ( ) ;
intent . setAction ( ACTION_LANGUAGE_CHANGE ) ;
LocalBroadcastManager . getInstance ( context ) . sendBroadcast ( intent ) ;
}
2016-01-09 16:07:22 +01:00
public static LimitedQueue getIDSenderLookup ( ) {
2015-12-14 23:31:31 +01:00
return mIDSenderLookup ;
}
2016-04-14 15:21:25 +02:00
public static boolean isDarkThemeEnabled ( ) {
2016-04-25 23:18:55 +02:00
return prefs . getString ( " pref_key_theme " , context . getString ( R . string . pref_theme_value_light ) ) . equals ( context . getString ( R . string . pref_theme_value_dark ) ) ;
2016-04-14 15:21:25 +02:00
}
2016-04-23 23:24:56 +02:00
public static int getTextColor ( Context context ) {
TypedValue typedValue = new TypedValue ( ) ;
Resources . Theme theme = context . getTheme ( ) ;
2017-04-08 15:49:00 +02:00
theme . resolveAttribute ( R . attr . textColorPrimary , typedValue , true ) ;
2016-04-23 23:24:56 +02:00
return typedValue . data ;
}
2016-12-07 23:13:51 +01:00
2017-09-03 01:02:31 +02:00
@Override
public void onConfigurationChanged ( Configuration newConfig ) {
super . onConfigurationChanged ( newConfig ) ;
updateLanguage ( getLanguage ( ) ) ;
}
2016-04-23 23:24:56 +02:00
public static int getBackgroundColor ( Context context ) {
TypedValue typedValue = new TypedValue ( ) ;
Resources . Theme theme = context . getTheme ( ) ;
theme . resolveAttribute ( android . R . attr . background , typedValue , true ) ;
return typedValue . data ;
}
2016-04-25 23:18:55 +02:00
public static Prefs getPrefs ( ) {
return prefs ;
}
2016-04-28 23:17:13 +02:00
public static GBPrefs getGBPrefs ( ) {
return gbPrefs ;
2016-04-14 15:21:25 +02:00
}
2016-06-18 23:35:34 +02:00
2016-12-07 23:13:51 +01:00
public DeviceManager getDeviceManager ( ) {
2016-06-18 23:35:34 +02:00
return deviceManager ;
}
2017-04-27 07:52:11 +02:00
public static GBApplication app ( ) {
return app ;
}
2017-07-31 22:49:05 +02:00
public static Locale getLanguage ( ) {
return language ;
}
2017-10-19 21:52:38 +02:00
public String getVersion ( ) {
try {
return getPackageManager ( ) . getPackageInfo ( getPackageName ( ) , PackageManager . GET_META_DATA ) . versionName ;
} catch ( PackageManager . NameNotFoundException e ) {
GB . log ( " Unable to determine Gadgetbridge's version " , GB . WARN , e ) ;
return " 0.0.0 " ;
}
}
public String getNameAndVersion ( ) {
try {
ApplicationInfo appInfo = getPackageManager ( ) . getApplicationInfo ( getContext ( ) . getPackageName ( ) , PackageManager . GET_META_DATA ) ;
PackageInfo packageInfo = getPackageManager ( ) . getPackageInfo ( getPackageName ( ) , PackageManager . GET_META_DATA ) ;
return String . format ( " %s %s " , appInfo . name , packageInfo . versionName ) ;
} catch ( PackageManager . NameNotFoundException e ) {
GB . log ( " Unable to determine Gadgetbridge's name/version " , GB . WARN , e ) ;
return " Gadgetbridge " ;
}
}
2015-05-01 09:36:10 +02:00
}