/*
* Copyright (C) 2013 Simon Vig Therkildsen
*
* 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 net.simonvt.cathode;
import android.accounts.Account;
import android.app.Activity;
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import com.crashlytics.android.Crashlytics;
import dagger.ObjectGraph;
import io.fabric.sdk.android.Fabric;
import javax.inject.Inject;
import net.simonvt.cathode.event.AuthFailedEvent;
import net.simonvt.cathode.event.AuthFailedEvent.OnAuthFailedListener;
import net.simonvt.cathode.jobqueue.JobManager;
import net.simonvt.cathode.remote.ForceUpdateJob;
import net.simonvt.cathode.remote.UpdateShowCounts;
import net.simonvt.cathode.remote.sync.SyncJob;
import net.simonvt.cathode.remote.sync.SyncUserActivity;
import net.simonvt.cathode.remote.sync.movies.SyncAnticipatedMovies;
import net.simonvt.cathode.remote.sync.shows.SyncAnticipatedShows;
import net.simonvt.cathode.remote.upgrade.EnsureSync;
import net.simonvt.cathode.remote.upgrade.UpperCaseGenres;
import net.simonvt.cathode.settings.Accounts;
import net.simonvt.cathode.settings.FirstAiredOffsetPreference;
import net.simonvt.cathode.settings.Settings;
import net.simonvt.cathode.settings.TraktTimestamps;
import net.simonvt.cathode.settings.UpcomingTimePreference;
import net.simonvt.cathode.settings.login.LoginActivity;
import net.simonvt.cathode.ui.HomeActivity;
import net.simonvt.cathode.ui.shows.upcoming.UpcomingSortByPreference;
import net.simonvt.cathode.util.DateUtils;
import net.simonvt.cathode.util.MainHandler;
import timber.log.Timber;
public class CathodeApp extends Application {
private static final int AUTH_NOTIFICATION = 2;
private static final long SYNC_DELAY = 15 * DateUtils.MINUTE_IN_MILLIS;
private static CathodeApp instance;
private SharedPreferences settings;
private ObjectGraph objectGraph;
@Inject JobManager jobManager;
private int homeActivityResumedCount;
private long lastSync;
@Override public void onCreate() {
super.onCreate();
instance = this;
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectAll().permitDiskReads().penaltyLog().build());
} else {
Fabric.with(this, new Crashlytics());
Timber.plant(new CrashlyticsTree());
}
UpcomingSortByPreference.init(this);
UpcomingTimePreference.init(this);
FirstAiredOffsetPreference.init(this);
settings = PreferenceManager.getDefaultSharedPreferences(this);
upgrade();
objectGraph = ObjectGraph.create(Modules.list(this));
objectGraph.inject(this);
AuthFailedEvent.registerListener(authFailedListener);
final boolean isLoggedIn = settings.getBoolean(Settings.TRAKT_LOGGED_IN, false);
if (isLoggedIn) {
Accounts.setupAccount(this);
} else if (!isLoggedIn) {
Accounts.removeAccount(this);
}
registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks() {
@Override public void onActivityResumed(Activity activity) {
if (activity instanceof HomeActivity) {
homeResumed();
}
}
@Override public void onActivityPaused(Activity activity) {
if (activity instanceof HomeActivity) {
homePaused();
}
}
});
}
private Runnable syncRunnable = new Runnable() {
@Override public void run() {
Timber.d("Performing periodic sync");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(CathodeApp.this);
final long lastFullSync = settings.getLong(Settings.LAST_FULL_SYNC, 0);
final long currentTime = System.currentTimeMillis();
if (lastFullSync + 24 * DateUtils.DAY_IN_MILLIS < currentTime) {
jobManager.addJob(new SyncJob());
} else {
jobManager.addJob(new SyncUserActivity());
}
lastSync = System.currentTimeMillis();
MainHandler.postDelayed(this, SYNC_DELAY);
}
};
private void homeResumed() {
homeActivityResumedCount++;
if (homeActivityResumedCount == 1) {
Timber.d("Starting periodic sync");
final long currentTime = System.currentTimeMillis();
if (lastSync + SYNC_DELAY < currentTime) {
syncRunnable.run();
} else {
final long delay = Math.max(SYNC_DELAY - (currentTime - lastSync), 0);
MainHandler.postDelayed(syncRunnable, delay);
}
}
}
private void homePaused() {
homeActivityResumedCount--;
if (homeActivityResumedCount == 0) {
Timber.d("Pausing periodic sync");
MainHandler.removeCallbacks(syncRunnable);
}
}
private void upgrade() {
final int currentVersion = settings.getInt(Settings.VERSION_CODE, -1);
if (currentVersion == -1) {
settings.edit().putInt(Settings.VERSION_CODE, BuildConfig.VERSION_CODE).apply();
return;
}
if (currentVersion != BuildConfig.VERSION_CODE) {
if (currentVersion < 20002) {
Accounts.removeAccount(this);
settings.edit().clear().apply();
}
if (currentVersion < 20501) {
TraktTimestamps.clear(this);
}
if (currentVersion < 21001) {
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new ForceUpdateJob());
}
});
}
if (currentVersion <= 21001) {
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new UpdateShowCounts());
}
});
}
if (currentVersion <= 31001) {
Account account = Accounts.getAccount(this);
if (account != null) {
ContentResolver.setIsSyncable(account, BuildConfig.AUTHORITY_DUMMY_CALENDAR, 1);
ContentResolver.setSyncAutomatically(account, BuildConfig.AUTHORITY_DUMMY_CALENDAR, true);
ContentResolver.addPeriodicSync(account, BuildConfig.AUTHORITY_DUMMY_CALENDAR,
new Bundle(), 12 * DateUtils.HOUR_IN_SECONDS);
}
Accounts.requestCalendarSync(this);
}
if (currentVersion <= 31003) {
settings.edit().remove("showHidden").apply();
}
if (currentVersion <= 37000) {
settings.edit().remove(Settings.START_PAGE).apply();
}
if (currentVersion <= 39003) {
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new SyncAnticipatedShows());
jobManager.addJob(new SyncAnticipatedMovies());
}
});
}
if (currentVersion <= 40102) {
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new EnsureSync());
}
});
}
if (currentVersion <= 40104) {
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new UpperCaseGenres());
}
});
}
MainHandler.post(new Runnable() {
@Override public void run() {
jobManager.addJob(new SyncJob());
}
});
settings.edit().putInt(Settings.VERSION_CODE, BuildConfig.VERSION_CODE).apply();
}
}
private OnAuthFailedListener authFailedListener = new OnAuthFailedListener() {
@Override public void onAuthFailed() {
Timber.i("onAuthFailure");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(CathodeApp.this);
settings.edit().putBoolean(Settings.TRAKT_LOGGED_IN, false).apply();
Intent intent = new Intent(CathodeApp.this, LoginActivity.class);
intent.setAction(HomeActivity.ACTION_LOGIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(CathodeApp.this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(CathodeApp.this) //
.setSmallIcon(R.drawable.ic_noti_error)
.setTicker(getString(R.string.auth_failed))
.setContentTitle(getString(R.string.auth_failed))
.setContentText(getString(R.string.auth_failed_desc))
.setContentIntent(pi)
.setPriority(Notification.PRIORITY_HIGH)
.setAutoCancel(true);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(AUTH_NOTIFICATION, builder.build());
}
};
public static void inject(Context context) {
((CathodeApp) context.getApplicationContext()).objectGraph.inject(context);
}
public static void inject(Context context, Object object) {
((CathodeApp) context.getApplicationContext()).objectGraph.inject(object);
}
}