Java tutorial
/* * Copyright (c) 2016 Metin Kale * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.metinkale.prayerapp.vakit.times; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; import android.util.ArraySet; import android.widget.Toast; import com.crashlytics.android.Crashlytics; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; import com.evernote.android.job.Job; import com.evernote.android.job.JobManager; import com.evernote.android.job.JobRequest; import com.koushikdutta.async.future.FutureCallback; import com.koushikdutta.ion.Response; import com.koushikdutta.ion.builder.Builders; import com.metinkale.prayer.R; import com.metinkale.prayerapp.App; import com.metinkale.prayerapp.utils.FastParser; import org.joda.time.LocalDate; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; public class WebTimes extends Times { @NonNull protected Map<String, String> times = new ArrayMap<>(); private String id; private int jobId = -1; private long lastSync; WebTimes(long id) { super(id); App.get().getHandler().post(new Runnable() { @Override public void run() { scheduleJob(); } }); } WebTimes() { super(); App.get().getHandler().post(new Runnable() { @Override public void run() { scheduleJob(); } }); } public static void add(@Nullable Source source, String city, String id, double lat, double lng) { if (source == null || source == Source.Calc) return; long _id = System.currentTimeMillis(); WebTimes t = null; switch (source) { case Diyanet: t = new DiyanetTimes(_id); break; case IGMG: t = new IGMGTimes(_id); break; case Fazilet: t = new FaziletTimes(_id); break; case NVC: t = new NVCTimes(_id); break; case Semerkand: t = new SemerkandTimes(_id); break; case Morocco: t = new MoroccoTimes(_id); break; case Malaysia: t = new MalaysiaTimes(_id); break; case CSV: t = new CSVTimes(_id); break; } if (t == null) return; t.setSource(source); t.setName(city); t.setLat(lat); t.setLng(lng); t.setId(id); t.setSortId(99); t.scheduleJob(); Answers.getInstance().logCustom(new CustomEvent("AddCity").putCustomAttribute("Source", source.name()) .putCustomAttribute("City", city)); } @Override public void delete() { super.delete(); if (jobId != -1) JobManager.instance().cancel(jobId); } @Override public synchronized String getTime(LocalDate date, int time) { return super.getTime(date, time); } String extractLine(String str) { str = str.substring(str.indexOf(">") + 1); str = str.substring(0, str.indexOf("</")); return str; } @Override protected synchronized String _getTime(@NonNull LocalDate date, int time) { String str = times.get(date.toString("yyyy-MM-dd") + "-" + time); if (str == null || str.isEmpty() || str.contains("00:00")) { return "00:00"; } return str.replace("*", ""); } private synchronized void setTime(@NonNull LocalDate date, int time, @NonNull String value) { if (deleted() || value.contains("00:00")) return; times.put(date.toString("yyyy-MM-dd") + "-" + time, value.replace("*", "")); save(); } void setTimes(@NonNull LocalDate date, @NonNull String[] value) { if (deleted()) return; for (int i = 0; i < value.length; i++) { setTime(date, i, value[i]); } } public synchronized String getId() { return id; } public synchronized void setId(String id) { this.id = id; save(); } public void syncAsync() { cleanTimes(); if (!App.isOnline()) { Toast.makeText(App.get(), R.string.no_internet, Toast.LENGTH_SHORT).show(); return; } if (getId() == null) return; Builders.Any.F[] builders = createIonBuilder(); for (Builders.Any.F builder : builders) { builder.asString().withResponse().setCallback(new FutureCallback<Response<String>>() { @Override public void onCompleted(Exception e, final Response<String> result) { if (e != null) { //Crashlytics.setString("WebTimesSource", getSource().toString()); //Crashlytics.setString("WebTimesName", getName()); //Crashlytics.setString("WebTimesId", getId()); //Crashlytics.logException(e); return; } try { parseResult(result.getResult()); } catch (Exception ee) { Crashlytics.setString("WebTimesSource", getSource().toString()); Crashlytics.setString("WebTimesName", getName()); Crashlytics.setString("WebTimesId", getId()); Crashlytics.logException(ee); } notifyOnUpdated(); } }); } } protected Builders.Any.F[] createIonBuilder() { return new Builders.Any.F[0]; } protected boolean parseResult(String result) { return true; } private int getSyncedDays() { LocalDate date = LocalDate.now().plusDays(1); int i = 0; while (i < 45) { String prefix = date.toString("yyyy-MM-dd") + "-"; String times[] = { this.times.get(prefix + 0), this.times.get(prefix + 1), this.times.get(prefix + 2), this.times.get(prefix + 3), this.times.get(prefix + 4), this.times.get(prefix + 5) }; for (String time : times) { if (time == null || time.contains("00:00")) return i; } i++; date = date.plusDays(1); } return i; } @NonNull public LocalDate getFirstSyncedDay() { LocalDate date = LocalDate.now(); int i = 0; while (true) { String prefix = date.toString("yyyy-MM-dd") + "-"; String times[] = { this.times.get(prefix + 0), this.times.get(prefix + 1), this.times.get(prefix + 2), this.times.get(prefix + 3), this.times.get(prefix + 4), this.times.get(prefix + 5) }; for (String time : times) { if (time == null || time.contains("00:00") || i > this.times.size()) return date.plusDays(1); } i++; date = date.minusDays(1); } } @NonNull public LocalDate getLastSyncedDay() { LocalDate date = LocalDate.now(); int i = 0; while (true) { String prefix = date.toString("yyyy-MM-dd") + "-"; String times[] = { this.times.get(prefix + 0), this.times.get(prefix + 1), this.times.get(prefix + 2), this.times.get(prefix + 3), this.times.get(prefix + 4), this.times.get(prefix + 5) }; for (String time : times) { if (time == null || time.contains("00:00") || i > this.times.size()) return date.minusDays(1); } i++; date = date.plusDays(1); } } private void scheduleJob() { int syncedDays = getSyncedDays(); if (syncedDays == 0 && System.currentTimeMillis() - lastSync < 1000 * 60 * 60) { lastSync = System.currentTimeMillis(); if (App.isOnline()) syncAsync(); else jobId = new JobRequest.Builder(SyncJob.TAG + getID()) .setExecutionWindow(1, TimeUnit.MINUTES.toMillis(3)) .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) .setBackoffCriteria(TimeUnit.MINUTES.toMillis(3), JobRequest.BackoffPolicy.EXPONENTIAL) .setUpdateCurrent(true).build().schedule(); } else if (syncedDays < 3) jobId = new JobRequest.Builder(SyncJob.TAG + getID()).setExecutionWindow(1, TimeUnit.HOURS.toMillis(3)) .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED).setUpdateCurrent(true) .setBackoffCriteria(TimeUnit.HOURS.toMillis(1), JobRequest.BackoffPolicy.EXPONENTIAL).build() .schedule(); else if (syncedDays < 10) jobId = new JobRequest.Builder(SyncJob.TAG + getID()).setExecutionWindow(1, TimeUnit.DAYS.toMillis(3)) .setBackoffCriteria(TimeUnit.DAYS.toMillis(1), JobRequest.BackoffPolicy.LINEAR) .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED).setRequiresCharging(true) .setUpdateCurrent(true).build().schedule(); else if (syncedDays < 20) jobId = new JobRequest.Builder(SyncJob.TAG + getID()).setExecutionWindow(1, TimeUnit.DAYS.toMillis(10)) .setRequiredNetworkType(JobRequest.NetworkType.UNMETERED) .setBackoffCriteria(TimeUnit.DAYS.toMillis(3), JobRequest.BackoffPolicy.LINEAR) .setUpdateCurrent(true).build().schedule(); } public class SyncJob extends Job { public static final String TAG = "WebTimesSyncJob"; @NonNull @Override protected Result onRunJob(Params params) { if (!App.isOnline()) return Result.RESCHEDULE; syncAsync(); return Result.SUCCESS; } @Override protected void onReschedule(int newJobId) { jobId = newJobId; } } private void cleanTimes() { Set<String> keys = new ArraySet<>(); keys.addAll(times.keySet()); LocalDate date = LocalDate.now(); int y = date.getYear(); int m = date.getMonthOfYear(); for (String key : keys) { int year = FastParser.parseInt(key.substring(0, 4)); if (year < y) keys.remove(key); else if (year == y) { int month = FastParser.parseInt(key.substring(5, 7)); if (month < m) keys.remove(key); } } } }