First baby steps into the world of dependency injection using Dagger.

This commit is contained in:
Paul Hawke 2017-08-25 00:57:17 -05:00
parent 04f676c320
commit 8fe2816ca9
32 changed files with 351 additions and 115 deletions

View file

@ -55,6 +55,7 @@ dependencies {
compile 'com.google.dagger:dagger:2.11'
compile 'com.google.dagger:dagger-android-support:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
}
android {

View file

@ -4,7 +4,9 @@ import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.Application;
import android.content.ContentProvider;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -23,11 +25,21 @@ import org.acra.annotation.ReportsCrashes;
import java.io.File;
import java.io.IOException;
import javax.inject.Inject;
import dagger.android.AndroidInjector;
import dagger.android.DaggerApplication;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;
import dagger.android.HasContentProviderInjector;
import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.caching.CacheController;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.data.Category;
import fr.free.nrw.commons.data.DBOpenHelper;
import fr.free.nrw.commons.di.CommonsApplicationComponent;
import fr.free.nrw.commons.di.CommonsApplicationModule;
import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent;
import fr.free.nrw.commons.modifications.ModifierSequence;
import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
@ -44,7 +56,10 @@ import timber.log.Timber;
resDialogCommentPrompt = R.string.crash_dialog_comment_prompt,
resDialogOkToast = R.string.crash_dialog_ok_toast
)
public class CommonsApplication extends Application {
public class CommonsApplication extends DaggerApplication {
@Inject MediaWikiApi mediaWikiApi;
@Inject AccountUtil accountUtil;
private Account currentAccount = null; // Unlike a savings account...
public static final String API_URL = "https://commons.wikimedia.org/w/api.php";
@ -70,6 +85,7 @@ public class CommonsApplication extends Application {
private CacheController cacheData = null;
private DBOpenHelper dbOpenHelper = null;
private NearbyPlaces nearbyPlaces = null;
private CommonsApplicationComponent component;
/**
* This should not be called by ANY application code (other than the magic Android glue)
@ -121,6 +137,7 @@ public class CommonsApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
@ -130,8 +147,6 @@ public class CommonsApplication extends Application {
Timber.plant(new Timber.DebugTree());
if (!BuildConfig.DEBUG) {
ACRA.init(this);
} else {
@ -147,13 +162,27 @@ public class CommonsApplication extends Application {
cacheData = new CacheController();
}
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return injector();
}
public CommonsApplicationComponent injector() {
if (component == null) {
component = DaggerCommonsApplicationComponent.builder()
.appModule(new CommonsApplicationModule(this))
.build();
}
return component;
}
/**
* @return Account|null
*/
public Account getCurrentAccount() {
if(currentAccount == null) {
AccountManager accountManager = AccountManager.get(this);
Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.accountType());
Account[] allAccounts = accountManager.getAccountsByType(accountUtil.accountType());
if(allAccounts.length != 0) {
currentAccount = allAccounts[0];
}
@ -169,10 +198,10 @@ public class CommonsApplication extends Application {
return false; // This should never happen
}
accountManager.invalidateAuthToken(AccountUtil.accountType(), getMWApi().getAuthCookie());
accountManager.invalidateAuthToken(accountUtil.accountType(), mediaWikiApi.getAuthCookie());
try {
String authCookie = accountManager.blockingGetAuthToken(curAccount, "", false);
getMWApi().setAuthCookie(authCookie);
mediaWikiApi.setAuthCookie(authCookie);
return true;
} catch (OperationCanceledException | NullPointerException | IOException | AuthenticatorException e) {
e.printStackTrace();
@ -199,13 +228,13 @@ public class CommonsApplication extends Application {
}
AccountManager accountManager = AccountManager.get(this);
Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.accountType());
Account[] allAccounts = accountManager.getAccountsByType(accountUtil.accountType());
for (Account allAccount : allAccounts) {
accountManager.removeAccount(allAccount, null, null);
}
//TODO: fix preference manager
PreferenceManager.getDefaultSharedPreferences(getInstance()).edit().clear().commit();
PreferenceManager.getDefaultSharedPreferences(this).edit().clear().commit();
SharedPreferences preferences = context
.getSharedPreferences("fr.free.nrw.commons", MODE_PRIVATE);
preferences.edit().clear().commit();
@ -219,7 +248,7 @@ public class CommonsApplication extends Application {
* Deletes all tables and re-creates them.
*/
public void updateAllDatabases() {
DBOpenHelper dbOpenHelper = CommonsApplication.getInstance().getDBOpenHelper();
DBOpenHelper dbOpenHelper = getDBOpenHelper();
dbOpenHelper.getReadableDatabase().close();
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

View file

@ -2,7 +2,6 @@ package fr.free.nrw.commons;
import android.support.annotation.Nullable;
import org.mediawiki.api.ApiResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -34,6 +33,7 @@ import timber.log.Timber;
* which are not intrinsic to the media and may change due to editing.
*/
public class MediaDataExtractor {
private final MediaWikiApi mediaWikiApi;
private boolean fetched;
private String filename;
@ -45,14 +45,16 @@ public class MediaDataExtractor {
private LicenseList licenseList;
/**
* @param mwApi instance of MediaWikiApi
* @param filename of the target media object, should include 'File:' prefix
*/
public MediaDataExtractor(String filename, LicenseList licenseList) {
public MediaDataExtractor(String filename, LicenseList licenseList, MediaWikiApi mwApi) {
this.filename = filename;
categories = new ArrayList<>();
descriptions = new HashMap<>();
fetched = false;
this.categories = new ArrayList<>();
this.descriptions = new HashMap<>();
this.fetched = false;
this.licenseList = licenseList;
this.mediaWikiApi = mwApi;
}
/**
@ -66,8 +68,7 @@ public class MediaDataExtractor {
throw new IllegalStateException("Tried to call MediaDataExtractor.fetch() again.");
}
MediaWikiApi api = CommonsApplication.getInstance().getMWApi();
MediaResult result = api.fetchMediaByFilename(filename);
MediaResult result = mediaWikiApi.fetchMediaByFilename(filename);
// In-page category links are extracted from source, as XML doesn't cover [[links]]
extractCategories(result.getWikiSource());

View file

@ -7,16 +7,17 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi;
class MediaThumbnailFetchTask extends AsyncTask<String, String, String> {
protected final Media media;
private MediaWikiApi mediaWikiApi;
public MediaThumbnailFetchTask(@NonNull Media media) {
public MediaThumbnailFetchTask(@NonNull Media media, MediaWikiApi mwApi) {
this.media = media;
this.mediaWikiApi = mwApi;
}
@Override
protected String doInBackground(String... params) {
try {
MediaWikiApi api = CommonsApplication.getInstance().getMWApi();
return api.findThumbnailByFilename(params[0]);
return mediaWikiApi.findThumbnailByFilename(params[0]);
} catch (Exception e) {
// Do something better!
}

View file

@ -11,6 +11,7 @@ import android.widget.Toast;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import timber.log.Timber;
public class MediaWikiImageView extends SimpleDraweeView {
@ -43,7 +44,8 @@ public class MediaWikiImageView extends SimpleDraweeView {
setImageUrl(CommonsApplication.getInstance().getThumbnailUrlCache().get(media.getFilename()));
} else {
setImageUrl(null);
currentThumbnailTask = new ThumbnailFetchTask(media);
MediaWikiApi mediaWikiApi = CommonsApplication.getInstance().getMWApi();
currentThumbnailTask = new ThumbnailFetchTask(media, mediaWikiApi);
currentThumbnailTask.execute(media.getFilename());
}
}
@ -71,8 +73,8 @@ public class MediaWikiImageView extends SimpleDraweeView {
}
private class ThumbnailFetchTask extends MediaThumbnailFetchTask {
ThumbnailFetchTask(@NonNull Media media) {
super(media);
ThumbnailFetchTask(@NonNull Media media, @NonNull MediaWikiApi mwApi) {
super(media, mwApi);
}
@Override

View file

@ -8,6 +8,8 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import javax.inject.Inject;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
@ -15,8 +17,15 @@ import timber.log.Timber;
public class AccountUtil {
public static void createAccount(@Nullable AccountAuthenticatorResponse response,
String username, String password) {
private final CommonsApplication application;
@Inject
public AccountUtil(CommonsApplication application) {
this.application = application;
}
public void createAccount(@Nullable AccountAuthenticatorResponse response,
String username, String password) {
Account account = new Account(username, accountType());
boolean created = accountManager().addAccountExplicitly(account, password, null);
@ -46,17 +55,12 @@ public class AccountUtil {
}
@NonNull
public static String accountType() {
public String accountType() {
return "fr.free.nrw.commons";
}
private static AccountManager accountManager() {
return AccountManager.get(app());
}
@NonNull
private static CommonsApplication app() {
return CommonsApplication.getInstance();
private AccountManager accountManager() {
return AccountManager.get(application);
}
}

View file

@ -5,6 +5,9 @@ import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.os.Bundle;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.theme.NavigationBaseActivity;
import io.reactivex.Single;
@ -14,27 +17,23 @@ import timber.log.Timber;
public abstract class AuthenticatedActivity extends NavigationBaseActivity {
String accountType;
CommonsApplication app;
@Inject CommonsApplication app;
@Inject AccountUtil accountUtil;
private String authCookie;
public AuthenticatedActivity() {
this.accountType = AccountUtil.accountType();
}
private void getAuthCookie(Account account, AccountManager accountManager) {
Single.fromCallable(() -> accountManager.blockingGetAuthToken(account, "", false))
.subscribeOn(Schedulers.io())
.doOnError(Timber::e)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
cookie -> onAuthCookieAcquired(cookie),
this::onAuthCookieAcquired,
throwable -> onAuthFailure());
}
private void addAccount(AccountManager accountManager) {
Single.just(accountManager.addAccount(accountType, null, null, null, AuthenticatedActivity.this, null, null))
Single.just(accountManager.addAccount(accountUtil.accountType(), null, null, null, AuthenticatedActivity.this, null, null))
.subscribeOn(Schedulers.io())
.map(AccountManagerFuture::getResult)
.doOnEvent((bundle, throwable) -> {
@ -47,7 +46,7 @@ public abstract class AuthenticatedActivity extends NavigationBaseActivity {
.doOnError(Timber::e)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
Account[] allAccounts = accountManager.getAccountsByType(accountType);
Account[] allAccounts = accountManager.getAccountsByType(accountUtil.accountType());
Account curAccount = allAccounts[0];
getAuthCookie(curAccount, accountManager);
},
@ -71,7 +70,7 @@ public abstract class AuthenticatedActivity extends NavigationBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = CommonsApplication.getInstance();
if(savedInstanceState != null) {
authCookie = savedInstanceState.getString("authCookie");
}

View file

@ -8,15 +8,16 @@ import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
@ -34,6 +35,9 @@ public class LoginActivity extends AccountAuthenticatorActivity {
public static final String PARAM_USERNAME = "fr.free.nrw.commons.login.username";
@Inject CommonsApplication application;
@Inject AccountUtil accountUtil;
private SharedPreferences prefs = null;
private Button loginButton;
@ -43,14 +47,11 @@ public class LoginActivity extends AccountAuthenticatorActivity {
ProgressDialog progressDialog;
private LoginTextWatcher textWatcher = new LoginTextWatcher();
private CommonsApplication app;
@Override
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
app = CommonsApplication.getInstance();
setContentView(R.layout.activity_login);
loginButton = (Button) findViewById(R.id.loginButton);
@ -111,7 +112,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
WelcomeActivity.startYourself(this);
prefs.edit().putBoolean("firstrun", false).apply();
}
if (app.getCurrentAccount() != null) {
if (application.getCurrentAccount() != null) {
startMainActivity();
}
}
@ -143,7 +144,8 @@ public class LoginActivity extends AccountAuthenticatorActivity {
this,
canonicializeUsername(usernameEdit.getText().toString()),
passwordEdit.getText().toString(),
twoFactorEdit.getText().toString()
twoFactorEdit.getText().toString(),
accountUtil, application
);
}

View file

@ -19,14 +19,16 @@ class LoginTask extends AsyncTask<String, String, String> {
private String username;
private String password;
private String twoFactorCode = "";
private AccountUtil accountUtil;
private CommonsApplication app;
public LoginTask(LoginActivity loginActivity, String username, String password, String twoFactorCode) {
public LoginTask(LoginActivity loginActivity, String username, String password, String twoFactorCode, AccountUtil accountUtil, CommonsApplication application) {
this.loginActivity = loginActivity;
this.username = username;
this.password = password;
this.twoFactorCode = twoFactorCode;
app = CommonsApplication.getInstance();
this.accountUtil = accountUtil;
this.app = application;
}
@Override
@ -59,7 +61,7 @@ class LoginTask extends AsyncTask<String, String, String> {
super.onPostExecute(result);
Timber.d("Login done!");
EventLog.schema(CommonsApplication.EVENT_LOGIN_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_LOGIN_ATTEMPT, app)
.param("username", username)
.param("result", result)
.log();
@ -83,12 +85,12 @@ class LoginTask extends AsyncTask<String, String, String> {
if (response != null) {
Bundle authResult = new Bundle();
authResult.putString(AccountManager.KEY_ACCOUNT_NAME, username);
authResult.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountUtil.accountType());
authResult.putString(AccountManager.KEY_ACCOUNT_TYPE, accountUtil.accountType());
response.onResult(authResult);
}
}
AccountUtil.createAccount(response, username, password);
accountUtil.createAccount(response, username, password);
loginActivity.startMainActivity();
}

View file

@ -6,12 +6,16 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.theme.BaseActivity;
import timber.log.Timber;
public class SignupActivity extends BaseActivity {
@Inject CommonsApplication application;
private WebView webView;
@Override
@ -38,7 +42,7 @@ public class SignupActivity extends BaseActivity {
Timber.d("Overriding URL %s", url);
Toast toast = Toast.makeText(
CommonsApplication.getInstance(),
application,
"Account created!",
Toast.LENGTH_LONG
);

View file

@ -13,16 +13,19 @@ import android.support.annotation.Nullable;
import java.io.IOException;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
private Context context;
private final Context context;
private final AccountUtil accountUtil;
private MediaWikiApi mediaWikiApi;
public WikiAccountAuthenticator(Context context) {
public WikiAccountAuthenticator(Context context, AccountUtil accountUtil, MediaWikiApi mwApi) {
super(context);
this.context = context;
this.accountUtil = accountUtil;
this.mediaWikiApi = mwApi;
}
private Bundle unsupportedOperation() {
@ -36,7 +39,7 @@ public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
}
private boolean supportedAccountType(@Nullable String type) {
return AccountUtil.accountType().equals(type);
return accountUtil.accountType().equals(type);
}
@Override
@ -75,11 +78,10 @@ public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
}
private String getAuthCookie(String username, String password) throws IOException {
MediaWikiApi api = CommonsApplication.getInstance().getMWApi();
//TODO add 2fa support here
String result = api.login(username, password);
String result = mediaWikiApi.login(username, password);
if(result.equals("PASS")) {
return api.getAuthCookie();
return mediaWikiApi.getAuthCookie();
} else {
return null;
}
@ -102,7 +104,7 @@ public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
if (authCookie != null) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountUtil.accountType());
result.putString(AccountManager.KEY_ACCOUNT_TYPE, accountUtil.accountType());
result.putString(AccountManager.KEY_AUTHTOKEN, authCookie);
return result;
}

View file

@ -5,18 +5,25 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import javax.inject.Inject;
import fr.free.nrw.commons.CommonsApplication;
public class WikiAccountAuthenticatorService extends Service {
private static WikiAccountAuthenticator wikiAccountAuthenticator = null;
@Inject CommonsApplication application;
@Inject AccountUtil accountUtil;
private WikiAccountAuthenticator wikiAccountAuthenticator = null;
@Override
public IBinder onBind(Intent intent) {
if (!intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
return null;
}
((CommonsApplication)getApplication()).injector().inject(this);
if (wikiAccountAuthenticator == null) {
wikiAccountAuthenticator = new WikiAccountAuthenticator(this);
wikiAccountAuthenticator = new WikiAccountAuthenticator(this, accountUtil, application.getMWApi());
}
return wikiAccountAuthenticator.getIBinder();
}

View file

@ -10,6 +10,9 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.data.Category;
import fr.free.nrw.commons.data.DBOpenHelper;
@ -36,10 +39,14 @@ public class CategoryContentProvider extends ContentProvider {
return Uri.parse(BASE_URI.toString() + "/" + id);
}
@Inject CommonsApplication application;
private DBOpenHelper dbOpenHelper;
@Override
public boolean onCreate() {
dbOpenHelper = CommonsApplication.getInstance().getDBOpenHelper();
AndroidInjection.inject(this);
dbOpenHelper = application.getDBOpenHelper();
return false;
}

View file

@ -24,13 +24,17 @@ import android.widget.AdapterView;
import java.util.ArrayList;
import javax.inject.Inject;
import butterknife.ButterKnife;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.HandlerService;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.AuthenticatedActivity;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.UploadService;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -46,6 +50,9 @@ public class ContributionsActivity
FragmentManager.OnBackStackChangedListener,
ContributionsListFragment.SourceRefresher {
@Inject CommonsApplication application;
@Inject MediaWikiApi mediaWikiApi;
private Cursor allContributions;
private ContributionsListFragment contributionsList;
private MediaDetailPagerFragment mediaDetails;
@ -108,7 +115,7 @@ public class ContributionsActivity
@Override
protected void onAuthCookieAcquired(String authCookie) {
// Do a sync everytime we get here!
ContentResolver.requestSync(CommonsApplication.getInstance().getCurrentAccount(), ContributionsContentProvider.AUTHORITY, new Bundle());
ContentResolver.requestSync(application.getCurrentAccount(), ContributionsContentProvider.AUTHORITY, new Bundle());
Intent uploadServiceIntent = new Intent(this, UploadService.class);
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
startService(uploadServiceIntent);
@ -263,10 +270,8 @@ public class ContributionsActivity
}
private void setUploadCount() {
CommonsApplication application = CommonsApplication.getInstance();
compositeDisposable.add(
CommonsApplication.getInstance().getMWApi()
mediaWikiApi
.getUploadCount(application.getCurrentAccount().name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View file

@ -10,6 +10,9 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import timber.log.Timber;
@ -33,9 +36,12 @@ public class ContributionsContentProvider extends ContentProvider{
return Uri.parse(BASE_URI.toString() + "/" + id);
}
@Inject CommonsApplication application;
@Override
public boolean onCreate() {
return false;
AndroidInjection.inject(this);
return true;
}
@Override
@ -45,7 +51,7 @@ public class ContributionsContentProvider extends ContentProvider{
int uriType = uriMatcher.match(uri);
SQLiteDatabase db = CommonsApplication.getInstance().getDBOpenHelper().getReadableDatabase();
SQLiteDatabase db = application.getDBOpenHelper().getReadableDatabase();
Cursor cursor;
switch(uriType) {
@ -79,7 +85,7 @@ public class ContributionsContentProvider extends ContentProvider{
@Override
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
long id = 0;
switch (uriType) {
case CONTRIBUTIONS:
@ -97,7 +103,7 @@ public class ContributionsContentProvider extends ContentProvider{
int rows = 0;
int uriType = uriMatcher.match(uri);
SQLiteDatabase db = CommonsApplication.getInstance().getDBOpenHelper().getReadableDatabase();
SQLiteDatabase db = application.getDBOpenHelper().getReadableDatabase();
switch(uriType) {
case CONTRIBUTIONS_ID:
@ -118,7 +124,7 @@ public class ContributionsContentProvider extends ContentProvider{
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
Timber.d("Hello, bulk insert! (ContributionsContentProvider)");
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
sqlDB.beginTransaction();
switch (uriType) {
case CONTRIBUTIONS:
@ -146,7 +152,7 @@ public class ContributionsContentProvider extends ContentProvider{
In here, the only concat created argument is for id. It is cast to an int, and will error out otherwise.
*/
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case CONTRIBUTIONS:

View file

@ -17,6 +17,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.mwapi.LogEventResult;
@ -25,6 +27,9 @@ import timber.log.Timber;
public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
private static int COMMIT_THRESHOLD = 10;
@Inject CommonsApplication application;
public ContributionsSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@ -59,10 +64,12 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
((CommonsApplication)getContext().getApplicationContext()).injector().inject(this);
// This code is fraught with possibilities of race conditions, but lalalalala I can't hear you!
String user = account.name;
MediaWikiApi api = CommonsApplication.getInstance().getMWApi();
SharedPreferences prefs = this.getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
MediaWikiApi api = application.getMWApi();
SharedPreferences prefs = getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
String lastModified = prefs.getString("lastSyncTimestamp", "");
Date curTime = new Date();
LogEventResult result;

View file

@ -0,0 +1,45 @@
package fr.free.nrw.commons.di;
import dagger.Module;
import dagger.android.ContributesAndroidInjector;
import fr.free.nrw.commons.AboutActivity;
import fr.free.nrw.commons.WelcomeActivity;
import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.auth.SignupActivity;
import fr.free.nrw.commons.contributions.ContributionsActivity;
import fr.free.nrw.commons.nearby.NearbyActivity;
import fr.free.nrw.commons.settings.SettingsActivity;
import fr.free.nrw.commons.upload.MultipleShareActivity;
import fr.free.nrw.commons.upload.ShareActivity;
@Module
public abstract class ActivityBuilderModule {
@ContributesAndroidInjector
abstract ContributionsActivity bindContributionsActivity();
@ContributesAndroidInjector
abstract MultipleShareActivity bindMultipleShareActivity();
@ContributesAndroidInjector
abstract ShareActivity bindShareActivity();
@ContributesAndroidInjector
abstract LoginActivity bindLoginActivity();
@ContributesAndroidInjector
abstract SignupActivity bindSignupActivity();
@ContributesAndroidInjector
abstract NearbyActivity bindNearbyActivity();
@ContributesAndroidInjector
abstract AboutActivity bindAboutActivity();
@ContributesAndroidInjector
abstract SettingsActivity bindSettingsActivity();
@ContributesAndroidInjector
abstract WelcomeActivity bindWelcomeActivity();
}

View file

@ -0,0 +1,35 @@
package fr.free.nrw.commons.di;
import javax.inject.Singleton;
import dagger.Component;
import dagger.android.AndroidInjectionModule;
import dagger.android.AndroidInjector;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.auth.WikiAccountAuthenticatorService;
import fr.free.nrw.commons.contributions.ContributionsSyncAdapter;
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
@Singleton
@Component(modules = {
CommonsApplicationModule.class,
AndroidInjectionModule.class,
ActivityBuilderModule.class,
ContentProviderBuilderModule.class
})
public interface CommonsApplicationComponent extends AndroidInjector<CommonsApplication> {
void inject(CommonsApplication application);
void inject(WikiAccountAuthenticatorService service);
void inject(ContributionsSyncAdapter syncAdapter);
void inject(ModificationsSyncAdapter syncAdapter);
@Component.Builder
interface Builder {
Builder appModule(CommonsApplicationModule applicationModule);
CommonsApplicationComponent build();
}
}

View file

@ -0,0 +1,29 @@
package fr.free.nrw.commons.di;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
@Module
public class CommonsApplicationModule {
private CommonsApplication application;
public CommonsApplicationModule(CommonsApplication application) {
this.application = application;
}
@Provides
public CommonsApplication providesCommonsApplication() {
return application;
}
@Provides
@Singleton
public MediaWikiApi provideMediaWikiApi() {
return new ApacheHttpClientMediaWikiApi(CommonsApplication.API_URL);
}
}

View file

@ -0,0 +1,24 @@
package fr.free.nrw.commons.di;
import dagger.Module;
import dagger.android.ContributesAndroidInjector;
import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.auth.SignupActivity;
import fr.free.nrw.commons.category.CategoryContentProvider;
import fr.free.nrw.commons.contributions.ContributionsActivity;
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
@Module
public abstract class ContentProviderBuilderModule {
@ContributesAndroidInjector
abstract CategoryContentProvider bindCategoryContentProvider();
@ContributesAndroidInjector
abstract ContributionsContentProvider bindContributionsContentProvider();
@ContributesAndroidInjector
abstract ModificationsContentProvider bindModificationsContentProvider();
}

View file

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.License;
import fr.free.nrw.commons.LicenseList;
import fr.free.nrw.commons.Media;
@ -188,7 +189,7 @@ public class MediaDetailFragment extends Fragment {
@Override
protected void onPreExecute() {
extractor = new MediaDataExtractor(media.getFilename(), licenseList);
extractor = new MediaDataExtractor(media.getFilename(), licenseList, CommonsApplication.getInstance().getMWApi());
}
@Override

View file

@ -131,7 +131,7 @@ public class MediaDetailPagerFragment extends Fragment implements ViewPager.OnPa
switch(item.getItemId()) {
case R.id.menu_share_current_image:
// Share - this is just logs it, intent set in onCreateOptionsMenu, around line 252
EventLog.schema(CommonsApplication.EVENT_SHARE_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_SHARE_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("filename", m.getFilename())
.log();

View file

@ -10,6 +10,9 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import javax.inject.Inject;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import timber.log.Timber;
@ -33,10 +36,12 @@ public class ModificationsContentProvider extends ContentProvider{
return Uri.parse(BASE_URI.toString() + "/" + id);
}
@Inject CommonsApplication application;
@Override
public boolean onCreate() {
return false;
AndroidInjection.inject(this);
return true;
}
@Override
@ -53,7 +58,7 @@ public class ModificationsContentProvider extends ContentProvider{
throw new IllegalArgumentException("Unknown URI" + uri);
}
SQLiteDatabase db = CommonsApplication.getInstance().getDBOpenHelper().getReadableDatabase();
SQLiteDatabase db = application.getDBOpenHelper().getReadableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
@ -69,7 +74,7 @@ public class ModificationsContentProvider extends ContentProvider{
@Override
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
long id = 0;
switch (uriType) {
case MODIFICATIONS:
@ -85,7 +90,7 @@ public class ModificationsContentProvider extends ContentProvider{
@Override
public int delete(@NonNull Uri uri, String s, String[] strings) {
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
switch (uriType) {
case MODIFICATIONS_ID:
String id = uri.getLastPathSegment();
@ -103,7 +108,7 @@ public class ModificationsContentProvider extends ContentProvider{
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
Timber.d("Hello, bulk insert! (ModificationsContentProvider)");
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
sqlDB.beginTransaction();
switch (uriType) {
case MODIFICATIONS:
@ -131,7 +136,7 @@ public class ModificationsContentProvider extends ContentProvider{
In here, the only concat created argument is for id. It is cast to an int, and will error out otherwise.
*/
int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = CommonsApplication.getInstance().getDBOpenHelper().getWritableDatabase();
SQLiteDatabase sqlDB = application.getDBOpenHelper().getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case MODIFICATIONS:

View file

@ -14,6 +14,8 @@ import android.os.RemoteException;
import java.io.IOException;
import javax.inject.Inject;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.contributions.Contribution;
@ -23,6 +25,8 @@ import timber.log.Timber;
public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
@Inject CommonsApplication application;
public ModificationsSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@ -30,6 +34,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
// This code is fraught with possibilities of race conditions, but lalalalala I can't hear you!
((CommonsApplication)getContext().getApplicationContext()).injector().inject(this);
Cursor allModifications;
try {
@ -59,7 +64,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
return;
}
MediaWikiApi api = CommonsApplication.getInstance().getMWApi();
MediaWikiApi api = application.getMWApi();
api.setAuthCookie(authCookie);
String editToken;

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.mwapi;
import android.os.Build;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Utils;
public class EventLog {
@ -15,14 +16,14 @@ public class EventLog {
}
}
private static LogBuilder schema(String schema, long revision) {
return new LogBuilder(schema, revision);
private static LogBuilder schema(String schema, long revision, CommonsApplication application) {
return new LogBuilder(schema, revision, application);
}
public static LogBuilder schema(Object[] scid) {
public static LogBuilder schema(Object[] scid, CommonsApplication application) {
if (scid.length != 2) {
throw new IllegalArgumentException("Needs an object array with schema as first param and revision as second");
}
return schema((String) scid[0], (Long) scid[1]);
return schema((String) scid[0], (Long) scid[1], application);
}
}

View file

@ -17,14 +17,16 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.settings.Prefs;
public class LogBuilder {
private final CommonsApplication application;
private JSONObject data;
private long rev;
private String schema;
LogBuilder(String schema, long revision) {
LogBuilder(String schema, long revision, CommonsApplication application) {
data = new JSONObject();
this.schema = schema;
this.rev = revision;
this.application = application;
}
public LogBuilder param(String key, Object value) {
@ -56,11 +58,11 @@ public class LogBuilder {
// Use *only* for tracking the user preference change for EventLogging
// Attempting to use anywhere else will cause kitten explosions
public void log(boolean force) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(CommonsApplication.getInstance());
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(application);
if (!settings.getBoolean(Prefs.TRACKING_ENABLED, true) && !force) {
return; // User has disabled tracking
}
LogTask logTask = new LogTask();
LogTask logTask = new LogTask(application.getMWApi());
logTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this);
}

View file

@ -2,11 +2,16 @@ package fr.free.nrw.commons.mwapi;
import android.os.AsyncTask;
import fr.free.nrw.commons.CommonsApplication;
class LogTask extends AsyncTask<LogBuilder, Void, Boolean> {
private final MediaWikiApi mwApi;
public LogTask(MediaWikiApi mwApi) {
this.mwApi = mwApi;
}
@Override
protected Boolean doInBackground(LogBuilder... logBuilders) {
return CommonsApplication.getInstance().getMWApi().logEvents(logBuilders);
return mwApi.logEvents(logBuilders);
}
}

View file

@ -27,8 +27,11 @@ import com.google.gson.GsonBuilder;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.location.LatLng;
@ -37,11 +40,12 @@ import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.UriSerializer;
import timber.log.Timber;
public class NearbyActivity extends NavigationBaseActivity {
@BindView(R.id.progressBar)
ProgressBar progressBar;
@Inject CommonsApplication application;
private boolean isMapViewActive = false;
private static final int LOCATION_REQUEST = 1;
@ -91,7 +95,7 @@ public class NearbyActivity extends NavigationBaseActivity {
locationManager = new LocationServiceManager(this);
locationManager.registerLocationManager();
curLatLang = locationManager.getLatestLocation();
nearbyAsyncTask = new NearbyAsyncTask(this);
nearbyAsyncTask = new NearbyAsyncTask(this, application);
nearbyAsyncTask.execute();
}
@ -230,7 +234,7 @@ public class NearbyActivity extends NavigationBaseActivity {
}
private void refreshView() {
nearbyAsyncTask = new NearbyAsyncTask(this);
nearbyAsyncTask = new NearbyAsyncTask(this, application);
nearbyAsyncTask.execute();
}
@ -245,9 +249,11 @@ public class NearbyActivity extends NavigationBaseActivity {
private class NearbyAsyncTask extends AsyncTask<Void, Integer, List<Place>> {
private final Context mContext;
private final CommonsApplication application;
private NearbyAsyncTask(Context context) {
private NearbyAsyncTask(Context context, CommonsApplication application) {
mContext = context;
this.application = application;
}
@Override
@ -258,8 +264,7 @@ public class NearbyActivity extends NavigationBaseActivity {
@Override
protected List<Place> doInBackground(Void... params) {
return NearbyController
.loadAttractionsFromLocation(curLatLang, CommonsApplication.getInstance()
);
.loadAttractionsFromLocation(curLatLang, application);
}
@Override

View file

@ -5,15 +5,16 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import dagger.android.AndroidInjection;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
public class BaseActivity extends AppCompatActivity {
boolean currentTheme;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
if(Utils.isDarkTheme(this)){
currentTheme = true;
setTheme(R.style.DarkAppTheme);

View file

@ -177,7 +177,7 @@ public class MultipleShareActivity
// FIXME: Make sure that the content provider is up
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(app.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("categories-count", categories.size())
.param("files-count", photosList.size())
@ -288,7 +288,7 @@ public class MultipleShareActivity
public void onBackPressed() {
super.onBackPressed();
if(categorizationFragment != null && categorizationFragment.isVisible()) {
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("categories-count", categorizationFragment.getCurrentSelectedCount())
.param("files-count", photosList.size())
@ -296,7 +296,7 @@ public class MultipleShareActivity
.param("result", "cancelled")
.log();
} else {
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("source", getIntent().getStringExtra(UploadService.EXTRA_SOURCE))
.param("multiple", true)

View file

@ -27,7 +27,6 @@ import com.facebook.drawee.view.SimpleDraweeView;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -168,7 +167,7 @@ public class ShareActivity
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(app.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("categories-count", categories.size())
.param("files-count", 1)
@ -190,7 +189,7 @@ public class ShareActivity
public void onBackPressed() {
super.onBackPressed();
if(categorizationFragment != null && categorizationFragment.isVisible()) {
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("categories-count", categorizationFragment.getCurrentSelectedCount())
.param("files-count", 1)
@ -198,7 +197,7 @@ public class ShareActivity
.param("result", "cancelled")
.log();
} else {
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("source", getIntent().getStringExtra(UploadService.EXTRA_SOURCE))
.param("multiple", true)

View file

@ -247,7 +247,7 @@ public class UploadService extends HandlerService<Contribution> {
String resultStatus = uploadResult.getResultStatus();
if (!resultStatus.equals("Success")) {
showFailedNotification(contribution);
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("source", contribution.getSource())
.param("multiple", contribution.getMultiple())
@ -261,7 +261,7 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setDateUploaded(uploadResult.getDateUploaded());
contribution.save();
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT, CommonsApplication.getInstance())
.param("username", app.getCurrentAccount().name)
.param("source", contribution.getSource()) //FIXME
.param("filename", contribution.getFilename())