diff --git a/.idea/copyright/GPLv3.xml b/.idea/copyright/GPLv3.xml
new file mode 100644
index 00000000..bb6cb37e
--- /dev/null
+++ b/.idea/copyright/GPLv3.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 00000000..3b363ccf
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..86a0dbfb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Florent Revest revestflo@gmail.com
+Doug Koellmer dougkoellmer@hotmail.com
+Justus Tartz git@jrtberlin.de
+Doomsdayrs doomsdayrs@gmail.com
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4e5d1f06..2da65c64 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,5 +1,6 @@
plugins {
id("com.android.application")
+ kotlin("android")
}
android {
@@ -35,8 +36,8 @@ android {
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
lint {
checkReleaseBuilds = true
@@ -53,11 +54,14 @@ repositories {
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
+ implementation("androidx.core:core-ktx:1.9.0")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
testImplementation("junit:junit:4.13.2")
- implementation("androidx.appcompat:appcompat:1.5.1")
+ implementation("androidx.appcompat:appcompat:1.6.0")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.cardview:cardview:1.0.0")
- implementation("com.google.android.material:material:1.6.1")
+ implementation("com.google.android.material:material:1.8.0")
implementation("com.github.MagneFire:EasyWeather:1.3")
implementation("com.google.code.gson:gson:2.9.1")
implementation("org.osmdroid:osmdroid-android:6.1.14")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 328e9e04..026a17b3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,8 @@
+
+
diff --git a/app/src/main/java/org/asteroidos/sync/MainActivity.java b/app/src/main/java/org/asteroidos/sync/MainActivity.java
index 84487647..e5bc8ffe 100644
--- a/app/src/main/java/org/asteroidos/sync/MainActivity.java
+++ b/app/src/main/java/org/asteroidos/sync/MainActivity.java
@@ -1,5 +1,25 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync;
+import static android.os.ParcelUuid.fromString;
+
import android.Manifest;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
@@ -17,10 +37,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import android.os.ParcelUuid;
-import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import android.view.MenuItem;
@@ -35,6 +52,7 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import androidx.lifecycle.ViewModelProvider;
import org.asteroidos.sync.asteroid.IAsteroidDevice;
import org.asteroidos.sync.fragments.AppListFragment;
@@ -45,6 +63,8 @@
import org.asteroidos.sync.utils.AppInfo;
import org.asteroidos.sync.utils.AppInfoHelper;
import org.asteroidos.sync.utils.AsteroidUUIDS;
+import org.asteroidos.sync.viewmodel.base.MainActivityViewModel;
+import org.asteroidos.sync.viewmodel.impl.MainActivityViewModelImpl;
import java.util.ArrayList;
import java.util.List;
@@ -55,8 +75,6 @@
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;
-import static android.os.ParcelUuid.fromString;
-
public class MainActivity extends AppCompatActivity implements DeviceListFragment.OnDefaultDeviceSelectedListener,
DeviceListFragment.OnScanRequestedListener, DeviceDetailFragment.OnDefaultDeviceUnselectedListener,
DeviceDetailFragment.OnConnectRequestedListener, DeviceDetailFragment.OnAppSettingsClickedListener,
@@ -67,21 +85,17 @@ public class MainActivity extends AppCompatActivity implements DeviceListFragmen
public static final String PREFS_DEFAULT_LOC_NAME = "defaultLocalName";
private static final String TAG = "MainActivity";
public static ArrayList appInfoList;
- final Messenger mDeviceDetailMessenger = new Messenger(new MainActivity.SynchronizationHandler(this));
- public ParcelUuid asteroidUUID = fromString(AsteroidUUIDS.SERVICE_UUID.toString());
- Messenger mSyncServiceMessenger;
+ public final ParcelUuid asteroidUUID = fromString(AsteroidUUIDS.SERVICE_UUID.toString());
ActivityResultLauncher mLocationEnableActivityLauncher;
LocationManager mLocationManager;
/* Synchronization service events handling */
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
- mSyncServiceMessenger = new Messenger(service);
onUpdateRequested();
}
public void onServiceDisconnected(ComponentName className) {
- mSyncServiceMessenger = null;
}
};
Intent mSyncServiceIntent;
@@ -89,7 +103,7 @@ public void onServiceDisconnected(ComponentName className) {
ScanSettings mSettings;
List mFilters;
private DeviceListFragment mListFragment;
- public ScanCallback scanCallback = new ScanCallback() {
+ public final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, @NonNull ScanResult result) {
super.onScanResult(callbackType, result);
@@ -102,7 +116,7 @@ public void onScanResult(int callbackType, @NonNull ScanResult result) {
}
return;
}
- Log.d(TAG, "SCAN RESULT:" + result.getDevice().toString() + " Name:" + result.getDevice().getName());
+ Log.d(TAG, "SCAN RESULT:" + result.getDevice() + " Name:" + result.getDevice().getName());
ParcelUuid[] arr = result.getDevice().getUuids();
}
};
@@ -110,22 +124,23 @@ public void onScanResult(int callbackType, @NonNull ScanResult result) {
private Fragment mPreviousFragment;
private BluetoothLeScannerCompat mScanner;
private SharedPreferences mPrefs;
+ MainActivityViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ viewModel = new ViewModelProvider(this).get(MainActivityViewModelImpl.class);
+ viewModel.onWatchLocalNameChanged(this::handleSetLocalName);
+ viewModel.onWatchConnectionStateChanged(this::handleSetStatus);
+ viewModel.onWatchBatteryPercentageChanged(this::handleSetBatteryPercentage);
mScanner = BluetoothLeScannerCompat.getScanner();
mPrefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
String defaultDevMacAddr = mPrefs.getString(PREFS_DEFAULT_MAC_ADDR, "");
- Thread appInfoRetrieval = new Thread(new Runnable() {
- public void run() {
- appInfoList = AppInfoHelper.getPackageInfo(MainActivity.this);
- }
- });
+ Thread appInfoRetrieval = new Thread(() -> appInfoList = AppInfoHelper.getPackageInfo(MainActivity.this));
appInfoRetrieval.start();
mSettings = new ScanSettings.Builder()
@@ -179,20 +194,14 @@ public void onDefaultDeviceSelected(BluetoothDevice mDevice) {
mDetailFragment = new DeviceDetailFragment();
if (mListFragment != null) mListFragment.scanningStopped();
- else if (mDetailFragment != null) mDetailFragment.scanningStopped();
+ else mDetailFragment.scanningStopped();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.flContainer, mDetailFragment)
.commit();
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_SET_DEVICE);
- msg.obj = mDevice;
- msg.replyTo = mDeviceDetailMessenger;
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.onDefaultDeviceSelected(mDevice);
onConnectRequested();
@@ -209,13 +218,7 @@ public void onDefaultDeviceUnselected() {
.replace(R.id.flContainer, mListFragment)
.commit();
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_UNSET_DEVICE);
- msg.obj = "";
- msg.replyTo = mDeviceDetailMessenger;
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.requestUnsetDevice();
mDetailFragment = null;
setTitle(R.string.app_name);
@@ -223,35 +226,19 @@ public void onDefaultDeviceUnselected() {
@Override
public void onUpdateRequested() {
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_UPDATE);
- msg.replyTo = mDeviceDetailMessenger;
- if (mSyncServiceMessenger != null)
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.requestUpdate();
}
@Override
public void onConnectRequested() {
if (mScanner != null)
mScanner.stopScan(scanCallback);
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_CONNECT);
- msg.replyTo = mDeviceDetailMessenger;
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.requestConnect();
}
@Override
public void onDisconnectRequested() {
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_DISCONNECT);
- msg.replyTo = mDeviceDetailMessenger;
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.requestDisconnect();
}
@Override
@@ -342,12 +329,7 @@ private void handleSetStatus(IAsteroidDevice.ConnectionState status) {
mStatus = status;
}
if (status == IAsteroidDevice.ConnectionState.STATUS_CONNECTED) {
- try {
- Message msg = Message.obtain(null, SynchronizationService.MSG_REQUEST_BATTERY_LIFE);
- msg.replyTo = mDeviceDetailMessenger;
- mSyncServiceMessenger.send(msg);
- } catch (RemoteException ignored) {
- }
+ viewModel.requestBatteryLevel();
}
}
@@ -418,7 +400,7 @@ protected void onPause() {
}
@Override
- public void onConfigurationChanged(Configuration newConfig) {
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
@@ -435,29 +417,4 @@ public void onConfigurationChanged(Configuration newConfig) {
overridePendingTransition(0, 0);
startActivity(getIntent());
}
-
- static private class SynchronizationHandler extends Handler {
- private final MainActivity mActivity;
-
- SynchronizationHandler(MainActivity activity) {
- mActivity = activity;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SynchronizationService.MSG_SET_LOCAL_NAME:
- mActivity.handleSetLocalName((String) msg.obj);
- break;
- case SynchronizationService.MSG_SET_STATUS:
- mActivity.handleSetStatus((IAsteroidDevice.ConnectionState) msg.obj);
- break;
- case SynchronizationService.MSG_SET_BATTERY_PERCENTAGE:
- mActivity.handleSetBatteryPercentage(msg.arg1);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- }
}
diff --git a/app/src/main/java/org/asteroidos/sync/NotificationPreferences.java b/app/src/main/java/org/asteroidos/sync/NotificationPreferences.java
index 5112801a..503fa00b 100644
--- a/app/src/main/java/org/asteroidos/sync/NotificationPreferences.java
+++ b/app/src/main/java/org/asteroidos/sync/NotificationPreferences.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync;
import android.content.Context;
@@ -21,7 +39,7 @@ public enum NotificationOption {
STRONG_VIBRATION(4),
RINGTONE_VIBRATION(5);
- private int value;
+ private final int value;
NotificationOption(int value) {
this.value = value;
}
diff --git a/app/src/main/java/org/asteroidos/sync/PermissionsActivity.java b/app/src/main/java/org/asteroidos/sync/PermissionsActivity.java
index 9c4ae711..54472e70 100644
--- a/app/src/main/java/org/asteroidos/sync/PermissionsActivity.java
+++ b/app/src/main/java/org/asteroidos/sync/PermissionsActivity.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync;
import android.Manifest;
@@ -16,11 +34,14 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import org.asteroidos.sync.services.NLService;
+import java.util.ArrayList;
+
import io.github.dreierf.materialintroscreen.MaterialIntroActivity;
import io.github.dreierf.materialintroscreen.SlideFragment;
import io.github.dreierf.materialintroscreen.SlideFragmentBuilder;
@@ -41,105 +62,116 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
if (hasBLE) {
if (!isLowRamDevice) {
- SlideFragment welcomeFragment = new SlideFragmentBuilder()
- .backgroundColor(R.color.colorintroslide1)
- .buttonsColor(R.color.colorintroslide1button)
- .image(R.drawable.introslide1icon)
- .title(getString(R.string.intro_slide1_title))
- .description(getString(R.string.intro_slide1_subtitle))
- .build();
-
- SlideFragment externalStorageFragment = new SlideFragmentBuilder()
- .backgroundColor(R.color.colorintroslide2)
- .buttonsColor(R.color.colorintroslide2button)
- .neededPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})
- .image(R.drawable.introslide2icon)
- .title(getString(R.string.intro_slide2_title))
- .description(getString(R.string.intro_slide2_subtitle))
- .build();
+ SlideFragment welcomeFragment = new SlideFragmentBuilder()
+ .backgroundColor(R.color.colorintroslide1)
+ .buttonsColor(R.color.colorintroslide1button)
+ .image(R.drawable.introslide1icon)
+ .title(getString(R.string.intro_slide1_title))
+ .description(getString(R.string.intro_slide1_subtitle))
+ .build();
+
+ SlideFragment externalStorageFragment = new SlideFragmentBuilder()
+ .backgroundColor(R.color.colorintroslide2)
+ .buttonsColor(R.color.colorintroslide2button)
+ .neededPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})
+ .image(R.drawable.introslide2icon)
+ .title(getString(R.string.intro_slide2_title))
+ .description(getString(R.string.intro_slide2_subtitle))
+ .build();
boolean externalStorageFragmentShown = false;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
- externalStorageFragmentShown = (ContextCompat.checkSelfPermission(this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED);
- }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ externalStorageFragmentShown = (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED);
+ }
- SlideFragmentBuilder localizationFragmentBuilder = new SlideFragmentBuilder()
- .backgroundColor(R.color.colorintroslide3)
- .buttonsColor(R.color.colorintroslide3button)
- .neededPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION})
- .image(R.drawable.introslide3icon)
- .title(getString(R.string.intro_slide3_title))
- .description(getString(R.string.intro_slide3_subtitle));
+ ArrayList permissions = new ArrayList<>();
+ permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- localizationFragmentBuilder.neededPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN});
- }
- SlideFragment localizationFragment = localizationFragmentBuilder.build();
-
- boolean localizationFragmentShown = (ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED);
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- localizationFragmentShown |= (ContextCompat.checkSelfPermission(this,
- Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED);
- localizationFragmentShown |= (ContextCompat.checkSelfPermission(this,
- Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED);
- }
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ permissions.add(Manifest.permission.BLUETOOTH_CONNECT);
+ permissions.add(Manifest.permission.BLUETOOTH_SCAN);
+ }
- boolean notificationsPermissionFragmentShown = false;
- SlideFragment notificationsPermissionFragment = null;
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- SlideFragmentBuilder notificationsPermissionSlideBuilder = new SlideFragmentBuilder()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
+ permissions.add(Manifest.permission.NEARBY_WIFI_DEVICES);
+ }
+
+ SlideFragmentBuilder localizationFragmentBuilder = new SlideFragmentBuilder()
.backgroundColor(R.color.colorintroslide3)
.buttonsColor(R.color.colorintroslide3button)
- .neededPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS})
- .image(R.drawable.ic_notifications)
- .title(getString(R.string.intro_slide6_title))
- .description(getString(R.string.intro_slide6_subtitle));
- notificationsPermissionSlideBuilder.neededPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS});
- notificationsPermissionFragment = notificationsPermissionSlideBuilder.build();
- notificationsPermissionFragmentShown = (ContextCompat.checkSelfPermission(this,
- Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED);
- }
+ .neededPermissions(permissions.toArray(new String[]{}))
+ .image(R.drawable.introslide3icon)
+ .title(getString(R.string.intro_slide3_title))
+ .description(getString(R.string.intro_slide3_subtitle));
- NotificationsSlide notificationFragment = new NotificationsSlide();
- notificationFragment.setContext(this);
- boolean notificationFragmentShown = notificationFragment.hasAnyPermissionsToGrant();
-
- BatteryOptimSlide batteryOptimFragment = new BatteryOptimSlide();
- batteryOptimFragment.setContext(this);
- boolean batteryOptimFragmentShown = batteryOptimFragment.hasAnyPermissionsToGrant();
-
- SlideFragment phoneStateFragment = new SlideFragmentBuilder()
- .backgroundColor(R.color.colorintroslide2)
- .buttonsColor(R.color.colorintroslide2button)
- .neededPermissions(new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG, Manifest.permission.READ_CONTACTS})
- .image(R.drawable.ic_ring_volume)
- .title(getString(R.string.intro_phonestateslide_title))
- .description(getString(R.string.intro_phonestateslide_subtitle))
- .build();
- boolean phoneStateFragmentShown = (ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) ||
- (ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) ||
- (ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED);
-
- if (externalStorageFragmentShown || localizationFragmentShown ||
- notificationFragmentShown || notificationsPermissionFragmentShown || batteryOptimFragmentShown || phoneStateFragmentShown) {
- addSlide(welcomeFragment);
- if (externalStorageFragmentShown) addSlide(externalStorageFragment);
- if (localizationFragmentShown) addSlide(localizationFragment);
- if (notificationsPermissionFragmentShown && notificationsPermissionFragment != null) addSlide(notificationsPermissionFragment);
- if (notificationFragmentShown) addSlide(notificationFragment);
- if (batteryOptimFragmentShown) addSlide(batteryOptimFragment);
- if (phoneStateFragmentShown) addSlide(phoneStateFragment);
- } else
- startMainActivity();
- } else {
+
+ SlideFragment localizationFragment = localizationFragmentBuilder.build();
+
+ boolean localizationFragmentShown = (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED);
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ localizationFragmentShown |= (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED);
+ localizationFragmentShown |= (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED);
+ }
+
+ boolean notificationsPermissionFragmentShown = false;
+ SlideFragment notificationsPermissionFragment = null;
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ SlideFragmentBuilder notificationsPermissionSlideBuilder = new SlideFragmentBuilder()
+ .backgroundColor(R.color.colorintroslide3)
+ .buttonsColor(R.color.colorintroslide3button)
+ .neededPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS})
+ .image(R.drawable.ic_notifications)
+ .title(getString(R.string.intro_slide6_title))
+ .description(getString(R.string.intro_slide6_subtitle));
+ notificationsPermissionSlideBuilder.neededPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS});
+ notificationsPermissionFragment = notificationsPermissionSlideBuilder.build();
+ notificationsPermissionFragmentShown = (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED);
+ }
+
+ NotificationsSlide notificationFragment = new NotificationsSlide();
+ notificationFragment.setContext(this);
+ boolean notificationFragmentShown = notificationFragment.hasAnyPermissionsToGrant();
+
+ BatteryOptimSlide batteryOptimFragment = new BatteryOptimSlide();
+ batteryOptimFragment.setContext(this);
+ boolean batteryOptimFragmentShown = batteryOptimFragment.hasAnyPermissionsToGrant();
+
+ SlideFragment phoneStateFragment = new SlideFragmentBuilder()
+ .backgroundColor(R.color.colorintroslide2)
+ .buttonsColor(R.color.colorintroslide2button)
+ .neededPermissions(new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG, Manifest.permission.READ_CONTACTS})
+ .image(R.drawable.ic_ring_volume)
+ .title(getString(R.string.intro_phonestateslide_title))
+ .description(getString(R.string.intro_phonestateslide_subtitle))
+ .build();
+ boolean phoneStateFragmentShown = (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED);
+
+ if (externalStorageFragmentShown || localizationFragmentShown ||
+ notificationFragmentShown || notificationsPermissionFragmentShown || batteryOptimFragmentShown || phoneStateFragmentShown) {
+ addSlide(welcomeFragment);
+ if (externalStorageFragmentShown) addSlide(externalStorageFragment);
+ if (localizationFragmentShown) addSlide(localizationFragment);
+ if (notificationsPermissionFragmentShown && notificationsPermissionFragment != null)
+ addSlide(notificationsPermissionFragment);
+ if (notificationFragmentShown) addSlide(notificationFragment);
+ if (batteryOptimFragmentShown) addSlide(batteryOptimFragment);
+ if (phoneStateFragmentShown) addSlide(phoneStateFragment);
+ } else
+ startMainActivity();
+ } else {
addSlide(new AndroidGoSlide());
}
} else {
- addSlide(new BLENotSupportedSlide());
+ addSlide(new BLENotSupportedSlide());
}
}
@@ -169,7 +201,7 @@ static public class NotificationsSlide extends SlideFragment {
@Nullable
@Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Bundle bundle = new Bundle();
bundle.putInt("background_color", R.color.colorintroslide4);
bundle.putInt("buttons_color", R.color.colorintroslide4button);
@@ -209,7 +241,7 @@ static public class BatteryOptimSlide extends SlideFragment {
@Nullable
@Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Bundle bundle = new Bundle();
bundle.putInt("background_color", R.color.colorintroslide5);
bundle.putInt("buttons_color", R.color.colorintroslide5button);
@@ -227,13 +259,10 @@ public void setContext(Context ctx) {
@Override
public boolean hasAnyPermissionsToGrant() {
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- String packageName = mCtx.getPackageName();
- PowerManager pm = (PowerManager) mCtx.getSystemService(POWER_SERVICE);
- return (pm != null && !pm.isIgnoringBatteryOptimizations(packageName));
- }
+ String packageName = mCtx.getPackageName();
+ PowerManager pm = (PowerManager) mCtx.getSystemService(POWER_SERVICE);
+ return (pm != null && !pm.isIgnoringBatteryOptimizations(packageName));
- return false;
}
// Ignore violation of play store content since
@@ -241,15 +270,12 @@ public boolean hasAnyPermissionsToGrant() {
@SuppressLint("BatteryLife")
@Override
public void askForPermissions() {
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- Intent intent = new Intent();
- String packageName = mCtx.getPackageName();
- PowerManager pm = (PowerManager) mCtx.getSystemService(POWER_SERVICE);
- intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- intent.setData(Uri.parse("package:" + packageName));
- getActivity().startActivityForResult(intent, BATTERYOPTIM_REQUEST);
-
- }
+ Intent intent = new Intent();
+ String packageName = mCtx.getPackageName();
+ PowerManager pm = (PowerManager) mCtx.getSystemService(POWER_SERVICE);
+ intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ intent.setData(Uri.parse("package:" + packageName));
+ getActivity().startActivityForResult(intent, BATTERYOPTIM_REQUEST);
}
@Override
diff --git a/app/src/main/java/org/asteroidos/sync/adapters/AppInfoAdapter.java b/app/src/main/java/org/asteroidos/sync/adapters/AppInfoAdapter.java
index 16cf096a..85277576 100644
--- a/app/src/main/java/org/asteroidos/sync/adapters/AppInfoAdapter.java
+++ b/app/src/main/java/org/asteroidos/sync/adapters/AppInfoAdapter.java
@@ -1,5 +1,6 @@
package org.asteroidos.sync.adapters;
+// TODO Handle dubious copyright
// copied from https://github.com/jensstein/oandbackup, used under MIT license
import android.content.Context;
@@ -30,9 +31,10 @@
public class AppInfoAdapter extends ArrayAdapter {
private final static String TAG = AppInfoAdapter.class.getSimpleName();
- private Context context;
- private ArrayList items;
- private int iconSize, layout;
+ private final Context context;
+ private final ArrayList items;
+ private int iconSize;
+ private final int layout;
public AppInfoAdapter(Context context, int layout, ArrayList items) {
super(context, layout, items);
@@ -134,8 +136,8 @@ private static class ViewHolder {
Spinner spinner;
}
- abstract class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
- String packageName;
+ abstract static class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
+ final String packageName;
MyOnItemSelectedListener(String packageName) {
this.packageName = packageName;
@@ -144,7 +146,7 @@ abstract class MyOnItemSelectedListener implements AdapterView.OnItemSelectedLis
private class SeenPackagesFilter extends Filter {
- private List seenPackages;
+ private final List seenPackages;
private SeenPackagesFilter(List seenPackages) {
this.seenPackages = seenPackages;
diff --git a/app/src/main/java/org/asteroidos/sync/asteroid/AsteroidBleManager.java b/app/src/main/java/org/asteroidos/sync/asteroid/AsteroidBleManager.java
index 1ac0a8c2..07550758 100644
--- a/app/src/main/java/org/asteroidos/sync/asteroid/AsteroidBleManager.java
+++ b/app/src/main/java/org/asteroidos/sync/asteroid/AsteroidBleManager.java
@@ -1,16 +1,31 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.asteroid;
-import android.Manifest;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.core.app.ActivityCompat;
import org.asteroidos.sync.connectivity.IConnectivityService;
import org.asteroidos.sync.connectivity.IServiceCallback;
@@ -30,9 +45,9 @@ public class AsteroidBleManager extends BleManager {
public static final String TAG = AsteroidBleManager.class.toString();
@Nullable
public BluetoothGattCharacteristic batteryCharacteristic;
- SynchronizationService mSynchronizationService;
- ArrayList mGattServices;
- public HashMap recvCallbacks;
+ final SynchronizationService mSynchronizationService;
+ final ArrayList mGattServices;
+ public final HashMap recvCallbacks;
public HashMap sendingCharacteristics;
public AsteroidBleManager(@NonNull final Context context, SynchronizationService syncService) {
@@ -64,11 +79,6 @@ public final void abort() {
cancelQueue();
}
- @Override
- protected final void finalize() throws Throwable {
- super.finalize();
- }
-
public final void setBatteryLevel(Data data) {
BatteryLevelEvent batteryLevelEvent = new BatteryLevelEvent();
batteryLevelEvent.battery = Objects.requireNonNull(data.getByte(0)).intValue();
@@ -91,7 +101,6 @@ the characteristics in the isRequiredServiceSupported() function. */
public final boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService batteryService = gatt.getService(AsteroidUUIDS.BATTERY_SERVICE_UUID);
- boolean supported = true;
boolean notify = false;
if (batteryService != null) {
@@ -127,8 +136,7 @@ public final boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gat
});
}
- supported = (batteryCharacteristic != null && notify);
- return supported;
+ return (batteryCharacteristic != null && notify);
}
@Override
@@ -142,20 +150,20 @@ protected final void initialize() {
.enqueue();
setNotificationCallback(batteryCharacteristic).with(((device, data) -> setBatteryLevel(data)));
- // Do not call readCharacteristic(batteryCharacteristic) here.
- // Otherwise, on Android 12 and later, the BLE bond to the watch
- // is lost, and communication no longer works. Arguably, reading
- // and writing should not be done in initialize(), since it is
- // part of the BLE manager's connect() request. Instead, do those
- // IO operations _after_ that request finishes (-> read the
- // characteristic in the SynchronizationService class, which is
- // where the BLE manager's connect() function is called).
+ // Do not call readCharacteristic(batteryCharacteristic) here.
+ // Otherwise, on Android 12 and later, the BLE bond to the watch
+ // is lost, and communication no longer works. Arguably, reading
+ // and writing should not be done in initialize(), since it is
+ // part of the BLE manager's connect() request. Instead, do those
+ // IO operations _after_ that request finishes (-> read the
+ // characteristic in the SynchronizationService class, which is
+ // where the BLE manager's connect() function is called).
enableNotifications(batteryCharacteristic).enqueue();
// Let all services know that we are connected.
try {
mSynchronizationService.syncServices();
- } catch (Exception e){
+ } catch (Exception e) {
e.printStackTrace();
}
}
diff --git a/app/src/main/java/org/asteroidos/sync/asteroid/IAsteroidDevice.java b/app/src/main/java/org/asteroidos/sync/asteroid/IAsteroidDevice.java
index 8645fcc2..3fe92ccf 100644
--- a/app/src/main/java/org/asteroidos/sync/asteroid/IAsteroidDevice.java
+++ b/app/src/main/java/org/asteroidos/sync/asteroid/IAsteroidDevice.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.asteroid;
import org.asteroidos.sync.connectivity.IConnectivityService;
diff --git a/app/src/main/java/org/asteroidos/sync/common/ext/Log.kt b/app/src/main/java/org/asteroidos/sync/common/ext/Log.kt
new file mode 100644
index 00000000..0f3187cd
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/common/ext/Log.kt
@@ -0,0 +1,113 @@
+/*
+ * This file is part of shosetsu & asteroidOS (imported to)
+ *
+ * shosetsu 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.
+ *
+ * shosetsu 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 shosetsu. If not, see .
+ *
+ * 14 / 08 / 2020
+ */
+package org.asteroidos.sync.common.ext
+
+import android.util.Log.*
+import java.io.PrintStream
+
+const val NULL_METHOD_NAME = "UnknownMethod"
+
+var fileOut: PrintStream? = null
+
+const val CRESET: String = "\u001B[0m"
+const val CRED: String = "\u001B[31m"
+
+fun writeT(t: Throwable? = null) {
+ if (t != null)
+ fileOut?.println(t.stackTraceToString())
+}
+
+@Suppress("unused")
+inline fun T.logI(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("i:\t$tag:\t$msg")
+
+ writeT(t)
+
+ return i(tag, msg, t)
+}
+
+@Suppress("unused")
+inline fun T.logD(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("D:\t$tag:\t$msg")
+
+ writeT(t)
+
+ return d(tag, msg, t)
+}
+
+@Suppress("unused")
+inline fun T.logE(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("${CRED}e:\t$tag:\t$msg${CRESET}")
+
+ writeT(t)
+
+ return e(tag, msg, t)
+}
+
+@Suppress("unused")
+inline fun T.logW(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("w:\t$tag:\t$msg")
+
+ writeT(t)
+
+ return w(tag, msg, t)
+}
+
+@Suppress("unused")
+inline fun T.logV(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("v:\t$tag:\t$msg")
+
+ writeT(t)
+
+ return v(tag, msg, t)
+}
+
+@Suppress("unused")
+inline fun T.logWTF(message: String?, t: Throwable? = null): Int {
+ val name = Thread.currentThread().stackTrace[2].methodName ?: NULL_METHOD_NAME
+ val msg = "${name}:\t$message"
+ val tag = T::class.java.simpleName
+
+ fileOut?.println("wtf:\t$tag:\t$msg")
+
+ writeT(t)
+
+ return wtf(tag, msg, t)
+}
+
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/IConnectivityService.java b/app/src/main/java/org/asteroidos/sync/connectivity/IConnectivityService.java
index 9b04436d..728b43d5 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/IConnectivityService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/IConnectivityService.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.connectivity;
import java.util.HashMap;
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/IService.java b/app/src/main/java/org/asteroidos/sync/connectivity/IService.java
index ab989555..03461ab6 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/IService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/IService.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.connectivity;
/**
@@ -9,6 +27,6 @@
* ({@link IService#unsync()}) is called when the watch is disconnected.
*/
public interface IService {
- public void sync();
- public void unsync();
+ void sync();
+ void unsync();
}
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/IServiceCallback.java b/app/src/main/java/org/asteroidos/sync/connectivity/IServiceCallback.java
index 7bd698ce..7d76ec4c 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/IServiceCallback.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/IServiceCallback.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.connectivity;
public interface IServiceCallback {
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/MediaService.java b/app/src/main/java/org/asteroidos/sync/connectivity/MediaService.java
index 787784b7..c50dab0b 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/MediaService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/MediaService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/NotificationService.java b/app/src/main/java/org/asteroidos/sync/connectivity/NotificationService.java
index 18013759..1dcc503c 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/NotificationService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/NotificationService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -34,9 +35,9 @@
public class NotificationService implements IConnectivityService {
public static final String TAG = NotificationService.class.toString();
- private Context mCtx;
- private IAsteroidDevice mDevice;
- private NotificationReceiver mNReceiver;
+ private final Context mCtx;
+ private final IAsteroidDevice mDevice;
+ private final NotificationReceiver mNReceiver;
public NotificationService(Context ctx, IAsteroidDevice device) {
this.mDevice = device;
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/ScreenshotService.java b/app/src/main/java/org/asteroidos/sync/connectivity/ScreenshotService.java
index 90e2d3ac..7cc10748 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/ScreenshotService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/ScreenshotService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -17,6 +18,7 @@
package org.asteroidos.sync.connectivity;
+import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -54,13 +56,12 @@
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-@SuppressWarnings({"FieldCanBeLocal"}) // For clarity, we prefer having NOTIFICATION as a top level field
public class ScreenshotService implements IConnectivityService {
private static final String NOTIFICATION_CHANNEL_ID = "screenshotservice_channel_id_01";
- private int NOTIFICATION = 2726;
+ private final int NOTIFICATION = 2726;
- private Context mCtx;
- private IAsteroidDevice mDevice;
+ private final Context mCtx;
+ private final IAsteroidDevice mDevice;
private ScreenshotReqReceiver mSReceiver;
@@ -71,7 +72,7 @@ public class ScreenshotService implements IConnectivityService {
private byte[] totalData;
private ScheduledExecutorService processUpdate;
- private NotificationManager mNM;
+ private final NotificationManager mNM;
public ScreenshotService(Context ctx, IAsteroidDevice device) {
mDevice = device;
@@ -194,14 +195,14 @@ private Uri createFile(byte[] totalData) throws IOException {
metaInfo.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , metaInfo);
assert imageUri != null;
+ @SuppressLint("Recycle")
OutputStream out = resolver.openOutputStream(imageUri);
- assert out != null;
- try {
+ try (out) {
+ assert out != null;
out.write(totalData);
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
- out.close();
uri = imageUri;
}
} else {
@@ -251,7 +252,6 @@ public void onReceive(Context context, Intent intent) {
mFirstNotify = true;
mDownloading = true;
byte[] data = new byte[1];
- data[0] = 0x0;
mDevice.send(AsteroidUUIDS.SCREENSHOT_REQUEST, data, ScreenshotService.this);
}
}
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/SilentModeService.java b/app/src/main/java/org/asteroidos/sync/connectivity/SilentModeService.java
index 4ba93ad9..d06a5bb6 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/SilentModeService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/SilentModeService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2019 - Justus Tartz
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -27,16 +28,14 @@ public class SilentModeService implements SharedPreferences.OnSharedPreferenceCh
public static final String PREFS_NAME = "AppPreferences";
public static final String PREF_RINGER = "PhoneRingModeOnConnection";
private static final String PREF_ORIG_RINGER = "OriginalRingMode";
- private SharedPreferences prefs;
+ private final SharedPreferences prefs;
private Boolean notificationPref;
- private Context context;
- private AudioManager am;
+ private final AudioManager am;
public SilentModeService(Context con) {
prefs = con.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
- context = con;
prefs.registerOnSharedPreferenceChangeListener(this);
- am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ am = (AudioManager) con.getSystemService(Context.AUDIO_SERVICE);
}
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/TimeService.java b/app/src/main/java/org/asteroidos/sync/connectivity/TimeService.java
index 8254f800..38f3558c 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/TimeService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/TimeService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -41,10 +42,10 @@ public class TimeService implements IConnectivityService, SharedPreferences.OnSh
public static final boolean PREFS_SYNC_TIME_DEFAULT = true;
public static final String TIME_SYNC_INTENT = "org.asteroidos.sync.TIME_SYNC_REQUEST_LISTENER";
- private IAsteroidDevice mDevice;
- private Context mCtx;
+ private final IAsteroidDevice mDevice;
+ private final Context mCtx;
- private SharedPreferences mTimeSyncSettings;
+ private final SharedPreferences mTimeSyncSettings;
private TimeSyncReqReceiver mSReceiver;
private PendingIntent alarmPendingIntent;
@@ -60,12 +61,7 @@ public TimeService(Context ctx, IAsteroidDevice device) {
@Override
public final void sync() {
Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- updateTime();
- }
- }, 500);
+ handler.postDelayed(this::updateTime, 500);
// Register a broadcast handler to use for the alarm Intent
// Also listen for TIME_CHANGED and TIMEZONE_CHANGED events
diff --git a/app/src/main/java/org/asteroidos/sync/connectivity/WeatherService.java b/app/src/main/java/org/asteroidos/sync/connectivity/WeatherService.java
index 115ffc92..733a067a 100644
--- a/app/src/main/java/org/asteroidos/sync/connectivity/WeatherService.java
+++ b/app/src/main/java/org/asteroidos/sync/connectivity/WeatherService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -61,9 +62,9 @@ public class WeatherService implements IConnectivityService {
public static final boolean PREFS_SYNC_WEATHER_DEFAULT = false;
public static final String WEATHER_SYNC_INTENT = "org.asteroidos.sync.WEATHER_SYNC_REQUEST_LISTENER";
- private IAsteroidDevice mDevice;
- private Context mCtx;
- private SharedPreferences mSettings;
+ private final IAsteroidDevice mDevice;
+ private final Context mCtx;
+ private final SharedPreferences mSettings;
private WeatherSyncReqReceiver mSReceiver;
private PendingIntent mAlarmPendingIntent;
@@ -132,12 +133,7 @@ private void updateWeather() {
// We don't have a valid Location yet
// Use the old location until we have a new one, recheck in 2 Minutes
Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- updateWeather();
- }
- }, 1000 * 60 * 2);
+ handler.postDelayed(this::updateWeather, 1000 * 60 * 2);
return;
}
}
diff --git a/app/src/main/java/org/asteroidos/sync/dataobjects/Notification.java b/app/src/main/java/org/asteroidos/sync/dataobjects/Notification.java
index 8dec8636..0b38f517 100644
--- a/app/src/main/java/org/asteroidos/sync/dataobjects/Notification.java
+++ b/app/src/main/java/org/asteroidos/sync/dataobjects/Notification.java
@@ -1,11 +1,29 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.dataobjects;
import java.nio.charset.StandardCharsets;
public class Notification {
String packageName, appName, appIcon, summary, body, vibration = "";
- MsgType msgType = null;
- int id = 0;
+ final MsgType msgType;
+ final int id;
public Notification(MsgType msgType, String packageName, int id, String appName, String appIcon, String summary, String body, String vibration) {
this.msgType = msgType;
diff --git a/app/src/main/java/org/asteroidos/sync/domain/repository/base/MessageRepository.kt b/app/src/main/java/org/asteroidos/sync/domain/repository/base/MessageRepository.kt
new file mode 100644
index 00000000..f2942a70
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/domain/repository/base/MessageRepository.kt
@@ -0,0 +1,82 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.domain.repository.base
+
+import android.bluetooth.BluetoothDevice
+import kotlinx.coroutines.flow.Flow
+import org.asteroidos.sync.domain.repository.impl.MessageRepositoryImpl
+import org.asteroidos.sync.domain.repository.impl.WatchStatusRepositoryImpl
+
+/**
+ * Source of truth for all inter app message communication using flows.
+ */
+interface MessageRepository {
+ /**
+ * Emits when a device is selected
+ */
+ val requestSetDeviceFlow: Flow
+
+ fun requestSetDevice(device: BluetoothDevice)
+
+ /**
+ * Emits when device should be unset
+ */
+ val requestUnsetDeviceFlow: Flow
+
+ fun requestUnsetDevice()
+
+ /**
+ * Emits when a device update is requested
+ */
+ val requestUpdateDeviceFlow: Flow
+
+ fun requestUpdateDevice()
+
+ /**
+ * Emits when a device should be connected to
+ */
+ val requestConnectFlow: Flow
+
+ fun requestConnect()
+
+ /**
+ * Emits when a device should be disconnected from
+ */
+ val requestDisconnectFlow: Flow
+
+ fun requestDisconnect()
+
+ /**
+ * Emits when a battery life update is requested
+ */
+ val requestBatteryLifeFlow: Flow
+
+ fun requestBatteryLife()
+
+ companion object {
+ private var repo: MessageRepository? = null
+
+ fun get(): MessageRepository {
+ if (repo == null)
+ repo = MessageRepositoryImpl()
+
+ return repo!!
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/domain/repository/base/WatchStatusRepository.kt b/app/src/main/java/org/asteroidos/sync/domain/repository/base/WatchStatusRepository.kt
new file mode 100644
index 00000000..18821a6a
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/domain/repository/base/WatchStatusRepository.kt
@@ -0,0 +1,60 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.domain.repository.base
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import org.asteroidos.sync.asteroid.IAsteroidDevice
+import org.asteroidos.sync.asteroid.IAsteroidDevice.ConnectionState
+import org.asteroidos.sync.domain.repository.impl.WatchStatusRepositoryImpl
+
+/**
+ * Source of truth on watch status
+ */
+interface WatchStatusRepository {
+ /**
+ * Battery percentage state
+ */
+ val batteryPercentage: StateFlow
+
+ fun setBatteryPercentage(batteryPercentage: Int)
+
+ /**
+ * Connection state
+ */
+ val connectionState: StateFlow
+ fun setConnectionState(state: ConnectionState)
+
+ /**
+ * Device name
+ */
+ val deviceName: StateFlow
+ fun setDeviceName(name: String)
+
+ companion object {
+ private var repo: WatchStatusRepository? = null
+
+ fun get(): WatchStatusRepository {
+ if (repo == null)
+ repo = WatchStatusRepositoryImpl()
+
+ return repo!!
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/domain/repository/impl/MessageRepositoryImpl.kt b/app/src/main/java/org/asteroidos/sync/domain/repository/impl/MessageRepositoryImpl.kt
new file mode 100644
index 00000000..a9232830
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/domain/repository/impl/MessageRepositoryImpl.kt
@@ -0,0 +1,64 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.domain.repository.impl
+
+import android.bluetooth.BluetoothDevice
+import kotlinx.coroutines.flow.*
+import org.asteroidos.sync.domain.repository.base.MessageRepository
+
+class MessageRepositoryImpl : MessageRepository {
+ private val _requestSetDeviceFlow = MutableStateFlow(null)
+
+ override val requestSetDeviceFlow: Flow =
+ _requestSetDeviceFlow.filterNotNull()
+
+ override fun requestSetDevice(device: BluetoothDevice) {
+ _requestSetDeviceFlow.value = device
+ }
+
+ override val requestUnsetDeviceFlow: MutableStateFlow = MutableStateFlow(0)
+
+ override fun requestUnsetDevice() {
+ requestUnsetDeviceFlow.value = requestUnsetDeviceFlow.value++
+ }
+
+ override val requestUpdateDeviceFlow: MutableStateFlow = MutableStateFlow(0)
+
+ override fun requestUpdateDevice() {
+ requestUpdateDeviceFlow.value = requestUpdateDeviceFlow.value++
+ }
+
+ override val requestConnectFlow: MutableStateFlow = MutableStateFlow(0)
+
+ override fun requestConnect() {
+ requestConnectFlow.value = requestConnectFlow.value++
+ }
+
+ override val requestDisconnectFlow: MutableStateFlow = MutableStateFlow(0)
+
+ override fun requestDisconnect() {
+ requestDisconnectFlow.value = requestDisconnectFlow.value++
+ }
+
+ override val requestBatteryLifeFlow: MutableStateFlow = MutableStateFlow(0)
+
+ override fun requestBatteryLife() {
+ requestBatteryLifeFlow.value = requestBatteryLifeFlow.value++
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/domain/repository/impl/WatchStatusRepositoryImpl.kt b/app/src/main/java/org/asteroidos/sync/domain/repository/impl/WatchStatusRepositoryImpl.kt
new file mode 100644
index 00000000..2c75f372
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/domain/repository/impl/WatchStatusRepositoryImpl.kt
@@ -0,0 +1,44 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.domain.repository.impl
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.asteroidos.sync.asteroid.IAsteroidDevice.ConnectionState
+import org.asteroidos.sync.domain.repository.base.WatchStatusRepository
+
+class WatchStatusRepositoryImpl : WatchStatusRepository {
+
+ override val batteryPercentage: MutableStateFlow = MutableStateFlow(0)
+
+ override fun setBatteryPercentage(batteryPercentage: Int) {
+ this.batteryPercentage.value = batteryPercentage
+ }
+
+ override val connectionState = MutableStateFlow(ConnectionState.STATUS_DISCONNECTED)
+
+ override fun setConnectionState(state: ConnectionState) {
+ connectionState.value = state
+ }
+
+ override val deviceName = MutableStateFlow("")
+
+ override fun setDeviceName(name: String) {
+ deviceName.value = name
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/fragments/AppListFragment.java b/app/src/main/java/org/asteroidos/sync/fragments/AppListFragment.java
index f5356f6f..ee6a5b8c 100644
--- a/app/src/main/java/org/asteroidos/sync/fragments/AppListFragment.java
+++ b/app/src/main/java/org/asteroidos/sync/fragments/AppListFragment.java
@@ -1,13 +1,32 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.fragments;
import android.content.Context;
import android.os.Bundle;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Filter;
import android.widget.ListView;
import org.asteroidos.sync.MainActivity;
@@ -20,7 +39,7 @@ public class AppListFragment extends Fragment {
View placeholder;
@Override
- public void onAttach(Context context) {
+ public void onAttach(@NonNull Context context) {
super.onAttach(context);
adapter = new AppInfoAdapter(context, R.layout.app_list_item, MainActivity.appInfoList);
adapter.restoreFilter();
@@ -37,10 +56,6 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
listView.setAdapter(adapter);
placeholder = view.findViewById(R.id.no_notification_placeholder);
- adapter.getFilter().filter("", new Filter.FilterListener() {
- public void onFilterComplete(int count) {
- placeholder.setVisibility(count == 0 ? View.VISIBLE : View.INVISIBLE);
- }
- });
+ adapter.getFilter().filter("", count -> placeholder.setVisibility(count == 0 ? View.VISIBLE : View.INVISIBLE));
}
}
diff --git a/app/src/main/java/org/asteroidos/sync/fragments/DeviceDetailFragment.java b/app/src/main/java/org/asteroidos/sync/fragments/DeviceDetailFragment.java
index 7894a7f9..981c6b5f 100644
--- a/app/src/main/java/org/asteroidos/sync/fragments/DeviceDetailFragment.java
+++ b/app/src/main/java/org/asteroidos/sync/fragments/DeviceDetailFragment.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
- * Doug Koellmer
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -33,6 +33,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.Fragment;
@@ -56,10 +57,6 @@ public class DeviceDetailFragment extends Fragment {
private SharedPreferences mSilenceModeSettings;
private SharedPreferences mCallStateSettings;
- private CheckBox mTimeSyncCheckBox;
- private CheckBox mSilenceModeCheckBox;
- private CheckBox mCallStateServiceCheckBox;
-
private FloatingActionButton mFab;
private boolean mConnected = false;
@@ -117,7 +114,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
Intent iremove = new Intent("org.asteroidos.sync.NOTIFICATION_LISTENER");
iremove.putExtra("event", "removed");
iremove.putExtra("id", 0xa57e401d);
- getActivity().sendBroadcast(iremove);
+ requireActivity().sendBroadcast(iremove);
Intent ipost = new Intent("org.asteroidos.sync.NOTIFICATION_LISTENER");
ipost.putExtra("event", "posted");
@@ -127,18 +124,18 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
ipost.putExtra("appIcon", "ios-watch-vibrating");
ipost.putExtra("summary", getString(R.string.watch_finder));
ipost.putExtra("body", getString(R.string.phone_is_searching));
- getActivity().sendBroadcast(ipost);
+ requireActivity().sendBroadcast(ipost);
});
CardView screenshotCard = view.findViewById(R.id.card_view3);
- screenshotCard.setOnClickListener(view1 -> getActivity().sendBroadcast(new Intent("org.asteroidos.sync.SCREENSHOT_REQUEST_LISTENER")));
+ screenshotCard.setOnClickListener(view1 -> requireActivity().sendBroadcast(new Intent("org.asteroidos.sync.SCREENSHOT_REQUEST_LISTENER")));
CardView notifSettCard = view.findViewById(R.id.card_view4);
notifSettCard.setOnClickListener(notifSettCardView -> mAppSettingsListener.onAppSettingsClicked());
- mTimeSyncSettings = getActivity().getSharedPreferences(TimeService.PREFS_NAME, 0);
+ mTimeSyncSettings = requireActivity().getSharedPreferences(TimeService.PREFS_NAME, 0);
- mTimeSyncCheckBox = view.findViewById(R.id.timeSyncCheckBox);
+ CheckBox mTimeSyncCheckBox = view.findViewById(R.id.timeSyncCheckBox);
mTimeSyncCheckBox.setChecked(mTimeSyncSettings.getBoolean(TimeService.PREFS_SYNC_TIME, TimeService.PREFS_SYNC_TIME_DEFAULT));
mTimeSyncCheckBox.setOnCheckedChangeListener((ignored, checked) -> {
SharedPreferences.Editor editor = mTimeSyncSettings.edit();
@@ -146,8 +143,8 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
editor.apply();
});
- mSilenceModeSettings = getActivity().getSharedPreferences(SilentModeService.PREFS_NAME, Context.MODE_PRIVATE);
- mSilenceModeCheckBox = view.findViewById(R.id.SilentModeCheckBox);
+ mSilenceModeSettings = requireActivity().getSharedPreferences(SilentModeService.PREFS_NAME, Context.MODE_PRIVATE);
+ CheckBox mSilenceModeCheckBox = view.findViewById(R.id.SilentModeCheckBox);
mSilenceModeCheckBox.setChecked(mSilenceModeSettings.getBoolean(SilentModeService.PREF_RINGER, false));
mSilenceModeCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
SharedPreferences.Editor editor = mSilenceModeSettings.edit();
@@ -155,8 +152,8 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
editor.apply();
});
- mCallStateSettings = getActivity().getSharedPreferences(PhoneStateReceiver.PREFS_NAME, Context.MODE_PRIVATE);
- mCallStateServiceCheckBox = view.findViewById(R.id.CallStateServiceCheckBox);
+ mCallStateSettings = requireActivity().getSharedPreferences(PhoneStateReceiver.PREFS_NAME, Context.MODE_PRIVATE);
+ CheckBox mCallStateServiceCheckBox = view.findViewById(R.id.CallStateServiceCheckBox);
mCallStateServiceCheckBox.setChecked(mCallStateSettings.getBoolean(PhoneStateReceiver.PREF_SEND_CALL_STATE, true));
mCallStateServiceCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
SharedPreferences.Editor editor = mCallStateSettings.edit();
@@ -168,7 +165,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.device_detail_manu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@@ -182,7 +179,7 @@ public boolean onOptionsItemSelected(MenuItem menuItem) {
}
public void setLocalName(String name) {
- getActivity().setTitle(name);
+ requireActivity().setTitle(name);
}
public void setStatus(IAsteroidDevice.ConnectionState status) {
@@ -230,36 +227,36 @@ public void scanningStopped() {
}
@Override
- public void onAttach(Context context) {
+ public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof DeviceDetailFragment.OnDefaultDeviceUnselectedListener)
mDeviceListener = (DeviceDetailFragment.OnDefaultDeviceUnselectedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceDetailFragment.OnDefaultDeviceUnselectedListener");
if (context instanceof DeviceDetailFragment.OnConnectRequestedListener)
mConnectListener = (DeviceDetailFragment.OnConnectRequestedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceDetailFragment.OnConnectRequestedListener");
if (context instanceof DeviceDetailFragment.OnAppSettingsClickedListener)
mAppSettingsListener = (DeviceDetailFragment.OnAppSettingsClickedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceDetailFragment.OnAppSettingsClickedListener");
if (context instanceof DeviceDetailFragment.OnWeatherSettingsClickedListener)
mWeatherSettingsListener = (DeviceDetailFragment.OnWeatherSettingsClickedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceDetailFragment.OnWeatherSettingsClickedListener");
if (context instanceof DeviceDetailFragment.OnUpdateListener)
mUpdateListener = (DeviceDetailFragment.OnUpdateListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceDetailFragment.onUpdateListener");
}
diff --git a/app/src/main/java/org/asteroidos/sync/fragments/DeviceListFragment.java b/app/src/main/java/org/asteroidos/sync/fragments/DeviceListFragment.java
index 8d03ae3b..5e6755ea 100644
--- a/app/src/main/java/org/asteroidos/sync/fragments/DeviceListFragment.java
+++ b/app/src/main/java/org/asteroidos/sync/fragments/DeviceListFragment.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
- * Doug Koellmer
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -29,6 +29,7 @@
import android.widget.ListView;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@@ -109,18 +110,18 @@ public void deviceUndiscovered(BluetoothDevice dev) {
}
@Override
- public void onAttach(Context context) {
+ public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnDefaultDeviceSelectedListener)
mDeviceListener = (OnDefaultDeviceSelectedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceListFragment.OnDeviceSelectedListener");
if (context instanceof OnScanRequestedListener)
mScanListener = (OnScanRequestedListener) context;
else
- throw new ClassCastException(context.toString()
+ throw new ClassCastException(context
+ " does not implement DeviceListFragment.OnScanRequestedListener");
}
@@ -144,7 +145,7 @@ private class LeDeviceListAdapter extends BaseAdapter {
LeDeviceListAdapter() {
super();
- mLeDevices = new ArrayList();
+ mLeDevices = new ArrayList<>();
mInflator = requireActivity().getLayoutInflater();
}
diff --git a/app/src/main/java/org/asteroidos/sync/fragments/WeatherSettingsFragment.java b/app/src/main/java/org/asteroidos/sync/fragments/WeatherSettingsFragment.java
index fb0fc387..61c42cd9 100644
--- a/app/src/main/java/org/asteroidos/sync/fragments/WeatherSettingsFragment.java
+++ b/app/src/main/java/org/asteroidos/sync/fragments/WeatherSettingsFragment.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.fragments;
import android.Manifest;
@@ -5,12 +23,16 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
+
import android.os.Bundle;
+
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
+
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -19,7 +41,6 @@
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.EditText;
import org.asteroidos.sync.R;
@@ -27,6 +48,7 @@
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
+import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
@@ -46,7 +68,7 @@ public class WeatherSettingsFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {
- mSettings = getContext().getSharedPreferences(WeatherService.PREFS_NAME, 0);
+ mSettings = requireActivity().getSharedPreferences(WeatherService.PREFS_NAME, 0);
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_position_picker, parent, false);
@@ -62,64 +84,58 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
mMapView = view.findViewById(R.id.map);
mMapView.setTileSource(TileSourceFactory.MAPNIK);
mMapView.setMultiTouchControls(true);
- mMapView.setBuiltInZoomControls(false);
+ mMapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
mMapView.setZoomRounding(true);
mMapView.setMaxZoomLevel(13.0);
mMapView.setMinZoomLevel(5.0);
mMapView.getController().setZoom(zoom);
mMapView.getController().setCenter(new GeoPoint(latitude, longitude));
- if (ContextCompat.checkSelfPermission(getActivity(),
+ if (ContextCompat.checkSelfPermission(requireActivity(),
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(getActivity(),
+ ActivityCompat.requestPermissions(requireActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
WEATHER_LOCATION_PERMISSION_REQUEST);
} else {
- MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(getContext()),mMapView);
+ MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(requireContext()), mMapView);
mLocationOverlay.enableMyLocation();
mMapView.getOverlays().add(mLocationOverlay);
}
mButton = view.findViewById(R.id.positionPickerButton);
- mButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- IGeoPoint center = mMapView.getMapCenter();
-
- float latitude = (float) center.getLatitude();
- float longitude = (float) center.getLongitude();
- float zoom = (float) mMapView.getZoomLevelDouble();
-
- SharedPreferences.Editor editor = mSettings.edit();
- editor.putFloat(WeatherService.PREFS_LATITUDE, latitude);
- editor.putFloat(WeatherService.PREFS_LONGITUDE, longitude);
- editor.putFloat(WeatherService.PREFS_ZOOM, zoom);
- editor.apply();
+ mButton.setOnClickListener(v -> {
+ IGeoPoint center = mMapView.getMapCenter();
- // Update the Weather after changing it
- getActivity().sendBroadcast(new Intent(WeatherService.WEATHER_SYNC_INTENT));
+ float latitude1 = (float) center.getLatitude();
+ float longitude1 = (float) center.getLongitude();
+ float zoom1 = (float) mMapView.getZoomLevelDouble();
- getActivity().onBackPressed();
- }
+ SharedPreferences.Editor editor = mSettings.edit();
+ editor.putFloat(WeatherService.PREFS_LATITUDE, latitude1);
+ editor.putFloat(WeatherService.PREFS_LONGITUDE, longitude1);
+ editor.putFloat(WeatherService.PREFS_ZOOM, zoom1);
+ editor.apply();
+
+ // Update the Weather after changing it
+ getActivity().sendBroadcast(new Intent(WeatherService.WEATHER_SYNC_INTENT));
+
+ getActivity().onBackPressed();
});
mWeatherSyncSettings = getActivity().getSharedPreferences(WeatherService.PREFS_NAME, 0);
mWeatherSyncCheckBox = view.findViewById(R.id.autoLocationPickerButton);
mWeatherSyncCheckBox.setChecked(mWeatherSyncSettings.getBoolean(WeatherService.PREFS_SYNC_WEATHER, WeatherService.PREFS_SYNC_WEATHER_DEFAULT));
- mWeatherSyncCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton ignored, boolean checked) {
- if (ContextCompat.checkSelfPermission(getActivity(),
- Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(getActivity(),
- new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
- WEATHER_LOCATION_SYNC_PERMISSION_REQUEST);
- } else {
- handleLocationToggle(mWeatherSyncCheckBox.isChecked());
- }
+ mWeatherSyncCheckBox.setOnCheckedChangeListener((ignored, checked) -> {
+ if (ContextCompat.checkSelfPermission(getActivity(),
+ Manifest.permission.ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(getActivity(),
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
+ WEATHER_LOCATION_SYNC_PERMISSION_REQUEST);
+ } else {
+ handleLocationToggle(mWeatherSyncCheckBox.isChecked());
}
});
@@ -127,7 +143,7 @@ public void onCheckedChanged(CompoundButton ignored, boolean checked) {
}
@Override
- public void onResume(){
+ public void onResume() {
super.onResume();
mMapView.onResume();
}
@@ -139,14 +155,14 @@ public void onPause() {
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.owm_position_picker_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (menuItem.getItemId() == R.id.customApiKey){
+ if (menuItem.getItemId() == R.id.customApiKey) {
View view = View.inflate(getActivity(), R.layout.dialog_api_key, null);
EditText editText = view.findViewById(R.id.apikey);
editText.setText(mOwmKey);
@@ -177,12 +193,12 @@ private void handleLocationToggle(boolean enable) {
editor.putBoolean(WeatherService.PREFS_SYNC_WEATHER, enable);
editor.apply();
mButton.setVisibility(enable ? View.INVISIBLE : View.VISIBLE);
- getActivity().sendBroadcast(new Intent(WeatherService.WEATHER_SYNC_INTENT));
+ requireActivity().sendBroadcast(new Intent(WeatherService.WEATHER_SYNC_INTENT));
}
@Override
public void onRequestPermissionsResult(int requestCode,
- @NonNull String permissions[], @NonNull int[] grantResults) {
+ @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case WEATHER_LOCATION_SYNC_PERMISSION_REQUEST: {
// If request is cancelled, the result arrays are empty.
@@ -198,7 +214,7 @@ public void onRequestPermissionsResult(int requestCode,
case WEATHER_LOCATION_PERMISSION_REQUEST: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(getContext()), mMapView);
+ MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(requireContext()), mMapView);
mLocationOverlay.enableMyLocation();
mMapView.getOverlays().add(mLocationOverlay);
}
diff --git a/app/src/main/java/org/asteroidos/sync/services/AutostartService.java b/app/src/main/java/org/asteroidos/sync/services/AutostartService.java
index 51696df4..1f2aafbf 100644
--- a/app/src/main/java/org/asteroidos/sync/services/AutostartService.java
+++ b/app/src/main/java/org/asteroidos/sync/services/AutostartService.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.services;
import android.content.BroadcastReceiver;
diff --git a/app/src/main/java/org/asteroidos/sync/services/GPSTracker.java b/app/src/main/java/org/asteroidos/sync/services/GPSTracker.java
index b704c7d9..87c94ba5 100644
--- a/app/src/main/java/org/asteroidos/sync/services/GPSTracker.java
+++ b/app/src/main/java/org/asteroidos/sync/services/GPSTracker.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.services;
import android.app.Service;
diff --git a/app/src/main/java/org/asteroidos/sync/services/GenericFileProvider.java b/app/src/main/java/org/asteroidos/sync/services/GenericFileProvider.java
index 6296f2ee..0a04db07 100644
--- a/app/src/main/java/org/asteroidos/sync/services/GenericFileProvider.java
+++ b/app/src/main/java/org/asteroidos/sync/services/GenericFileProvider.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.services;
import androidx.core.content.FileProvider;
diff --git a/app/src/main/java/org/asteroidos/sync/services/NLService.java b/app/src/main/java/org/asteroidos/sync/services/NLService.java
index 73bb5c9e..d8626c73 100644
--- a/app/src/main/java/org/asteroidos/sync/services/NLService.java
+++ b/app/src/main/java/org/asteroidos/sync/services/NLService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -17,7 +18,6 @@
package org.asteroidos.sync.services;
-import android.annotation.TargetApi;
import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -38,6 +38,7 @@
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
public class NLService extends NotificationListenerService {
private NLServiceReceiver nlServiceReceiver;
@@ -160,11 +161,11 @@ public void onNotificationPosted(StatusBarNotification sbn) {
String packageName = sbn.getPackageName();
String[] allowedOngoingApps = {"com.google.android.apps.maps", "org.thoughtcrime.securesms"};
- if((notification.priority < Notification.PRIORITY_DEFAULT) ||
- ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0
- && !Arrays.asList(allowedOngoingApps).contains(packageName)) ||
- (NotificationCompat.getLocalOnly(notification)) ||
- (NotificationCompat.isGroupSummary(notification)))
+ if ((notification.priority < Notification.PRIORITY_DEFAULT) ||
+ ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0
+ && !Arrays.asList(allowedOngoingApps).contains(packageName)) ||
+ (NotificationCompat.getLocalOnly(notification)) ||
+ (NotificationCompat.isGroupSummary(notification)))
return;
NotificationParser notifParser = new NotificationParser(notification);
@@ -178,16 +179,17 @@ public void onNotificationPosted(StatusBarNotification sbn) {
final PackageManager pm = getApplicationContext().getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
appName = pm.getApplicationLabel(ai).toString();
- } catch (PackageManager.NameNotFoundException ignored) {}
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
- if(summary == null) summary = "";
- else summary = summary.trim();
- if(body == null) body = "";
- else body = body.trim();
- if(packageName == null) packageName = "";
- if(appIcon == null) appIcon = "";
+ if (summary == null) summary = "";
+ else summary = summary.trim();
+ if (body == null) body = "";
+ else body = body.trim();
+ if (packageName == null) packageName = "";
+ if (appIcon == null) appIcon = "";
- Intent i = new Intent("org.asteroidos.sync.NOTIFICATION_LISTENER");
+ Intent i = new Intent("org.asteroidos.sync.NOTIFICATION_LISTENER");
i.putExtra("event", "posted");
i.putExtra("packageName", packageName);
i.putExtra("id", id);
@@ -208,7 +210,6 @@ public void onNotificationRemoved(StatusBarNotification sbn) {
}
@Override
- @TargetApi(Build.VERSION_CODES.N)
public void onListenerDisconnected() {
listenerConnected = false;
// Notification listener disconnected - requesting rebind
@@ -227,9 +228,16 @@ public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra("command").equals("refresh")) {
Handler handler = new Handler();
handler.postDelayed(() -> {
- while (!listenerConnected);
+ while (!listenerConnected) {
+ // Sleep the spin
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ Thread.onSpinWait();
+ }else {
+ // Will not delay here, as we can cause the entire UI to freeze
+ }
+ }
StatusBarNotification[] notifs = getActiveNotifications();
- for(StatusBarNotification notif : notifs)
+ for (StatusBarNotification notif : notifs)
onNotificationPosted(notif);
}, 500);
}
diff --git a/app/src/main/java/org/asteroidos/sync/services/PhoneStateReceiver.java b/app/src/main/java/org/asteroidos/sync/services/PhoneStateReceiver.java
index 1edbee17..8daa3e6a 100644
--- a/app/src/main/java/org/asteroidos/sync/services/PhoneStateReceiver.java
+++ b/app/src/main/java/org/asteroidos/sync/services/PhoneStateReceiver.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.services;
import android.app.Activity;
@@ -34,10 +52,11 @@ public void onReceive(Context context, Intent intent) {
}
static class CallStateService extends PhoneStateListener {
- private Context context;
- private SharedPreferences prefs;
+ private final Context context;
+ private final SharedPreferences prefs;
CallStateService(Context con) {
+ super();
context = con;
prefs = con.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
}
diff --git a/app/src/main/java/org/asteroidos/sync/services/SynchronizationService.java b/app/src/main/java/org/asteroidos/sync/services/SynchronizationService.java
index 906caf67..6831fc71 100644
--- a/app/src/main/java/org/asteroidos/sync/services/SynchronizationService.java
+++ b/app/src/main/java/org/asteroidos/sync/services/SynchronizationService.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2016 - Florent Revest
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
*
* 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
@@ -28,11 +29,7 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -51,13 +48,14 @@
import org.asteroidos.sync.connectivity.SilentModeService;
import org.asteroidos.sync.connectivity.TimeService;
import org.asteroidos.sync.connectivity.WeatherService;
+import org.asteroidos.sync.viewmodel.base.SynchronizationServiceModel;
+import org.asteroidos.sync.viewmodel.impl.SynchronizationServiceModelImpl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
import no.nordicsemi.android.ble.observer.ConnectionObserver;
@@ -74,7 +72,6 @@ public class SynchronizationService extends Service implements IAsteroidDevice,
public static final int MSG_UNSET_DEVICE = 9;
private static final String NOTIFICATION_CHANNEL_ID = "synchronizationservice_channel_id_01";
- final Messenger mMessenger = new Messenger(new SynchronizationHandler(this));
private final int NOTIFICATION = 2725;
public BluetoothDevice mDevice;
public int batteryPercentage = 0;
@@ -82,16 +79,18 @@ public class SynchronizationService extends Service implements IAsteroidDevice,
List nonBleServices;
private NotificationManager mNM;
private ConnectionState mState = ConnectionState.STATUS_DISCONNECTED;
- private Messenger replyTo;
private SharedPreferences mPrefs;
private AsteroidBleManager mBleMngr;
+ private final SynchronizationServiceModel model = new SynchronizationServiceModelImpl();
+
final void handleConnect() {
if (mBleMngr == null) {
mBleMngr = new AsteroidBleManager(getApplicationContext(), SynchronizationService.this);
mBleMngr.setConnectionObserver(this);
}
- if (mState == ConnectionState.STATUS_CONNECTED || mState == ConnectionState.STATUS_CONNECTING) return;
+ if (mState == ConnectionState.STATUS_CONNECTED || mState == ConnectionState.STATUS_CONNECTING)
+ return;
mPrefs = getSharedPreferences(MainActivity.PREFS_NAME, Context.MODE_PRIVATE);
String defaultDevMacAddr = mPrefs.getString(MainActivity.PREFS_DEFAULT_MAC_ADDR, "");
@@ -106,9 +105,9 @@ final void handleConnect() {
.retry(3, 200)
.done(device1 -> {
Log.d(TAG, "Connected to " + device1.getName());
- // Now we read the current values of the GATT characteristics,
- // _after_ the connection has been fully established, to avoid
- // connection failures on Android 12 and later.
+ // Now we read the current values of the GATT characteristics,
+ // _after_ the connection has been fully established, to avoid
+ // connection failures on Android 12 and later.
mBleMngr.readCharacteristics();
})
.fail((device2, error) -> Log.e(TAG, "Failed to connect to " + device.getName() +
@@ -135,11 +134,8 @@ final void handleSetDevice(BluetoothDevice device) {
mDevice = device;
try {
String name = mDevice.getName();
- Message answer = Message.obtain(null, MSG_SET_LOCAL_NAME);
- answer.obj = name;
- replyTo.send(answer);
- replyTo.send(Message.obtain(null, MSG_SET_STATUS, mState));
- } catch (RemoteException | SecurityException | NullPointerException ignored) {
+ model.setLocalName(name);
+ } catch (SecurityException | NullPointerException ignored) {
}
editor.putString(MainActivity.PREFS_DEFAULT_LOC_NAME, name);
editor.apply();
@@ -147,10 +143,7 @@ final void handleSetDevice(BluetoothDevice device) {
final void handleUpdateConnectionStatus() {
if (mDevice != null) {
- try {
- replyTo.send(Message.obtain(null, MSG_SET_STATUS, mState));
- } catch (RemoteException | NullPointerException ignored) {
- }
+ model.setConnectionState(mState);
}
}
@@ -288,6 +281,13 @@ public void onCreate() {
handleConnect();
updateNotification();
+
+ model.onConnectRequested(this::handleConnect);
+ model.onDisconnectRequested(this::handleDisconnect);
+ model.onBatteryLifeRequested(this::handleUpdateBatteryPercentageRequest);
+ model.onDeviceSetRequested(this::handleSetDevice);
+ model.onDeviceUnsetRequested(this::handleUnSetDevice);
+ model.onDeviceUpdateRequested(this::handleUpdateConnectionStatus);
}
@Override
@@ -337,7 +337,7 @@ public void onDestroy() {
@Override
public IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
+ return null;
}
@Override
@@ -358,52 +358,15 @@ private void handleUnSetDevice() {
editor.apply();
}
+ public void handleUpdateBatteryPercentageRequest() {
+ AsteroidBleManager.BatteryLevelEvent batteryLevelEvent = new AsteroidBleManager.BatteryLevelEvent();
+ batteryLevelEvent.battery = batteryPercentage;
+ handleUpdateBatteryPercentage(batteryLevelEvent);
+ }
+
public void handleUpdateBatteryPercentage(AsteroidBleManager.BatteryLevelEvent battery) {
Log.d(TAG, "handleBattery: " + battery.battery + "%");
batteryPercentage = battery.battery;
- try {
- if (replyTo != null)
- replyTo.send(Message.obtain(null, MSG_SET_BATTERY_PERCENTAGE, batteryPercentage, 0));
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- static private class SynchronizationHandler extends Handler {
- private final SynchronizationService mService;
-
- SynchronizationHandler(SynchronizationService service) {
- mService = service;
- }
-
- @Override
- public void handleMessage(Message msg) {
- mService.replyTo = msg.replyTo;
-
- switch (msg.what) {
- case MSG_CONNECT:
- mService.handleConnect();
- break;
- case MSG_DISCONNECT:
- mService.handleDisconnect();
- break;
- case MSG_REQUEST_BATTERY_LIFE:
- AsteroidBleManager.BatteryLevelEvent batteryLevelEvent = new AsteroidBleManager.BatteryLevelEvent();
- batteryLevelEvent.battery = mService.batteryPercentage;
- mService.handleUpdateBatteryPercentage(batteryLevelEvent);
- break;
- case MSG_SET_DEVICE:
- mService.handleSetDevice((BluetoothDevice) msg.obj);
- break;
- case MSG_UNSET_DEVICE:
- mService.handleUnSetDevice();
- break;
- case MSG_UPDATE:
- mService.handleUpdateConnectionStatus();
- break;
- default:
- super.handleMessage(msg);
- }
- }
+ model.setBatteryPercentage(batteryPercentage);
}
}
diff --git a/app/src/main/java/org/asteroidos/sync/utils/AppInfo.java b/app/src/main/java/org/asteroidos/sync/utils/AppInfo.java
index eade707e..142889c2 100644
--- a/app/src/main/java/org/asteroidos/sync/utils/AppInfo.java
+++ b/app/src/main/java/org/asteroidos/sync/utils/AppInfo.java
@@ -1,76 +1,80 @@
package org.asteroidos.sync.utils;
+// TODO Handle dubious copyright
// copied from https://github.com/jensstein/oandbackup, used under MIT license
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
+
import androidx.annotation.NonNull;
-public class AppInfo
- implements Comparable, Parcelable
-{
- private String label, packageName;
- private boolean system, installed, checked, disabled;
+public class AppInfo implements Comparable, Parcelable {
+
+ private final String label, packageName;
+ private final boolean system, installed;
+ private boolean checked, disabled;
+
public Bitmap icon;
- AppInfo(String packageName, String label, boolean system, boolean installed)
- {
+ AppInfo(String packageName, String label, boolean system, boolean installed) {
this.label = label;
this.packageName = packageName;
this.system = system;
this.installed = installed;
}
- public String getPackageName()
- {
+
+ public String getPackageName() {
return packageName;
}
- public String getLabel()
- {
+
+ public String getLabel() {
return label;
}
- public void setDisabled(boolean disabled)
- {
+ public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
- public boolean isDisabled()
- {
+
+ public boolean isDisabled() {
return disabled;
}
- public boolean isSystem()
- {
+
+ public boolean isSystem() {
return system;
}
- public int compareTo(@NonNull AppInfo appInfo) { return label.compareToIgnoreCase(appInfo.getLabel()); }
- public String toString()
- {
+
+ public int compareTo(@NonNull AppInfo appInfo) {
+ return label.compareToIgnoreCase(appInfo.getLabel());
+ }
+
+ @NonNull
+ public String toString() {
return label + " : " + packageName;
}
- public int describeContents()
- {
+
+ public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel out, int flags)
- {
+
+ public void writeToParcel(Parcel out, int flags) {
out.writeString(label);
out.writeString(packageName);
- out.writeBooleanArray(new boolean[] {system, installed, checked});
+ out.writeBooleanArray(new boolean[]{system, installed, checked});
out.writeParcelable(icon, flags);
}
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator()
- {
- public AppInfo createFromParcel(Parcel in)
- {
- return new AppInfo (in);
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator<>() {
+ public AppInfo createFromParcel(Parcel in) {
+ return new AppInfo(in);
}
- public AppInfo[] newArray(int size)
- {
+
+ public AppInfo[] newArray(int size) {
return new AppInfo[size];
}
};
- private AppInfo(Parcel in)
- {
+
+ private AppInfo(Parcel in) {
label = in.readString();
packageName = in.readString();
boolean[] bools = new boolean[4];
diff --git a/app/src/main/java/org/asteroidos/sync/utils/AppInfoHelper.java b/app/src/main/java/org/asteroidos/sync/utils/AppInfoHelper.java
index 4ce4f3a2..e3296083 100644
--- a/app/src/main/java/org/asteroidos/sync/utils/AppInfoHelper.java
+++ b/app/src/main/java/org/asteroidos/sync/utils/AppInfoHelper.java
@@ -1,5 +1,24 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.utils;
+// TODO Handle dubious copyright
// copied from https://github.com/jensstein/oandbackup, used under MIT license
import android.content.Context;
@@ -13,7 +32,6 @@
import android.util.Log;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -26,16 +44,12 @@ public static ArrayList getPackageInfo(Context context)
ArrayList list = new ArrayList<>();
PackageManager pm = context.getPackageManager();
List pinfoList = pm.getInstalledPackages(0);
- Collections.sort(pinfoList, pInfoPackageNameComparator);
+ pinfoList.sort(pInfoPackageNameComparator);
// list seemingly starts scrambled on 4.3
for(PackageInfo pinfo : pinfoList)
{
- boolean isSystem = false;
- if((pinfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
- {
- isSystem = true;
- }
+ boolean isSystem = (pinfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Bitmap icon = null;
Drawable apkIcon = pm.getApplicationIcon(pinfo.applicationInfo);
try
@@ -68,11 +82,5 @@ public static ArrayList getPackageInfo(Context context)
}
return list;
}
- private static Comparator pInfoPackageNameComparator = new Comparator()
- {
- public int compare(PackageInfo p1, PackageInfo p2)
- {
- return p1.packageName.compareToIgnoreCase(p2.packageName);
- }
- };
+ private static final Comparator pInfoPackageNameComparator = (p1, p2) -> p1.packageName.compareToIgnoreCase(p2.packageName);
}
diff --git a/app/src/main/java/org/asteroidos/sync/utils/AsteroidUUIDS.java b/app/src/main/java/org/asteroidos/sync/utils/AsteroidUUIDS.java
index 14f9c9ec..7bbdf43d 100644
--- a/app/src/main/java/org/asteroidos/sync/utils/AsteroidUUIDS.java
+++ b/app/src/main/java/org/asteroidos/sync/utils/AsteroidUUIDS.java
@@ -1,3 +1,21 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 .
+ */
+
/* AsteroidOS UUID collection for ble characteristics and watch filtering */
package org.asteroidos.sync.utils;
diff --git a/app/src/main/java/org/asteroidos/sync/utils/NotificationParser.java b/app/src/main/java/org/asteroidos/sync/utils/NotificationParser.java
index 99e55e16..14f1b668 100644
--- a/app/src/main/java/org/asteroidos/sync/utils/NotificationParser.java
+++ b/app/src/main/java/org/asteroidos/sync/utils/NotificationParser.java
@@ -1,7 +1,24 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.utils;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.app.Notification;
import android.graphics.Typeface;
import android.os.Build;
@@ -14,8 +31,6 @@
import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
// Originally from https://github.com/matejdro/PebbleNotificationCenter-Android written by Matej Drobnič under the terms of the GPLv3
@@ -35,7 +50,6 @@ public NotificationParser(Notification notification)
getExtraBigData(notification);
}
- @TargetApi(value = Build.VERSION_CODES.JELLY_BEAN)
private boolean tryParseNatively(Notification notification)
{
Bundle extras = notification.extras;
@@ -101,12 +115,7 @@ private boolean parseMessageStyleNotification(Notification notification, Bundle
summary = "";
List messagesDescending = new ArrayList<>(messagingStyle.getMessages());
- Collections.sort(messagesDescending, new Comparator() {
- @Override
- public int compare(NotificationCompat.MessagingStyle.Message m1, NotificationCompat.MessagingStyle.Message m2) {
- return (int) (m2.getTimestamp() - m1.getTimestamp());
- }
- });
+ messagesDescending.sort((m1, m2) -> (int) (m2.getTimestamp() - m1.getTimestamp()));
StringBuilder sb = new StringBuilder();
body = "";
@@ -114,10 +123,10 @@ public int compare(NotificationCompat.MessagingStyle.Message m1, NotificationCom
for (NotificationCompat.MessagingStyle.Message message : messagesDescending)
{
String sender;
- if (message.getSender() == null)
- sender = formatCharSequence(messagingStyle.getUserDisplayName());
+ if (message.getPerson() == null)
+ sender = formatCharSequence(messagingStyle.getUser().getName());
else
- sender = formatCharSequence(message.getSender());
+ sender = formatCharSequence(message.getPerson().getName());
sb.append(sender);
sb.append(": ");
@@ -130,7 +139,6 @@ public int compare(NotificationCompat.MessagingStyle.Message m1, NotificationCom
return true;
}
- @TargetApi(value = Build.VERSION_CODES.JELLY_BEAN)
private boolean parseInboxNotification(Bundle extras)
{
CharSequence summaryTextSequence = extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT);
@@ -214,7 +222,6 @@ private void getExtraData(Notification notification) {
parseRemoteView(views);
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void getExtraBigData(Notification notification) {
RemoteViews views;
try {
diff --git a/app/src/main/java/org/asteroidos/sync/viewmodel/base/MainActivityViewModel.kt b/app/src/main/java/org/asteroidos/sync/viewmodel/base/MainActivityViewModel.kt
new file mode 100644
index 00000000..32eaf44e
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/viewmodel/base/MainActivityViewModel.kt
@@ -0,0 +1,75 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.viewmodel.base
+
+import android.bluetooth.BluetoothDevice
+import androidx.lifecycle.ViewModel
+import org.asteroidos.sync.asteroid.IAsteroidDevice
+import java.util.function.Consumer
+
+/**
+ * View model for the main activity
+ */
+abstract class MainActivityViewModel : ViewModel() {
+
+ /**
+ * Listen to changes to local name
+ */
+ abstract fun onWatchLocalNameChanged(consumer: Consumer)
+
+ /**
+ * Listen to connection state changes
+ */
+ abstract fun onWatchConnectionStateChanged(consumer: Consumer)
+
+ /**
+ * Listen to battery percentage changes
+ */
+ abstract fun onWatchBatteryPercentageChanged(consumer: Consumer)
+
+ /**
+ * Request the device to be disconnected
+ */
+ abstract fun requestDisconnect()
+
+ /**
+ * Request to connect to the device
+ */
+ abstract fun requestConnect()
+
+ /**
+ * Request an update from the device
+ */
+ abstract fun requestUpdate()
+
+ /**
+ * Request the device to be unset
+ */
+ abstract fun requestUnsetDevice()
+
+ /**
+ * Select device
+ */
+ abstract fun onDefaultDeviceSelected(mDevice: BluetoothDevice)
+
+ /**
+ * Request battery level of the device
+ */
+ abstract fun requestBatteryLevel()
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/viewmodel/base/SynchronizationServiceModel.kt b/app/src/main/java/org/asteroidos/sync/viewmodel/base/SynchronizationServiceModel.kt
new file mode 100644
index 00000000..e699495e
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/viewmodel/base/SynchronizationServiceModel.kt
@@ -0,0 +1,77 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.viewmodel.base
+
+import android.bluetooth.BluetoothDevice
+import androidx.core.util.Consumer
+import kotlinx.coroutines.Runnable
+import org.asteroidos.sync.asteroid.IAsteroidDevice
+import org.asteroidos.sync.asteroid.IAsteroidDevice.ConnectionState
+
+/**
+ * Model for the synchronization service to bind to kotlin flows.
+ * In the future this can be removed.
+ */
+interface SynchronizationServiceModel {
+
+ /**
+ * Listen to connection requests
+ */
+ fun onConnectRequested(consumer: Runnable)
+
+ /**
+ * Listen to disconnect requests
+ */
+ fun onDisconnectRequested(consumer: Runnable)
+
+ /**
+ * Listen to battery life requests
+ */
+ fun onBatteryLifeRequested(consumer: Runnable)
+
+ /**
+ * Listen to device set requests
+ */
+ fun onDeviceSetRequested(consumer: Consumer)
+
+ /**
+ * Listen to device unset requests
+ */
+ fun onDeviceUnsetRequested(consumer: Runnable)
+
+ /**
+ * Listen to device update requests
+ */
+ fun onDeviceUpdateRequested(consumer: Runnable)
+
+ /**
+ * Set the local name
+ */
+ fun setLocalName(name: String)
+
+ /**
+ * Set the device connection state
+ */
+ fun setConnectionState(state: ConnectionState)
+
+ /**
+ * Set the battery percentage
+ */
+ fun setBatteryPercentage(percentage: Int)
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/viewmodel/impl/MainActivityViewModelImpl.kt b/app/src/main/java/org/asteroidos/sync/viewmodel/impl/MainActivityViewModelImpl.kt
new file mode 100644
index 00000000..0abbeb17
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/viewmodel/impl/MainActivityViewModelImpl.kt
@@ -0,0 +1,104 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.viewmodel.impl
+
+import android.bluetooth.BluetoothDevice
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.asteroidos.sync.asteroid.IAsteroidDevice
+import org.asteroidos.sync.common.ext.logV
+import org.asteroidos.sync.domain.repository.base.MessageRepository
+import org.asteroidos.sync.domain.repository.base.WatchStatusRepository
+import org.asteroidos.sync.viewmodel.base.MainActivityViewModel
+import java.util.function.Consumer
+
+/**
+ * Implementation of the main activity view model
+ *
+ * TODO use android DI framework
+ */
+class MainActivityViewModelImpl(
+ private val messageRepo: MessageRepository = MessageRepository.get(),
+ private val watchStatusRepo: WatchStatusRepository = WatchStatusRepository.get()
+) : MainActivityViewModel() {
+
+ override fun onWatchLocalNameChanged(consumer: Consumer) {
+ viewModelScope.launch(Dispatchers.IO) {
+ watchStatusRepo.deviceName.collect {
+ logV("onWatchLocalNameChanged")
+ viewModelScope.launch {
+ consumer.accept(it)
+ }
+ }
+ }
+ }
+
+ override fun onWatchConnectionStateChanged(consumer: Consumer) {
+ viewModelScope.launch(Dispatchers.IO) {
+ watchStatusRepo.connectionState.collect {
+ logV("onWatchConnectionStateChanged")
+ viewModelScope.launch {
+ consumer.accept(it)
+ }
+ }
+ }
+ }
+
+ override fun onWatchBatteryPercentageChanged(consumer: Consumer) {
+ viewModelScope.launch(Dispatchers.IO) {
+ watchStatusRepo.batteryPercentage.collect {
+ logV("onWatchBatteryPercentageChanged")
+ viewModelScope.launch {
+ consumer.accept(it)
+ }
+ }
+ }
+ }
+
+ override fun requestDisconnect() {
+ logV("")
+ messageRepo.requestDisconnect()
+ }
+
+ override fun requestConnect() {
+ logV("")
+ messageRepo.requestConnect()
+ }
+
+ override fun requestUpdate() {
+ logV("")
+ messageRepo.requestUpdateDevice()
+ }
+
+ override fun requestUnsetDevice() {
+ logV("")
+ messageRepo.requestUnsetDevice()
+ }
+
+ override fun onDefaultDeviceSelected(mDevice: BluetoothDevice) {
+ logV("")
+ messageRepo.requestSetDevice(mDevice)
+ }
+
+ override fun requestBatteryLevel() {
+ logV("")
+ messageRepo.requestBatteryLife()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/asteroidos/sync/viewmodel/impl/SynchronizationServiceModelImpl.kt b/app/src/main/java/org/asteroidos/sync/viewmodel/impl/SynchronizationServiceModelImpl.kt
new file mode 100644
index 00000000..1bb6d1d8
--- /dev/null
+++ b/app/src/main/java/org/asteroidos/sync/viewmodel/impl/SynchronizationServiceModelImpl.kt
@@ -0,0 +1,97 @@
+/*
+ * AsteroidOSSync
+ * Copyright (c) 2023 AsteroidOS
+ *
+ * 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 org.asteroidos.sync.viewmodel.impl
+
+import android.bluetooth.BluetoothDevice
+import androidx.core.util.Consumer
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.launch
+import org.asteroidos.sync.asteroid.IAsteroidDevice.ConnectionState
+import org.asteroidos.sync.domain.repository.base.MessageRepository
+import org.asteroidos.sync.domain.repository.base.WatchStatusRepository
+import org.asteroidos.sync.viewmodel.base.SynchronizationServiceModel
+
+class SynchronizationServiceModelImpl(
+ private val messageRepo: MessageRepository = MessageRepository.get(),
+ private val watchStatusRepo: WatchStatusRepository = WatchStatusRepository.get()
+) : SynchronizationServiceModel {
+ private val modelScope = CoroutineScope(Dispatchers.IO)
+
+ override fun onConnectRequested(consumer: Runnable) {
+ modelScope.launch {
+ messageRepo.requestConnectFlow.collect {
+ consumer.run()
+ }
+ }
+ }
+
+ override fun onDisconnectRequested(consumer: Runnable) {
+ modelScope.launch {
+ messageRepo.requestDisconnectFlow.collect {
+ consumer.run()
+ }
+ }
+ }
+
+ override fun onBatteryLifeRequested(consumer: Runnable) {
+ modelScope.launch {
+ messageRepo.requestBatteryLifeFlow.collect {
+ consumer.run()
+ }
+ }
+ }
+
+ override fun onDeviceSetRequested(consumer: Consumer) {
+ modelScope.launch {
+ messageRepo.requestSetDeviceFlow.collect {
+ consumer.accept(it)
+ }
+ }
+ }
+
+ override fun onDeviceUnsetRequested(consumer: Runnable) {
+ modelScope.launch {
+ messageRepo.requestUnsetDeviceFlow.collect {
+ consumer.run()
+ }
+ }
+ }
+
+ override fun onDeviceUpdateRequested(consumer: Runnable) {
+ modelScope.launch {
+ messageRepo.requestUpdateDeviceFlow.collect {
+ consumer.run()
+ }
+ }
+ }
+
+ override fun setLocalName(name: String) {
+ watchStatusRepo.setDeviceName(name)
+ }
+
+ override fun setConnectionState(state: ConnectionState) {
+ watchStatusRepo.setConnectionState(state)
+ }
+
+ override fun setBatteryPercentage(percentage: Int) {
+ watchStatusRepo.setBatteryPercentage(percentage)
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index e1a873fb..5f423d05 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,8 +5,8 @@ buildscript {
google()
}
dependencies {
- classpath("com.android.tools.build:gradle:7.3.0")
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21")
+ classpath("com.android.tools.build:gradle:7.4.1")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10")
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 73cd3fa1..d6c35de1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip