apps-android-commons/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java
Seán Mac Gillicuddy 942cef5d5e
#3222 Merge master into Structured Data branch, fix conflicts (#3447)
* [WIP] Fixes #2942. Set 'depicts' automatically for images uploaded via 'Nearby'

* Feature/refractor uploads [WIP] (#2887)

* Fix duplicate param information (#2515)

* Bug fix issue #2476 (#2526)

* Added wikidataEntityID in all db versions, handled db.execSql via method runQuery

* Versioning and changelog for v2.10.2 (#2531)

* Update changelog.md

* Versioning for v2.10.2

* Update changelog.md

* Bugfix/issue 2580 (#2584)

* Corrected string placedholders in certain string files

* Corrected string placedholders in certain string files[Bug fix #2580]

* Bug Fix #2585 (#2647)

* Bug Fix #2585
* Added null checks on view in SearchImageFragment when updating views from external sources
* Disposed the disposables in SearchActivity and SearchImageFragment when no longer in active lifecycle

* use FragmentUtils to verify fragment active state

* Bug Fix issue #2648 (#2678)

* Bug Fix issue #2648
* Handled external storage permission before file download

* * Removed redudant check for permission in MediaDetailPagerFragment (Dexter already does that)
* Removed duplicate code in PermissionUtil$checkPermissionsAndPerformAction, used the existing function with conditional extra parameters

* string name typo correction

* BugFix issue #2652 (#2706)

* Addded null check on bookmark before operating on it

* BugFix issue #2711 (#2712)

* Added null checks in OkHttpJsonApiClient$searchImages MwQueryResponse

* BugFix #2718 (#2719)

* Handled null auth cookies

* Fix #2791: NPE when nominating for deletion and leaving screen (#2792)

* Bug Fix issue #2789 (#2790)

* Handled Illegal State Exception for non existent appropriate view parents in ViewUtils$showShortSnackbar

* BugFix #2720 (#2831)

BugFix deprecated licenes #2720

* ui fixes, wip, upload

* *Issue #2886, BugFix #2832[wip]
* updated UploadActivity code
* modified ui
* Updated UploadPresenterTest

* * updated interfaces names to follow names suffixed with Contract
* added test cases

* card view elevation

* view pager disabled swipe

* bug fix, duplicate image

* used existing non-swipable view pager

* Avoid image view resize with keyboard, added adjustPan and stateVisible as softinputMode for UploadActivity

* retain UploadBaseFragment instances on orientation changes

* * Added test cases for UploadMediaPresenter
* Injected io and main thread schedulers

* categories presenter test cased wip

* Added CategoriesPresenter test

* * Added the logic to show open map (with to be uploaded image's coordinates while uploading image)

* codacy suggested changes * added java docs

* Added travis_wait fot android-wait-for-emulator

* ranamed interface onResponseCallback to Callback

* * Added api to delete picture in UploadModel
* cleanUp in UploadModel. once upload has been initiated
* Removed unused methods from UploadModel and the corresponding test class

* * Added tests for UploadPresenter
* Travis suggested changes
* Addded copy previous title and description

* * Made the upload add descriptions visible when keyboard visible
* add description request focus only when user manually requests it

* Added JavaDocs, review suggested changes

* Fix dagger injection

* use DialogUtil to show info in descriptions

* use activity context for DialogUtil

* Minor changes

* refactored title

* ui for depicts

* bug fix

* basic architecture for depicts

* adde architecture components for depicts

* [WIP] ApacheHttpClientMediaWikiApi.wikidataEditEntity: JSON param creation uses object instead of string

* resolved dagger errors

* multilingual captions and next button error resolved

* fixed next button issues in depicts fragment

* captions and depicts

* resolved previous button click issues

* fixed bindview error and added multi-captions

* replaced description and caption with uploadmediadetail

* refactored few classes

* modified ui of depicts

* minor fixes

* Bug fix, reduced the add description edit text clickable bound (#2973)

* moved depicts before categories

* replaced previous filename with captions

* removed time from filename

* added depicts suggestions

* [WIP] Wikidata Sandbox (Q4115189) test

* changes layout of layout_upload_depicts

* changed layout of upload_depicts

* code stuck at IO_SCHEDULER

* labels and description for depicts activity

* Bugfix/uploads (#3000)

* merged with master

* BugFix IllegalStateException
* setRetainState(true), not required with FragmentStatePagerAdapter
* Increase the ViewPager's Offscreen Limit, we want all the fragments to be active

* BugFix, clear selected categoris for previous upload session
* Clear Selected Categories
* Addded JavaDocs for CategoriesModel

* Code Formatting in app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

* Added class level JavaDoc UploadRemoteDataSource

* Added class level JavaDoc for UploadRepository

* Added JavaDocs for ThumbnailsAdapter

* Added JavaDocs for MediaLicensePresenter, CategoriesPresenter

* Removed null check on category query
* Show default catgeories based on image title and gps location when category text empty
* Allow search for empty category search

* Attached image scale listener to upload media image

* Bug fix, reduced the add description edit text clickable bound

* Fix memory leak (#3001)

* Bugfix/uploads (#3002)

* merged with master

* BugFix IllegalStateException
* setRetainState(true), not required with FragmentStatePagerAdapter
* Increase the ViewPager's Offscreen Limit, we want all the fragments to be active

* BugFix, clear selected categoris for previous upload session
* Clear Selected Categories
* Addded JavaDocs for CategoriesModel

* Code Formatting in app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

* Added class level JavaDoc UploadRemoteDataSource

* Added class level JavaDoc for UploadRepository

* Added JavaDocs for ThumbnailsAdapter

* Added JavaDocs for MediaLicensePresenter, CategoriesPresenter

* Removed null check on category query
* Show default catgeories based on image title and gps location when category text empty
* Allow search for empty category search

* Attached image scale listener to upload media image

* Bug fix, reduced the add description edit text clickable bound

* Added tooltip in Title in UploadMediaFragment

* BugFix recent categories

* Updated test methods

* Bugfix/uploads (#3011)

* merged with master

* BugFix IllegalStateException
* setRetainState(true), not required with FragmentStatePagerAdapter
* Increase the ViewPager's Offscreen Limit, we want all the fragments to be active

* BugFix, clear selected categoris for previous upload session
* Clear Selected Categories
* Addded JavaDocs for CategoriesModel

* Code Formatting in app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

* Added class level JavaDoc UploadRemoteDataSource

* Added class level JavaDoc for UploadRepository

* Added JavaDocs for ThumbnailsAdapter

* Added JavaDocs for MediaLicensePresenter, CategoriesPresenter

* Removed null check on category query
* Show default catgeories based on image title and gps location when category text empty
* Allow search for empty category search

* Attached image scale listener to upload media image

* Bug fix, reduced the add description edit text clickable bound

* Added tooltip in Title in UploadMediaFragment

* BugFix recent categories

* Updated test methods

* Avoid memory leak, free the adpater in MediaLicenseFragment.onDestroyView

* bugfix/uploads (#3012)

* merged with master

* BugFix IllegalStateException
* setRetainState(true), not required with FragmentStatePagerAdapter
* Increase the ViewPager's Offscreen Limit, we want all the fragments to be active

* BugFix, clear selected categoris for previous upload session
* Clear Selected Categories
* Addded JavaDocs for CategoriesModel

* Code Formatting in app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

* Added class level JavaDoc UploadRemoteDataSource

* Added class level JavaDoc for UploadRepository

* Added JavaDocs for ThumbnailsAdapter

* Added JavaDocs for MediaLicensePresenter, CategoriesPresenter

* Removed null check on category query
* Show default catgeories based on image title and gps location when category text empty
* Allow search for empty category search

* Attached image scale listener to upload media image

* Bug fix, reduced the add description edit text clickable bound

* Added tooltip in Title in UploadMediaFragment

* BugFix recent categories

* Updated test methods

* Avoid memory leak, free the adpater in MediaLicenseFragment.onDestroyView

* BugFix Illegal State Exception in ViewpPagerAdapter

* Remove irrelevant comment

* merge conflict with strings (#3016)

* [WIP] Fixed duplicated subscriprion for 'addPropertyP180'

* added documentation

* fixed issue #3006

* resolved issue #3004

* fixed issue with categoryPresenterTest.kt

* send captions as labels

* fixed issue with the captions

* optimised imports

* added upload for captions

* minor changes

* resolved issue with uploading captions

* resolved issue with api call

* uploading captions to wikibase

* added some tests and documentation

* undo formatting changes

* uploaded captions as labels to wikibase

* minor changes

* resolved error with spinner adpater

* adding captions to local database

* Fixed issue #3035

* fixed issue #3033

* fixed issue #3005

* fixed issue #3005

* added search for depicts

* fixed issue with compile time

* fixe issue with project build

* fixed issue #3044

* merged uploading depicts into branch

* uploading depicts

* rebased branch

* fixed crash due to depicts

* modified depicts interface

* Resolve merge conflicts

* Fix issues with API calls

* Use wikidata token

* searching depictions from depicts activity

* added some documentation and other changes

* fixed crash on selecting depictions

* sending wikidataentity id to upload depictions

* added changes after review

* Fixed issue with next button diabling in media detail activity

* added tests for depictions

* added all the unit tests and fixed few more issues

* showing captions in media details

* show captions in media details

* added documentations and worked upon review comments

* parsing response for depictions

* displaying captions and depiction QID in media detail

* added documentation

* fetching labels from QIDs

* captions working perfectly

* added documentations and code cleaning

* minor changes

* minor changes

* Showing items in explore

* added search via depicts in explore

* Added setOffscreenPageLimit in ViewPager

* show captions in explore

* show captions in home

* showing depict images under items

* added documentation and code refactoring

* enabled pagination in depiction search

* added some tests and media deatils in depiction detail activity

* fixed bug with back button in media

* fixed issue #3100

* fixed issue #3098

* fixed issue #3099

* fixed issue #3104 and #3098

* showing captions in place of title in home and explore:media

* show captions in explore:depiction image list activity

* showing depictions in media details

* showing depictions in media details in production flavor

* fixed issue #3108 and #3107

* fix isse #3108

* fixed issue #3110 and #3112

* fixed issue #3113

* added documentations

* fixed issue #3076 and #3109

* added depiction search test

* fixed issue #3113

* fixed issue #3111

* fixed issue #3106

* Showing items in explore

* minor change

* fixed issue #3118 and some other changes

* added MVP in searchdepictionsfragment

* added mvp architecture

* added MVP architecture to DepictedImagesDetailsActivity

* added documentation and some minor changes

* added image to depicted item in search depictions

* * Use callbacks from renderer to fetch thumbnails

* adding fresco to load image in depictions

* adding thumbnail image for depictions in upload and explore

* pagination issues

* fixed issue --(showing previous depiction thumbnail in explore)

* Fixed the logic for pagination

* hide progress on success of last page

* adding sub-items and parent items to search in explore

* minor changes for review comments

* fixed issue #3119

* fixed issue #3130

* changes after review comments

* showing child classes for depictions

* Showing child items

* showing parent classes for depicted items

* adding localised search for parent and child items

* clicking on any child class or parent class should call the corresponding class items

* fixed issue of showing wrong thumbnail for P18 item

* fixed issue #3132

* added test for DepictedImagesPresenter.java

* added unit tests for depicted items parent and child classes

* removed unused imports and code formatting

* fixed issue in search test

* deleting unnecessary .attach_pid9313 file

* deleting unnecessary .attach_pid9655 file

* added SearchDepictionsPresenterTest

* changes after review comments

* updates for review comments

* added more documentations

* removed unused code and classes and addressed spacing changes

* changes after review

* fixed build issues in the app

* worked on some review comments

* fixed issue:wrong thumbnail appears on wikidata item

* minor change

* worked on some review changes

* worked on review comments

* minor change

* addressed remaining review comments

* replaced hardcoded jpgs with pageIds to fetch captions

* added documentation

* removed hardcoded extensions and worked on review comments

* review comments

* [WIP] Added Depicts values for flavors

* [WIP] Minor fix

* [WIP] Minor fixes

* [WIP] Fixed URL

* [WIP] Fixed URLs and tokens

* Fixed MediaClient: added check for null in continuation store

* Fixed Media::from, changed return from null to new Media()

* [WIP] Merged with master

* Fix #3254 Displays a proper message in explore section when no result for caption

* Updated Mockito to org.mockito:mockito-inline:2.13.0

* [WIP] Fixed tests after merging

* [WIP] Fixed some JUnit tests

* Fixed 'accessing from wrong thread' error

* #3222 Delete manifest declaration of activity as fragment - stop casting MainActivity to CatgoryImagesCallback - fix tests

* Remove unit test not associated with any class - make CategoryPresenterTest more idiomatic

* fix compilation errors

Co-authored-by: Vitaly V. Pinchuk <vetal.978@gmail.com>
Co-authored-by: Ashish Kumar <ashishkumar468@gmail.com>
Co-authored-by: vanshikaarora <vanshikaa937@gmail.com>
Co-authored-by: Vivek Maskara <maskaravivek@gmail.com>
Co-authored-by: Vanshika Arora <34261945+vanshikaarora@users.noreply.github.com>
Co-authored-by: Somanshu and Himanshu <somanshS14@gmail.com>
2020-03-10 22:30:30 +10:00

329 lines
12 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.database.sqlite.SQLiteException;
import android.os.Build;
import android.os.Process;
import android.util.Log;
import androidx.annotation.NonNull;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.producers.Consumer;
import com.facebook.imagepipeline.producers.FetchState;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.ProducerContext;
import com.mapbox.mapboxsdk.Mapbox;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import org.acra.ACRA;
import org.acra.annotation.AcraCore;
import org.acra.annotation.AcraDialog;
import org.acra.annotation.AcraMailSender;
import org.acra.data.StringFormat;
import org.wikipedia.AppAdapter;
import org.wikipedia.language.AppLanguageLookUpTable;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
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.data.DBOpenHelper;
import fr.free.nrw.commons.db.AppDatabase;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.logging.FileLoggingTree;
import fr.free.nrw.commons.logging.LogUtils;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.FileUtils;
import fr.free.nrw.commons.upload.structure.depictions.DepictionDao;
import fr.free.nrw.commons.utils.ConfigUtils;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.internal.functions.Functions;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import timber.log.Timber;
import static fr.free.nrw.commons.data.DBOpenHelper.CONTRIBUTIONS_TABLE;
import static org.acra.ReportField.ANDROID_VERSION;
import static org.acra.ReportField.APP_VERSION_CODE;
import static org.acra.ReportField.APP_VERSION_NAME;
import static org.acra.ReportField.PHONE_MODEL;
import static org.acra.ReportField.STACK_TRACE;
import static org.acra.ReportField.USER_COMMENT;
@AcraCore(
buildConfigClass = BuildConfig.class,
resReportSendSuccessToast = R.string.crash_dialog_ok_toast,
reportFormat = StringFormat.KEY_VALUE_LIST,
reportContent = {USER_COMMENT, APP_VERSION_CODE, APP_VERSION_NAME, ANDROID_VERSION, PHONE_MODEL, STACK_TRACE}
)
@AcraMailSender(
mailTo = "commons-app-android-private@googlegroups.com",
reportAsFile = false
)
@AcraDialog(
resTheme = R.style.Theme_AppCompat_Dialog,
resText = R.string.crash_dialog_text,
resTitle = R.string.crash_dialog_title,
resCommentPrompt = R.string.crash_dialog_comment_prompt
)
public class CommonsApplication extends Application {
@Inject SessionManager sessionManager;
@Inject DBOpenHelper dbOpenHelper;
@Inject @Named("default_preferences") JsonKvStore defaultPrefs;
@Inject
OkHttpClient okHttpClient;
/**
* 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 Feedback";
public static final String NOTIFICATION_CHANNEL_ID_ALL = "CommonsNotificationAll";
public static final String FEEDBACK_EMAIL_TEMPLATE_HEADER = "-- Technical information --";
/**
* Constants End
*/
private RefWatcher refWatcher;
private static CommonsApplication INSTANCE;
public static CommonsApplication getInstance() {
return INSTANCE;
}
private AppLanguageLookUpTable languageLookUpTable;
public AppLanguageLookUpTable getLanguageLookUpTable() {
return languageLookUpTable;
}
@Inject
AppDatabase appDatabase;
/**
* Used to declare and initialize various components and dependencies
*/
@Override
public void onCreate() {
super.onCreate();
INSTANCE = this;
ACRA.init(this);
Mapbox.getInstance(this, getString(R.string.mapbox_commons_app_token));
ApplicationlessInjection
.getInstance(this)
.getCommonsApplicationComponent()
.inject(this);
AppAdapter.set(new CommonsAppAdapter(sessionManager, defaultPrefs));
initTimber();
if (!defaultPrefs.getBoolean("has_user_manually_removed_location")) {
Set<String> defaultExifTagsSet = defaultPrefs.getStringSet(Prefs.MANAGED_EXIF_TAGS);
if (null == defaultExifTagsSet) {
defaultExifTagsSet = new HashSet<>();
}
defaultExifTagsSet.add(getString(R.string.exif_tag_location));
defaultPrefs.putStringSet(Prefs.MANAGED_EXIF_TAGS, defaultExifTagsSet);
}
// Set DownsampleEnabled to True to downsample the image in case it's heavy
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(this)
.setDownsampleEnabled(true);
if(ConfigUtils.isBetaFlavour()){
NetworkFetcher networkFetcher=new CustomNetworkFetcher(okHttpClient);
imagePipelineConfigBuilder.setNetworkFetcher(networkFetcher);
}
ImagePipelineConfig config = imagePipelineConfigBuilder.build();
try {
Fresco.initialize(this, config);
} catch (Exception e) {
Timber.e(e);
// TODO: Remove when we're able to initialize Fresco in test builds.
}
createNotificationChannel(this);
languageLookUpTable = new AppLanguageLookUpTable(this);
// This handler will catch exceptions thrown from Observables after they are disposed,
// or from Observables that are (deliberately or not) missing an onError handler.
RxJavaPlugins.setErrorHandler(Functions.emptyConsumer());
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();
FileLoggingTree tree = new FileLoggingTree(
Log.VERBOSE,
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);
}
}
}
public String getUserAgent() {
return "Commons/" + ConfigUtils.getVersionNameWithSha(this) + " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE;
}
/**
* 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");
clearImageCache();
//TODO: fix preference manager
defaultPrefs.clearAll();
defaultPrefs.putBoolean("firstrun", false);
updateAllDatabases();
logoutListener.onLogoutComplete();
});
}
/**
* Clear all images cache held by Fresco
*/
private void clearImageCache() {
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.clearCaches();
}
/**
* Deletes all tables and re-creates them.
*/
private void updateAllDatabases() {
dbOpenHelper.getReadableDatabase().close();
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
CategoryDao.Table.onDelete(db);
DepictionDao.Table.onDelete(db);
dbOpenHelper.deleteTable(db,CONTRIBUTIONS_TABLE);//Delete the contributions table in the existing db on older versions
appDatabase.getContributionDao().deleteAll();
BookmarkPicturesDao.Table.onDelete(db);
BookmarkLocationsDao.Table.onDelete(db);
}
/**
* Interface used to get log-out events
*/
public interface LogoutListener {
void onLogoutComplete();
}
}