mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
* Use wrapper for accessing shared preferences across the app * Use Json kv store for storing place object * Fix tests * Fix test failure * Fix UI tests
251 lines
8.8 KiB
Java
251 lines
8.8 KiB
Java
package fr.free.nrw.commons;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.Application;
|
|
import android.app.NotificationChannel;
|
|
import android.app.NotificationManager;
|
|
import android.content.Context;
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
import android.os.Build;
|
|
import android.os.Process;
|
|
import android.support.annotation.NonNull;
|
|
import android.util.Log;
|
|
|
|
import com.facebook.drawee.backends.pipeline.Fresco;
|
|
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
|
import com.facebook.stetho.Stetho;
|
|
import com.squareup.leakcanary.LeakCanary;
|
|
import com.squareup.leakcanary.RefWatcher;
|
|
import com.tspoon.traceur.Traceur;
|
|
|
|
import org.acra.ACRA;
|
|
import org.acra.ReportingInteractionMode;
|
|
import org.acra.annotation.ReportsCrashes;
|
|
|
|
import java.io.File;
|
|
|
|
import javax.inject.Inject;
|
|
import javax.inject.Named;
|
|
|
|
import fr.free.nrw.commons.auth.SessionManager;
|
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
|
import fr.free.nrw.commons.category.CategoryDao;
|
|
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler;
|
|
import fr.free.nrw.commons.concurrency.ThreadPoolService;
|
|
import fr.free.nrw.commons.contributions.ContributionDao;
|
|
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
|
import fr.free.nrw.commons.kvstore.BasicKvStore;
|
|
import fr.free.nrw.commons.logging.FileLoggingTree;
|
|
import fr.free.nrw.commons.logging.LogUtils;
|
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
|
import fr.free.nrw.commons.upload.FileUtils;
|
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
|
import fr.free.nrw.commons.utils.ContributionUtils;
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
import io.reactivex.schedulers.Schedulers;
|
|
import timber.log.Timber;
|
|
|
|
@ReportsCrashes(
|
|
mailTo = "commons-app-android-private@googlegroups.com",
|
|
mode = ReportingInteractionMode.DIALOG,
|
|
resDialogText = R.string.crash_dialog_text,
|
|
resDialogTitle = R.string.crash_dialog_title,
|
|
resDialogCommentPrompt = R.string.crash_dialog_comment_prompt,
|
|
resDialogOkToast = R.string.crash_dialog_ok_toast
|
|
)
|
|
public class CommonsApplication extends Application {
|
|
@Inject SessionManager sessionManager;
|
|
@Inject DBOpenHelper dbOpenHelper;
|
|
|
|
@Inject @Named("default_preferences") BasicKvStore defaultPrefs;
|
|
@Inject @Named("application_preferences") BasicKvStore applicationPrefs;
|
|
|
|
/**
|
|
* Constants begin
|
|
*/
|
|
public static final int OPEN_APPLICATION_DETAIL_SETTINGS = 1001;
|
|
|
|
public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using [[COM:MOA|Commons Mobile App]]";
|
|
|
|
public static final String FEEDBACK_EMAIL = "commons-app-android@googlegroups.com";
|
|
|
|
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback";
|
|
|
|
public static final String NOTIFICATION_CHANNEL_ID_ALL = "CommonsNotificationAll";
|
|
|
|
/**
|
|
* Constants End
|
|
*/
|
|
|
|
private RefWatcher refWatcher;
|
|
|
|
|
|
/**
|
|
* Used to declare and initialize various components and dependencies
|
|
*/
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
ACRA.init(this);
|
|
if (BuildConfig.DEBUG) {
|
|
//FIXME: Traceur should be disabled for release builds until error fixed
|
|
//See https://github.com/commons-app/apps-android-commons/issues/1877
|
|
Traceur.enableLogging();
|
|
}
|
|
|
|
ApplicationlessInjection
|
|
.getInstance(this)
|
|
.getCommonsApplicationComponent()
|
|
.inject(this);
|
|
|
|
initTimber();
|
|
|
|
// Set DownsampleEnabled to True to downsample the image in case it's heavy
|
|
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
|
|
.setDownsampleEnabled(true)
|
|
.build();
|
|
try {
|
|
Fresco.initialize(this, config);
|
|
} catch (Exception e) {
|
|
Timber.e(e);
|
|
// TODO: Remove when we're able to initialize Fresco in test builds.
|
|
}
|
|
|
|
// Empty temp directory in case some temp files are created and never removed.
|
|
ContributionUtils.emptyTemporaryDirectory();
|
|
|
|
if (BuildConfig.DEBUG && !isRoboUnitTest()) {
|
|
Stetho.initializeWithDefaults(this);
|
|
}
|
|
|
|
createNotificationChannel(this);
|
|
|
|
|
|
if (setupLeakCanary() == RefWatcher.DISABLED) {
|
|
return;
|
|
}
|
|
// Fire progress callbacks for every 3% of uploaded content
|
|
System.setProperty("in.yuvi.http.fluent.PROGRESS_TRIGGER_THRESHOLD", "3.0");
|
|
}
|
|
|
|
/**
|
|
* Plants debug and file logging tree.
|
|
* Timber lets you plant your own logging trees.
|
|
*
|
|
*/
|
|
private void initTimber() {
|
|
boolean isBeta = ConfigUtils.isBetaFlavour();
|
|
String logFileName = isBeta ? "CommonsBetaAppLogs" : "CommonsAppLogs";
|
|
String logDirectory = LogUtils.getLogDirectory(isBeta);
|
|
FileLoggingTree tree = new FileLoggingTree(
|
|
Log.DEBUG,
|
|
logFileName,
|
|
logDirectory,
|
|
1000,
|
|
getFileLoggingThreadPool());
|
|
|
|
Timber.plant(tree);
|
|
Timber.plant(new Timber.DebugTree());
|
|
}
|
|
|
|
public static boolean isRoboUnitTest() {
|
|
return "robolectric".equals(Build.FINGERPRINT);
|
|
}
|
|
|
|
private ThreadPoolService getFileLoggingThreadPool() {
|
|
return new ThreadPoolService.Builder("file-logging-thread")
|
|
.setPriority(Process.THREAD_PRIORITY_LOWEST)
|
|
.setPoolSize(1)
|
|
.setExceptionHandler(new BackgroundPoolExceptionHandler())
|
|
.build();
|
|
}
|
|
|
|
public static void createNotificationChannel(@NonNull Context context) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
NotificationChannel channel = manager.getNotificationChannel(NOTIFICATION_CHANNEL_ID_ALL);
|
|
if (channel == null) {
|
|
channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID_ALL,
|
|
context.getString(R.string.notifications_channel_name_all), NotificationManager.IMPORTANCE_DEFAULT);
|
|
manager.createNotificationChannel(channel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helps in setting up LeakCanary library
|
|
* @return instance of LeakCanary
|
|
*/
|
|
protected RefWatcher setupLeakCanary() {
|
|
if (LeakCanary.isInAnalyzerProcess(this)) {
|
|
return RefWatcher.DISABLED;
|
|
}
|
|
return LeakCanary.install(this);
|
|
}
|
|
|
|
/**
|
|
* Provides a way to get member refWatcher
|
|
*
|
|
* @param context Application context
|
|
* @return application member refWatcher
|
|
*/
|
|
public static RefWatcher getRefWatcher(Context context) {
|
|
CommonsApplication application = (CommonsApplication) context.getApplicationContext();
|
|
return application.refWatcher;
|
|
}
|
|
|
|
/**
|
|
* clears data of current application
|
|
* @param context Application context
|
|
* @param logoutListener Implementation of interface LogoutListener
|
|
*/
|
|
@SuppressLint("CheckResult")
|
|
public void clearApplicationData(Context context, LogoutListener logoutListener) {
|
|
File cacheDirectory = context.getCacheDir();
|
|
File applicationDirectory = new File(cacheDirectory.getParent());
|
|
if (applicationDirectory.exists()) {
|
|
String[] fileNames = applicationDirectory.list();
|
|
for (String fileName : fileNames) {
|
|
if (!fileName.equals("lib")) {
|
|
FileUtils.deleteFile(new File(applicationDirectory, fileName));
|
|
}
|
|
}
|
|
}
|
|
|
|
sessionManager.logout()
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(() -> {
|
|
Timber.d("All accounts have been removed");
|
|
//TODO: fix preference manager
|
|
defaultPrefs.clearAll();
|
|
applicationPrefs.clearAll();
|
|
applicationPrefs.putBoolean("firstrun", false);
|
|
updateAllDatabases();
|
|
logoutListener.onLogoutComplete();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Deletes all tables and re-creates them.
|
|
*/
|
|
private void updateAllDatabases() {
|
|
dbOpenHelper.getReadableDatabase().close();
|
|
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
|
|
|
ModifierSequenceDao.Table.onDelete(db);
|
|
CategoryDao.Table.onDelete(db);
|
|
ContributionDao.Table.onDelete(db);
|
|
BookmarkPicturesDao.Table.onDelete(db);
|
|
BookmarkLocationsDao.Table.onDelete(db);
|
|
}
|
|
|
|
/**
|
|
* Interface used to get log-out events
|
|
*/
|
|
public interface LogoutListener {
|
|
void onLogoutComplete();
|
|
}
|
|
}
|