forked from github/szkolny
[Sync] Implement APIv2 auto sync using WorkManager.
This commit is contained in:
parent
dcd355851d
commit
07863fed6f
@ -162,6 +162,8 @@ dependencies {
|
||||
implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
||||
|
||||
implementation "io.github.wulkanowy:signer-android:0.1.1"
|
||||
|
||||
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -222,10 +222,6 @@
|
||||
|
||||
<service android:name=".Notifier$GetDataRetryService" />
|
||||
|
||||
<service
|
||||
android:name=".sync.SyncService"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/sync_service" />
|
||||
<receiver
|
||||
android:name=".receivers.SzkolnyReceiver"
|
||||
android:exported="true">
|
||||
|
@ -20,10 +20,13 @@ import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.work.Configuration;
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector;
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor;
|
||||
import com.chuckerteam.chucker.api.RetentionManager;
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.FirebaseOptions;
|
||||
@ -55,8 +58,6 @@ import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
import im.wangchao.mhttp.MHttp;
|
||||
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar;
|
||||
@ -66,7 +67,6 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.Iuczniowie;
|
||||
import pl.szczodrzynski.edziennik.data.api.Librus;
|
||||
@ -77,24 +77,32 @@ import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||
import pl.szczodrzynski.edziennik.receivers.JobsCreator;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
|
||||
public class App extends androidx.multidex.MultiDexApplication {
|
||||
public class App extends androidx.multidex.MultiDexApplication implements Configuration.Provider {
|
||||
private static final String TAG = "App";
|
||||
public static int profileId = -1;
|
||||
private Context mContext;
|
||||
|
||||
@Override
|
||||
public Configuration getWorkManagerConfiguration() {
|
||||
return new Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static final int REQUEST_TIMEOUT = 10 * 1000;
|
||||
|
||||
// notifications
|
||||
@ -301,12 +309,11 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
|
||||
//profileLoadById(appSharedPrefs.getInt("current_profile_id", 1));
|
||||
|
||||
JobManager.create(this).addJobCreator(new JobsCreator());
|
||||
if (appConfig.registerSyncEnabled) {
|
||||
SyncJob.schedule(this);
|
||||
SyncWorker.Companion.scheduleNext(this);
|
||||
}
|
||||
else {
|
||||
SyncJob.clear();
|
||||
SyncWorker.Companion.cancelNext(this);
|
||||
}
|
||||
|
||||
db.metadataDao().countUnseen().observeForever(count -> {
|
||||
|
@ -324,4 +324,6 @@ fun String.crc32(): Long {
|
||||
val crc = CRC32()
|
||||
crc.update(toByteArray())
|
||||
return crc.value
|
||||
}
|
||||
}
|
||||
|
||||
fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
|
@ -2,10 +2,7 @@ package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.*
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.*
|
||||
@ -19,6 +16,7 @@ import androidx.core.graphics.ColorUtils
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavOptions
|
||||
import com.danimahardhika.cafebar.CafeBar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.IconicsColor
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.IconicsSize
|
||||
@ -37,11 +35,12 @@ import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncProfileRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
@ -370,7 +369,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
SyncJob.schedule(app)
|
||||
//SyncWorker.scheduleNext(app)
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.appConfig.appBackground != null) {
|
||||
@ -499,7 +498,7 @@ class MainActivity : AppCompatActivity() {
|
||||
profileListEmptyListener()
|
||||
}
|
||||
DRAWER_PROFILE_SYNC_ALL -> {
|
||||
SyncJob.run(app)
|
||||
ApiService.startAndRequest(this, SyncRequest())
|
||||
}
|
||||
else -> {
|
||||
loadTarget(id)
|
||||
@ -569,6 +568,47 @@ class MainActivity : AppCompatActivity() {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncErrorEvent(event: SyncErrorEvent) {
|
||||
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||
if (app.appConfig.dontShowAppManagerDialog)
|
||||
return
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_manager_dialog_title)
|
||||
.setMessage(R.string.app_manager_dialog_text)
|
||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||
try {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
"com.huawei.systemmanager",
|
||||
"com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity"
|
||||
)
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
try {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
"com.asus.mobilemanager",
|
||||
"com.asus.mobilemanager.MainActivity"
|
||||
)
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
startActivity(Intent(android.provider.Settings.ACTION_SETTINGS))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
||||
app.appConfig.dontShowAppManagerDialog = true
|
||||
app.saveConfig("dontShowAppManagerDialog")
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
private fun fragmentToFeature(currentFragment: Int): Int {
|
||||
return when (currentFragment) {
|
||||
|
@ -19,14 +19,11 @@ import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncService;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT;
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
|
||||
import static pl.szczodrzynski.edziennik.sync.SyncService.ACTION_CANCEL;
|
||||
|
||||
public class Notifier {
|
||||
|
||||
@ -127,17 +124,17 @@ public class Notifier {
|
||||
| |__| | (_| | || (_| | | |__| | __/ |_
|
||||
|_____/ \__,_|\__\__,_| \_____|\___|\_*/
|
||||
public Notification notificationGetDataShow(int maxProgress) {
|
||||
Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
/*Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
notificationIntent.setAction(ACTION_CANCEL);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);*/
|
||||
|
||||
getDataNotificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_GET_DATA)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_title))
|
||||
.setContentText(app.getString(R.string.notification_get_data_text))
|
||||
.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.setGroup(GROUP_KEY_GET_DATA)
|
||||
.setOngoing(true)
|
||||
.setProgress(maxProgress, 0, false)
|
||||
@ -209,10 +206,8 @@ public class Notifier {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
SyncJob.run((App) getApplication(), intent.getExtras().getInt("failedProfileId", -1), -1);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
assert notificationManager != null;
|
||||
notificationManager.cancel(ID_GET_DATA_ERROR);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
@ -38,7 +40,6 @@ import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDetailsActivity;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService;
|
||||
|
||||
@ -65,8 +66,8 @@ public class WidgetTimetable extends AppWidgetProvider {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())){
|
||||
SyncJob.run((App) context.getApplicationContext());
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())) {
|
||||
ApiService.Companion.startAndRequest(context, new SyncRequest());
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
@ -39,6 +39,10 @@ class ApiService : Service() {
|
||||
fun start(context: Context) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
}
|
||||
fun startAndRequest(context: Context, request: Any) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
EventBus.getDefault().postSticky(request)
|
||||
}
|
||||
}
|
||||
|
||||
private val app by lazy { applicationContext as App }
|
||||
|
@ -63,7 +63,6 @@ import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification;
|
||||
@ -116,7 +115,6 @@ import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notificati
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_SERVER_MESSAGE;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_TIMETABLE_LESSON_CHANGE;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.REGISTRATION_ENABLED;
|
||||
import static pl.szczodrzynski.edziennik.sync.SyncService.PROFILE_MAX_PROGRESS;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.ns;
|
||||
|
||||
@ -592,12 +590,7 @@ public class Edziennik {
|
||||
}
|
||||
|
||||
public void notifyAndReload() {
|
||||
app.notifier.postAll(null);
|
||||
app.saveConfig();
|
||||
SyncJob.schedule(app);
|
||||
Intent i = new Intent(Intent.ACTION_MAIN)
|
||||
.putExtra("reloadProfileId", -1);
|
||||
app.sendBroadcast(i);
|
||||
// TODO \/
|
||||
|
||||
Intent intent = new Intent(app.getContext(), WidgetTimetable.class);
|
||||
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
@ -751,7 +744,7 @@ public class Edziennik {
|
||||
MaterialDialog progressDialog = new MaterialDialog.Builder(activity)
|
||||
.title(dialogTitle)
|
||||
.content(dialogText)
|
||||
.progress(false, PROFILE_MAX_PROGRESS, false)
|
||||
.progress(false, 110, false)
|
||||
.canceledOnTouchOutside(false)
|
||||
.show();
|
||||
SyncCallback guiSyncCallback = new SyncCallback() {
|
||||
|
@ -11,16 +11,17 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.core.content.FileProvider;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
@ -81,7 +82,7 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncJob.schedule(app);
|
||||
SyncWorker.Companion.scheduleNext(app);
|
||||
if (app.networkUtils.isOnline())
|
||||
{
|
||||
checkUpdate(context, intent);
|
||||
|
@ -1,22 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.receivers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.evernote.android.job.Job;
|
||||
import com.evernote.android.job.JobCreator;
|
||||
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
|
||||
public class JobsCreator implements JobCreator {
|
||||
@Override
|
||||
@Nullable
|
||||
public Job create(@NonNull String tag) {
|
||||
switch (tag) {
|
||||
case SyncJob.TAG:
|
||||
return new SyncJob();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,19 +7,20 @@ package pl.szczodrzynski.edziennik.receivers
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.ServiceCloseRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncProfileRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.TaskCancelRequest
|
||||
|
||||
class SzkolnyReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
context?.startService(Intent(context, ApiService::class.java))
|
||||
context ?: return
|
||||
when (intent?.extras?.getString("task", null)) {
|
||||
"ServiceCloseRequest" -> EventBus.getDefault().post(ServiceCloseRequest())
|
||||
"TaskCancelRequest" -> EventBus.getDefault().post(TaskCancelRequest(intent.extras?.getInt("taskId", -1) ?: return))
|
||||
"SyncRequest" -> EventBus.getDefault().post(SyncRequest())
|
||||
"SyncProfileRequest" -> EventBus.getDefault().post(SyncProfileRequest(intent.extras?.getInt("profileId", -1) ?: return))
|
||||
"AnnouncementsReadRequest" -> EventBus.getDefault().post(AnnouncementsReadRequest(intent.extras?.getInt("profileId", -1) ?: return))
|
||||
"ServiceCloseRequest" -> ApiService.startAndRequest(context, ServiceCloseRequest())
|
||||
"TaskCancelRequest" -> ApiService.startAndRequest(context, TaskCancelRequest(intent.extras?.getInt("taskId", -1) ?: return))
|
||||
"SyncRequest" -> ApiService.startAndRequest(context, SyncRequest())
|
||||
"SyncProfileRequest" -> ApiService.startAndRequest(context, SyncProfileRequest(intent.extras?.getInt("profileId", -1) ?: return))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
class AppManagerDetectedEvent(val failedWorkTimestamps: List<Long>)
|
@ -17,6 +17,9 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncProfileRequest;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType;
|
||||
@ -111,7 +114,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
app.notifier.postAll(profile);
|
||||
app.saveConfig("notifications");*/
|
||||
d(TAG, "Syncing profile " + profile.getId());
|
||||
SyncJob.run(app, -1, profile.getId());
|
||||
ApiService.Companion.startAndRequest(app, new SyncProfileRequest(profile.getId(), null));
|
||||
} else {
|
||||
/*app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message"))
|
||||
.withProfileData(profile.id, profile.name)
|
||||
@ -122,7 +125,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
app.notifier.postAll(profile);
|
||||
app.saveConfig("notifications");*/
|
||||
d(TAG, "Syncing profile " + profile.getId());
|
||||
SyncJob.run(app, -1, profile.getId());
|
||||
ApiService.Companion.startAndRequest(app, new SyncProfileRequest(profile.getId(), null));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,153 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.sync;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
import com.evernote.android.job.Job;
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.evernote.android.job.JobRequest;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class SyncJob extends Job {
|
||||
|
||||
public static final String TAG = "SyncJob";
|
||||
private static int retryCount = 0;
|
||||
|
||||
public static void schedule(App app) {
|
||||
schedule(app, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a SyncJob to be scheduled. Does nothing if it's already scheduled.
|
||||
*/
|
||||
public static void schedule(App app, boolean internetError) {
|
||||
int count = count();
|
||||
if (count > 0) {
|
||||
d(TAG, "Job is already scheduled");
|
||||
return;
|
||||
}
|
||||
if (app.appConfig.registerSyncEnabled) {
|
||||
//Toast.makeText(app, "Scheduling an alarm", Toast.LENGTH_SHORT).show();
|
||||
long timeout = 1000 * app.appConfig.registerSyncInterval;
|
||||
if (internetError) {
|
||||
retryCount++;
|
||||
timeout = 1000 * (30*retryCount*retryCount); // 30sec, 2min, 4min 30sec, 8min, 12min 30sec, ...
|
||||
timeout = Math.min(timeout, 30 * 60 * 1000); // max 30min between retries
|
||||
if (timeout > 1000 * app.appConfig.registerSyncInterval) {
|
||||
timeout = 1000 * app.appConfig.registerSyncInterval;
|
||||
}
|
||||
}
|
||||
|
||||
new JobRequest.Builder(SyncJob.TAG)
|
||||
.setExecutionWindow((long) (timeout - (0.1 * timeout)), (long) (timeout + (0.1 * timeout)))
|
||||
//.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
|
||||
.build()
|
||||
.schedule();
|
||||
if (!internetError) {
|
||||
retryCount = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
public static int count() {
|
||||
Set<JobRequest> jobRequests = JobManager.instance().getAllJobRequestsForTag(SyncJob.TAG);
|
||||
if (App.devMode) {
|
||||
for (JobRequest jobRequest: jobRequests) {
|
||||
d(TAG, "JOBLIST: Found at "+jobRequest.getStartMs()+" - "+jobRequest.getEndMs());
|
||||
}
|
||||
}
|
||||
return jobRequests.size();
|
||||
}
|
||||
public static void clear() {
|
||||
JobManager.instance().cancelAllForTag(SyncJob.TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes every scheduled SyncJob and then reschedules it.
|
||||
*/
|
||||
public static void update(App app) {
|
||||
update(app, false);
|
||||
}
|
||||
public static void update(App app, boolean internetError) {
|
||||
app.debugLogAsync("SyncJob update internetError="+internetError);
|
||||
clear();
|
||||
schedule(app, internetError);
|
||||
}
|
||||
public static void run(App app) {
|
||||
app.debugLogAsync("SyncJob run with no IDs");
|
||||
clear();
|
||||
runService(app, app.getContext(), -1, -1);
|
||||
/*new JobRequest.Builder(SyncJob.TAG)
|
||||
.startNow()
|
||||
.build()
|
||||
.schedule();*/
|
||||
}
|
||||
|
||||
public static void run(App app, int firstProfileId, int targetProfileId) {
|
||||
app.debugLogAsync("SyncJob run with firstProfileId="+firstProfileId+", targetProfileId="+targetProfileId);
|
||||
clear();
|
||||
runService(app, app.getContext(), firstProfileId, targetProfileId);
|
||||
/* PersistableBundleCompat extras = new PersistableBundleCompat();
|
||||
extras.putInt("firstProfileId", firstProfileId);
|
||||
extras.putInt("targetProfileId", targetProfileId);
|
||||
new JobRequest.Builder(SyncJob.TAG)
|
||||
.startNow()
|
||||
.setExtras(extras)
|
||||
.build()
|
||||
.schedule();*/
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected Result onRunJob(@NonNull Params params) {
|
||||
//Log.d(TAG, "Job is running!");
|
||||
|
||||
App app = (App) getContext().getApplicationContext();
|
||||
|
||||
int firstProfileId = params.getExtras().getInt("firstProfileId", -1);
|
||||
int targetProfileId = params.getExtras().getInt("targetProfileId", -1);
|
||||
|
||||
runService(app, getContext(), firstProfileId, targetProfileId);
|
||||
|
||||
return Result.SUCCESS;
|
||||
}
|
||||
|
||||
private static void runService(App app, Context context, int firstProfileId, int targetProfileId) {
|
||||
|
||||
SyncService.firstProfileId = firstProfileId;
|
||||
SyncService.targetProfileId = targetProfileId;
|
||||
|
||||
app.debugLog("SyncJob runService with firstProfileId="+firstProfileId+", targetProfileId="+targetProfileId);
|
||||
|
||||
boolean connected;
|
||||
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (app.appConfig.registerSyncOnlyWifi) {
|
||||
NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
connected = mWifi != null && mWifi.isConnected();
|
||||
}
|
||||
else {
|
||||
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
|
||||
connected = netInfo != null && netInfo.isConnected();
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
app.debugLog("SyncJob cancelling: no internet");
|
||||
update(app, true);
|
||||
}
|
||||
else {
|
||||
SyncService.start(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.sync;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.Notifier.ID_GET_DATA;
|
||||
import static pl.szczodrzynski.edziennik.Notifier.ID_GET_DATA_ERROR;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class SyncService extends Service {
|
||||
public static final String TAG = "SyncService";
|
||||
private App app;
|
||||
public static boolean running = false;
|
||||
private List<Profile> profiles;
|
||||
public static final int PROFILE_MAX_PROGRESS = 110;
|
||||
private Profile profile = null;
|
||||
private int profileId = -1;
|
||||
public static int progress = 0;
|
||||
private int profileProgress = 0;
|
||||
public static int maxProgress;
|
||||
public static int firstProfileId = -1;
|
||||
public static int targetProfileId = -1;
|
||||
public static final String ACTION_CANCEL = "SyncService.ACTION_CANCEL";
|
||||
public static SyncCallback customCallback = null;
|
||||
private static final int PROFILE_TIMEOUT = 40000;
|
||||
|
||||
private Handler timeoutHandler = new Handler();
|
||||
private Runnable timeoutRunnable = new Runnable() {
|
||||
public void run() {
|
||||
if (!running)
|
||||
return;
|
||||
error(AppError.stringErrorCode(app, AppError.CODE_TIMEOUT, ""), profile);
|
||||
finishDownload();
|
||||
}
|
||||
};
|
||||
|
||||
public static void start(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(new Intent(context, SyncService.class));
|
||||
} else {
|
||||
context.startService(new Intent(context, SyncService.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
app = (App) getApplicationContext();
|
||||
app.debugLog("SyncService created");
|
||||
startForeground(ID_GET_DATA, app.notifier.notificationGetDataShow(0));
|
||||
}
|
||||
|
||||
private void reNotify() {
|
||||
//app.notifier.notificationCancel(ID_GET_DATA_ERROR);
|
||||
app.notifier.notificationPost(ID_GET_DATA, app.notifier.notificationGetDataProgress(progress, maxProgress));
|
||||
}
|
||||
private void error(String error, Profile profile) {
|
||||
app.notifier.notificationPost(ID_GET_DATA_ERROR, app.notifier.notificationGetDataError(profile == null ? "" : profile.getName(), error, profile == null ? -1 : profile.getId()));
|
||||
}
|
||||
|
||||
long millisStart;
|
||||
|
||||
private void downloadData() {
|
||||
if (profiles.size() > 0) {
|
||||
profile = profiles.get(0);
|
||||
profileId = profile.getId();
|
||||
app.debugLog("SyncService downloading profileId="+profileId);
|
||||
profiles.remove(0);
|
||||
// mamy profileID wiec nie trzeba nic ładować. DAO musi używać profileId
|
||||
millisStart = System.currentTimeMillis();
|
||||
app.notifier.notificationPost(ID_GET_DATA, app.notifier.notificationGetDataProfile(profile.getName()));
|
||||
app.apiEdziennik.sync(app, SyncService.this, new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
if (customCallback != null)
|
||||
customCallback.onLoginFirst(profileList, loginStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profile) {
|
||||
profileProgress++;
|
||||
progress = profileProgress*PROFILE_MAX_PROGRESS;
|
||||
updateTimeoutHandler();
|
||||
reNotify();
|
||||
app.debugLog("SyncService profileId="+profileId+" done in "+(System.currentTimeMillis() - millisStart)+"ms");
|
||||
if (customCallback != null)
|
||||
customCallback.onSuccess(activityContext, profile);
|
||||
downloadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
error(error.asReadableString(activityContext), profile);
|
||||
if (customCallback != null)
|
||||
customCallback.onError(activityContext, error);
|
||||
if (error.errorCode == AppError.CODE_NO_INTERNET) {
|
||||
finishDownload(CODE_NO_INTERNET); // use finishDownload instead of scheduleNext so it always changes the profile back to previousProfile
|
||||
} else {
|
||||
finishDownload(CODE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
if (customCallback != null)
|
||||
customCallback.onProgress(Math.min(progressStep, PROFILE_MAX_PROGRESS));
|
||||
progress = Math.min(progress+progressStep, (profileProgress+1)*PROFILE_MAX_PROGRESS);
|
||||
reNotify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
if (customCallback != null)
|
||||
customCallback.onActionStarted(stringResId);
|
||||
app.notifier.notificationPost(ID_GET_DATA, app.notifier.notificationGetDataAction(stringResId));
|
||||
}
|
||||
}, profileId);
|
||||
}
|
||||
else {
|
||||
finishDownload();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTimeoutHandler() {
|
||||
timeoutHandler.removeCallbacks(timeoutRunnable);
|
||||
timeoutHandler.postDelayed(timeoutRunnable, PROFILE_TIMEOUT);
|
||||
}
|
||||
|
||||
private static final int CODE_OK = 0;
|
||||
private static final int CODE_ERROR = 1;
|
||||
private static final int CODE_NO_INTERNET = 2;
|
||||
private void finishDownload() {
|
||||
finishDownload(CODE_OK);
|
||||
}
|
||||
private void finishDownload(int errorCode) {
|
||||
timeoutHandler.removeCallbacks(timeoutRunnable);
|
||||
|
||||
app.apiEdziennik.notifyAndReload();
|
||||
|
||||
app.debugLog("SyncService finishing with profileId="+profileId);
|
||||
if (errorCode == CODE_OK) {
|
||||
app.notifier.notificationCancel(ID_GET_DATA_ERROR);
|
||||
}
|
||||
SyncJob.update((App) getApplication(), errorCode == CODE_NO_INTERNET);
|
||||
stopSelf();
|
||||
if (customCallback != null && errorCode == CODE_OK) {
|
||||
customCallback.onSuccess(null, null);
|
||||
}
|
||||
customCallback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
d(TAG, "Got an intent. Service is running "+running);
|
||||
if (intent != null && intent.getAction() != null && intent.getAction().equals(ACTION_CANCEL)) {
|
||||
d(TAG, "ACTION_CANCEL intent");
|
||||
finishDownload();
|
||||
running = true;
|
||||
}
|
||||
|
||||
if (running) {
|
||||
app.debugLog("SyncService already running; return");
|
||||
return Service.START_STICKY;
|
||||
}
|
||||
running = true;
|
||||
|
||||
timeoutHandler.postDelayed(timeoutRunnable, PROFILE_TIMEOUT);
|
||||
|
||||
profiles = app.db.profileDao().getProfilesForSyncNow();
|
||||
|
||||
app.debugLog("SyncService source profileList="+ Arrays.toString(profiles.toArray())+". firstProfileId="+firstProfileId+", targetProfileId="+targetProfileId);
|
||||
|
||||
if (profiles.size() == 0) {
|
||||
stopSelf();
|
||||
return Service.START_STICKY;
|
||||
}
|
||||
|
||||
if (firstProfileId != -1) {
|
||||
d(TAG, "Profile list from first "+firstProfileId);
|
||||
Collection<Profile> toRemove = new ArrayList<>();
|
||||
for (Profile profile: profiles) {
|
||||
if (firstProfileId == profile.getId()) {
|
||||
break;
|
||||
}
|
||||
toRemove.add(profile);
|
||||
}
|
||||
profiles.removeAll(toRemove);
|
||||
firstProfileId = -1;
|
||||
}
|
||||
if (targetProfileId != -1) {
|
||||
d(TAG, "Profile list only target "+targetProfileId);
|
||||
Profile targetProfile = null;
|
||||
for (Profile profile: profiles) {
|
||||
if (targetProfileId == profile.getId()) {
|
||||
targetProfile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
profiles.clear();
|
||||
if (targetProfile != null)
|
||||
profiles.add(targetProfile);
|
||||
targetProfileId = -1;
|
||||
}
|
||||
|
||||
app.debugLog("SyncService target profileList="+ Arrays.toString(profiles.toArray()));
|
||||
|
||||
progress = 0;
|
||||
profileProgress = 0;
|
||||
maxProgress = profiles.size()*PROFILE_MAX_PROGRESS;
|
||||
|
||||
app.notifier.notificationPost(ID_GET_DATA, app.notifier.notificationGetDataShow(maxProgress));
|
||||
|
||||
if (!app.networkUtils.isOnline()) {
|
||||
app.debugLog("SyncService no internet; update,stop");
|
||||
error(AppError.stringErrorCode(app, AppError.CODE_NO_INTERNET, ""), profiles.size() >= 1 ? profiles.get(0) : null);
|
||||
SyncJob.update((App) getApplication(), true);
|
||||
if (customCallback != null) {
|
||||
customCallback.onError(getApplicationContext(), new AppError(TAG, 241, AppError.CODE_NO_INTERNET, null, (Throwable) null));
|
||||
}
|
||||
stopSelf();
|
||||
return Service.START_STICKY;
|
||||
}
|
||||
|
||||
downloadData();
|
||||
|
||||
return Service.START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
app.debugLog("SyncService destroyed");
|
||||
running = false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.AsyncTask
|
||||
import androidx.work.*
|
||||
import androidx.work.impl.WorkManagerImpl
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest
|
||||
import pl.szczodrzynski.edziennik.formatDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SyncWorker(val context: Context, val params: WorkerParameters) : Worker(context, params) {
|
||||
companion object {
|
||||
const val TAG = "SyncWorker"
|
||||
|
||||
/**
|
||||
* Schedule the sync job only if it's not already scheduled.
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun scheduleNext(app: App) {
|
||||
AsyncTask.execute {
|
||||
val workManager = WorkManager.getInstance(app) as WorkManagerImpl
|
||||
val scheduledWork = workManager.workDatabase.workSpecDao().scheduledWork
|
||||
scheduledWork.forEach {
|
||||
d(TAG, "Work: ${it.id} at ${(it.periodStartTime+it.initialDelay).formatDate()}. State = ${it.state} (finished = ${it.state.isFinished})")
|
||||
}
|
||||
// remove finished work and other than SyncWorker
|
||||
scheduledWork.removeAll { it.workerClassName != SyncWorker::class.java.canonicalName || it.isPeriodic || it.state.isFinished }
|
||||
d(TAG, "Found ${scheduledWork.size} unfinished work")
|
||||
// remove all enqueued work that had to (but didn't) run at some point in the past (at least 1min ago)
|
||||
val failedWork = scheduledWork.filter { it.state == WorkInfo.State.ENQUEUED && it.periodStartTime+it.initialDelay < System.currentTimeMillis() - 1*MINUTE*1000 }
|
||||
d(TAG, "${failedWork.size} work requests failed to start (out of ${scheduledWork.size} requests)")
|
||||
if (failedWork.isNotEmpty()) {
|
||||
d(TAG, "App Manager detected!")
|
||||
EventBus.getDefault().postSticky(AppManagerDetectedEvent(failedWork.map { it.periodStartTime+it.initialDelay }))
|
||||
}
|
||||
if (scheduledWork.size-failedWork.size < 1) {
|
||||
d(TAG, "No pending work found, scheduling next:")
|
||||
rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any existing sync jobs and schedule a new one.
|
||||
*
|
||||
* If [registerSyncEnabled] is not true, just cancel every job.
|
||||
*/
|
||||
fun rescheduleNext(app: App) {
|
||||
cancelNext(app)
|
||||
val enableSync = app.appConfig.registerSyncEnabled
|
||||
if (!enableSync) {
|
||||
return
|
||||
}
|
||||
val onlyWifi = app.appConfig.registerSyncOnlyWifi
|
||||
val syncInterval = app.appConfig.registerSyncInterval.toLong()
|
||||
|
||||
val syncAt = System.currentTimeMillis() + syncInterval*1000
|
||||
d(TAG, "Scheduling work at ${syncAt.formatDate()}")
|
||||
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(
|
||||
if (onlyWifi)
|
||||
NetworkType.UNMETERED
|
||||
else
|
||||
NetworkType.CONNECTED)
|
||||
.build()
|
||||
|
||||
val syncWorkRequest = OneTimeWorkRequestBuilder<SyncWorker>()
|
||||
.setInitialDelay(syncInterval, TimeUnit.SECONDS)
|
||||
.setConstraints(constraints)
|
||||
.addTag(TAG)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance(app).enqueue(syncWorkRequest)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any scheduled sync job.
|
||||
*/
|
||||
fun cancelNext(app: App) {
|
||||
d(TAG, "Cancelling work by tag $TAG")
|
||||
WorkManager.getInstance(app).cancelAllWorkByTag(TAG)
|
||||
//WorkManager.getInstance(app).pruneWork() // do not prune the work in order to look for failed tasks
|
||||
}
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
d(TAG, "Running worker ID ${params.id}")
|
||||
ApiService.startAndRequest(context, SyncRequest())
|
||||
rescheduleNext(context as App)
|
||||
return Result.success()
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import androidx.annotation.PluralsRes;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
@ -34,19 +35,13 @@ import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import kotlin.Pair;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.AnnouncementsReadRequest;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncProfileRequest;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
@ -67,8 +62,6 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.UPDATES_ON_PLAY_STORE;
|
||||
import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_GRADES;
|
||||
import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_HOME;
|
||||
import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_MESSAGES;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER2_FINAL;
|
||||
@ -76,7 +69,6 @@ import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMES
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
private static final String TAG = "HomeFragment";
|
||||
@ -104,55 +96,13 @@ public class HomeFragment extends Fragment {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_HOME, b.refreshLayout);
|
||||
});*/
|
||||
/*b.refreshLayout.setOnTouchListener((v, event) -> {
|
||||
d(TAG, "event "+event);
|
||||
event.setSource(0x10000000); // set a unique source
|
||||
activity.swipeRefreshLayout.onTouchEvent(event);
|
||||
return true;
|
||||
});*/
|
||||
/*b.refreshLayout.setOnDragListener((v, event) -> {
|
||||
activity.swipeRefreshLayout.onDragEvent(event);
|
||||
return true;
|
||||
});*/
|
||||
b.devMode.setVisibility(App.devMode ? View.VISIBLE : View.GONE);
|
||||
|
||||
b.composeButton.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.composeButton.setOnClickListener((v -> {
|
||||
startActivity(new Intent(activity, MessagesComposeActivity.class));
|
||||
}));
|
||||
|
||||
b.testButton.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.testButton.setOnClickListener((v -> {
|
||||
app.startService(new Intent(app, ApiService.class));
|
||||
}));
|
||||
|
||||
b.test2.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.test2.setOnClickListener((v -> {
|
||||
List<Pair<Integer, Integer>> list = new ArrayList<>();
|
||||
list.add(new Pair<>(DRAWER_ITEM_HOME, 0));
|
||||
EventBus.getDefault().postSticky(new SyncProfileRequest(app.profile.getId(), list));
|
||||
}));
|
||||
|
||||
b.test3.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.test3.setOnClickListener((v -> {
|
||||
List<Pair<Integer, Integer>> list = new ArrayList<>();
|
||||
list.add(new Pair<>(DRAWER_ITEM_MESSAGES, TYPE_SENT));
|
||||
EventBus.getDefault().postSticky(new SyncProfileRequest(app.profile.getId(), list));
|
||||
}));
|
||||
|
||||
b.test4.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.test4.setOnClickListener((v -> {
|
||||
List<Pair<Integer, Integer>> list = new ArrayList<>();
|
||||
list.add(new Pair<>(DRAWER_ITEM_GRADES, 0));
|
||||
EventBus.getDefault().postSticky(new SyncProfileRequest(app.profile.getId(), list));
|
||||
}));
|
||||
|
||||
b.test5.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.test5.setOnClickListener((v -> {
|
||||
EventBus.getDefault().postSticky(new AnnouncementsReadRequest(app.profile.getId()));
|
||||
}));
|
||||
b.pruneWorkButton.setOnClickListener((v -> WorkManager.getInstance(app).pruneWork()));
|
||||
|
||||
//((TextView)v.findViewById(R.id.nextSync)).setText(getString(R.string.next_sync_format,Time.fromMillis(app.appJobs.syncJobTime).getStringHMS()));
|
||||
|
||||
|
@ -48,7 +48,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushConfigActivity;
|
||||
@ -511,6 +511,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.setOnChangeAction((isChecked, tag) -> {
|
||||
app.appConfig.registerSyncOnlyWifi = isChecked;
|
||||
app.saveConfig("registerSyncOnlyWifi");
|
||||
SyncWorker.Companion.rescheduleNext(app);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -532,6 +533,10 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
syncCardIntervalItem.setChecked(app.appConfig.registerSyncEnabled);
|
||||
syncCardIntervalItem.setOnClickAction(() -> {
|
||||
List<CharSequence> intervalNames = new ArrayList<>();
|
||||
if (App.devMode) {
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_seconds, 30));
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_minutes, 5));
|
||||
}
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_minutes, 30));
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_minutes, 45));
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_hours, 1));
|
||||
@ -540,6 +545,10 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_hours, 3));
|
||||
intervalNames.add(HomeFragment.plural(activity, R.plurals.time_till_hours, 4));
|
||||
List<Integer> intervals = new ArrayList<>();
|
||||
if (App.devMode) {
|
||||
intervals.add(30);
|
||||
intervals.add(5 * 60);
|
||||
}
|
||||
intervals.add(30 * 60);
|
||||
intervals.add(45 * 60);
|
||||
intervals.add(60 * 60);
|
||||
@ -564,20 +573,12 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
app.appConfig.registerSyncEnabled = true;
|
||||
// app.appConfig modifications have to surround syncCardIntervalItem and those ifs
|
||||
app.saveConfig("registerSyncInterval", "registerSyncEnabled");
|
||||
SyncJob.clear();
|
||||
SyncJob.schedule(app);
|
||||
SyncWorker.Companion.rescheduleNext(app);
|
||||
return true;
|
||||
})
|
||||
.show();
|
||||
});
|
||||
syncCardIntervalItem.setOnChangeAction((isChecked, tag) -> {
|
||||
if (isChecked) {
|
||||
SyncJob.update(app);
|
||||
}
|
||||
else {
|
||||
SyncJob.clear();
|
||||
}
|
||||
|
||||
if (isChecked && !app.appConfig.registerSyncEnabled) {
|
||||
addCardItem(CARD_SYNC, 1, getSyncCardWifiItem());
|
||||
}
|
||||
@ -586,6 +587,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
}
|
||||
app.appConfig.registerSyncEnabled = isChecked;
|
||||
app.saveConfig("registerSyncEnabled");
|
||||
SyncWorker.Companion.rescheduleNext(app);
|
||||
return true;
|
||||
});
|
||||
items.add(syncCardIntervalItem);
|
||||
|
@ -14,16 +14,18 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
@ -64,8 +66,6 @@ import javax.crypto.ShortBufferException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
|
||||
public class Utils {
|
||||
@ -106,7 +106,7 @@ public class Utils {
|
||||
|
||||
public static void d(String TAG, String message) {
|
||||
if (App.devMode) {
|
||||
Log.d(TAG, message);
|
||||
Log.d("Szkolny/"+TAG, message);
|
||||
//debugLog.add(TAG+": "+message);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package pl.szczodrzynski.edziennik.utils.models;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -115,4 +116,7 @@ public class AppConfig {
|
||||
|
||||
@Nullable
|
||||
public String language = null;
|
||||
|
||||
@NonNull
|
||||
public boolean dontShowAppManagerDialog = false;
|
||||
}
|
||||
|
@ -22,11 +22,12 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getCellsForSize;
|
||||
@ -39,7 +40,7 @@ public class WidgetLuckyNumber extends AppWidgetProvider {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())){
|
||||
SyncJob.run((App) context.getApplicationContext());
|
||||
ApiService.Companion.startAndRequest(context, new SyncRequest());
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
@ -22,9 +22,10 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest;
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
||||
|
||||
public class WidgetNotifications extends AppWidgetProvider {
|
||||
@ -35,7 +36,7 @@ public class WidgetNotifications extends AppWidgetProvider {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())){
|
||||
SyncJob.run((App) context.getApplicationContext());
|
||||
ApiService.Companion.startAndRequest(context, new SyncRequest());
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".HomeFragment">
|
||||
|
||||
@ -31,69 +30,41 @@
|
||||
android:layout_margin="8dp"
|
||||
tools:text="TextView" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/mobidziennikMessagesSwitch"
|
||||
android:layout_margin="8dp"
|
||||
<LinearLayout
|
||||
android:id="@+id/devMode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:text="Zmień moduł wiadomości"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/composeButton"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:visibility="gone"
|
||||
android:text="Compose" />
|
||||
android:orientation="vertical"
|
||||
tools:visibility="visible">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/mobidziennikMessagesSwitch"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Zmień moduł wiadomości" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/testButton"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Start Service"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/test2"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Sync profile - view home"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/test3"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Sync profile - view messages sent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/test4"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Sync profile - view grades"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/test5"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Mark all announcements as read"
|
||||
android:visibility="gone"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/composeButton"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Compose" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/pruneWorkButton"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Prune finished work" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
|
||||
|
@ -978,4 +978,8 @@
|
||||
<string name="edziennik_progress_endpoint_timetable">Pobieranie planu lekcji...</string>
|
||||
<string name="edziennik_progress_endpoint_proposed_grades">Pobieranie ocen proponowanych...</string>
|
||||
<string name="edziennik_progress_endpoint_exams">Pobieranie listy sprawdzianów...</string>
|
||||
<string name="app_manager_dialog_title">Wykryto problem z synchronizacją</string>
|
||||
<string name="app_manager_dialog_text">Na urządzeniu prawdopodobnie zainstalowany jest menedżer aplikacji, który może powodować problemy z synchronizacją automatyczną.\n\nNależy wyłączyć w ustawieniach telefonu optymalizację baterii dla aplikacji Szkolny.eu.\n\nKliknij OK, aby przejść do ustawień telefonu.</string>
|
||||
<string name="dont_ask_again">Nie pytaj ponownie</string>
|
||||
<string name="app_manager_open_failed">Nie udało się otworzyć ustawień</string>
|
||||
</resources>
|
||||
|
@ -34,6 +34,7 @@ buildscript {
|
||||
|
||||
room : "2.2.0-beta01",
|
||||
lifecycle : "2.2.0-alpha04",
|
||||
work : "2.2.0",
|
||||
|
||||
firebase : '17.2.0',
|
||||
firebasemessaging: "20.0.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user