[Sync] Implement APIv2 auto sync using WorkManager.

This commit is contained in:
Kuba Szczodrzyński 2019-11-03 15:01:12 +01:00
parent dcd355851d
commit 07863fed6f
26 changed files with 274 additions and 626 deletions

View File

@ -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()

View File

@ -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">

View File

@ -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 -> {

View File

@ -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)

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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 }

View File

@ -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() {

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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))
}
}
}

View File

@ -0,0 +1,3 @@
package pl.szczodrzynski.edziennik.sync
class AppManagerDetectedEvent(val failedWorkTimestamps: List<Long>)

View File

@ -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));
}
}
});

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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()
}
}

View File

@ -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()));

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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>

View File

@ -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>

View File

@ -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",