0% found this document useful (0 votes)
125 views7 pages

Habitica Base Application

This document contains code for an Android application. It defines a base application class that initializes various third party libraries, handles user authentication and logout, and manages the application's SQLite database. It also includes code for in-app purchases using billing and checkout libraries.

Uploaded by

john
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
125 views7 pages

Habitica Base Application

This document contains code for an Android application. It defines a base application class that initializes various third party libraries, handles user authentication and logout, and manages the application's SQLite database. It also includes code for in-app purchases using billing and checkout libraries.

Uploaded by

john
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

package com.habitrpg.android.

habitica;

import com.amplitude.api.Amplitude;
import com.facebook.FacebookSdk;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.proxy.ifce.CrashlyticsProxy;
import com.habitrpg.android.habitica.ui.activities.IntroActivity;
import com.habitrpg.android.habitica.ui.activities.LoginActivity;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

import org.solovyev.android.checkout.Billing;
import org.solovyev.android.checkout.Cache;
import org.solovyev.android.checkout.Checkout;
import org.solovyev.android.checkout.PurchaseVerifier;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.multidex.MultiDexApplication;
import android.util.Log;

import java.io.File;
import java.lang.reflect.Field;

import javax.inject.Inject;

import dagger.Lazy;

//contains all HabiticaApplicationLogic except dagger componentInitialisation


public abstract class HabiticaBaseApplication extends MultiDexApplication {

public static HabitRPGUser User;


public static Activity currentActivity = null;
private static AppComponent component;
public RefWatcher refWatcher;
@Inject
Lazy<APIHelper> lazyApiHelper;
@Inject
SharedPreferences sharedPrefs;
@Inject
CrashlyticsProxy crashlyticsProxy;
/**
* For better performance billing class should be used as singleton
*/
@NonNull
private Billing billing;
/**
* Application wide {@link Checkout} instance (can be used
* anywhere in the app).
* This instance contains all available products in the app.
*/
@NonNull
private Checkout checkout;

public static HabiticaBaseApplication getInstance(Context context) {


return (HabiticaBaseApplication) context.getApplicationContext();
}

public static boolean exists(@NonNull Context context) {


try {
File dbFile = context.getDatabasePath(String.format("%s.db",
HabitDatabase.NAME));
return dbFile.exists();
} catch (Exception exception) {
Log.e("DbExists", "Database %s doesn't exist.", exception);
return false;
}
}

private static void setFinalStatic(Field field, Object newValue) throws


NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
field.set(null, newValue);
}

public static void logout(Context context) {


getInstance(context).deleteDatabase(HabitDatabase.NAME);
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
boolean use_reminder = preferences.getBoolean("use_reminder", false);
String reminder_time = preferences.getString("reminder_time", "19:00");
SharedPreferences.Editor editor = preferences.edit();
editor.clear();
editor.putBoolean("use_reminder", use_reminder);
editor.putString("reminder_time", reminder_time);
editor.apply();

getInstance(context).lazyApiHelper.get().updateAuthenticationCredentials(null,
null);
startActivity(LoginActivity.class, context);
}

public static boolean checkUserAuthentication(Context context, HostConfig


hostConfig) {
if (hostConfig == null || hostConfig.getApi() == null ||
hostConfig.getApi().equals("") || hostConfig.getUser() == null ||
hostConfig.getUser().equals("")) {
startActivity(IntroActivity.class, context);

return false;
}

return true;
}

private static void startActivity(Class activityClass, Context context) {


Intent intent = new Intent(context, activityClass);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}

// region SQLite overrides

public static AppComponent getComponent() {


return component;
}

@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.
return;
}
setupDagger();
crashlyticsProxy.init(this);
setupLeakCanary();
setupFlowManager();
setupFacebookSdk();
createBillingAndCheckout();
registerActivityLifecycleCallbacks();

if (!BuildConfig.DEBUG) {
try {
Amplitude.getInstance().initialize(this,
getString(R.string.amplitude_app_id)).enableForegroundTracking(this);
} catch (Resources.NotFoundException e) {
//pass
}
}

Fresco.initialize(this);
checkIfNewVersion();
}

private void checkIfNewVersion() {


PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e("MyApplication", "couldn't get package info!");
}

if (info == null) {
return;
}

int lastInstalledVersion = sharedPrefs.getInt("last_installed_version", 0);


if (lastInstalledVersion < info.versionCode) {
sharedPrefs.edit().putInt("last_installed_version",
info.versionCode).apply();
APIHelper apiHelper = this.lazyApiHelper.get();

apiHelper.apiService.getContent(apiHelper.languageCode)
.compose(this.lazyApiHelper.get().configureApiCallObserver())
.subscribe(contentResult -> {
}, throwable -> {
});
}

private void setupDagger() {


component = initDagger();
component.inject(this);
}

protected abstract AppComponent initDagger();

private void setupLeakCanary() {


refWatcher = LeakCanary.install(this);
}

private void setupFlowManager() {


FlowManager.init(this);
}

private void setupFacebookSdk() {


String fbApiKey = null;
try {
ApplicationInfo ai =
getPackageManager().getApplicationInfo(getPackageName(),
PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
fbApiKey = bundle.getString(FacebookSdk.APPLICATION_ID_PROPERTY);
} catch (PackageManager.NameNotFoundException e) {
Log.e("FB Error", "Failed to load meta-data, NameNotFound: " +
e.getMessage());
} catch (NullPointerException e) {
Log.e("FB Error", "Failed to load meta-data, NullPointer: " +
e.getMessage());
}
if (fbApiKey != null) {
FacebookSdk.sdkInitialize(getApplicationContext());
}
}

private void registerActivityLifecycleCallbacks() {


registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle
savedInstanceState) {
HabiticaBaseApplication.currentActivity = activity;
}

@Override
public void onActivityStarted(Activity activity) {

}
@Override
public void onActivityResumed(Activity activity) {
HabiticaBaseApplication.currentActivity = activity;
}

@Override
public void onActivityPaused(Activity activity) {

@Override
public void onActivityStopped(Activity activity) {

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle
outState) {

@Override
public void onActivityDestroyed(Activity activity) {
if (currentActivity == activity)
currentActivity = null;
}
});
}

@Override
public SQLiteDatabase openOrCreateDatabase(String name,
int mode,
SQLiteDatabase.CursorFactory factory) {
return super.openOrCreateDatabase(getDatabasePath(name).getAbsolutePath(),
mode, factory);
}

@Override
public SQLiteDatabase openOrCreateDatabase(String name,
int mode,
SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
return super.openOrCreateDatabase(getDatabasePath(name).getAbsolutePath(),
mode, factory, errorHandler);
}

// endregion

// region IAP - Specific

@Override
public boolean deleteDatabase(String name) {
if (!name.endsWith(".db")) {
name += ".db";
}

FlowManager.destroy();
reflectionHack(getApplicationContext());
boolean deleted =
super.deleteDatabase(getDatabasePath(name).getAbsolutePath());

if (deleted) {
Log.i("hack", "Database deleted");
} else {
Log.e("hack", "Database not deleted");
}

if (exists(getApplicationContext())) {
Log.i("hack", "Database exists before FlowManager.init");
} else {
Log.i("hack", "Database does not exist before FlowManager.init");
}

return deleted;
}

// Hack for DBFlow - Not deleting Database


// https://github.com/kaeawc/dbflow-sample-
app/blob/master/app/src/main/java/io/kaeawc/flow/app/ui/MainActivityFragment.java#L
201
private void reflectionHack(@NonNull Context context) {

try {
Field field = FlowManager.class.getDeclaredField("mDatabaseHolder");
setFinalStatic(field, null);
} catch (NoSuchFieldException noSuchField) {
Log.e("nosuchfield", "No such field exists in FlowManager",
noSuchField);
} catch (IllegalAccessException illegalAccess) {
Log.e("illegalaccess", "Illegal access of FlowManager", illegalAccess);
}

FlowManager.init(context);

if (exists(context)) {
Log.i("Database", "Database exists after FlowManager.init with
reflection hack");
} else {
Log.i("Database", "Database does not exist after FlowManager.init with
reflection hack");
}
}

@Override
public File getDatabasePath(String name) {
File dbFile = new File(getExternalFilesDir(null), "HabiticaDatabase/" +
name);
//Crashlytics.setString("Database File", dbFile.getAbsolutePath());
return dbFile;
}

private void createBillingAndCheckout() {


billing = new Billing(this, new Billing.DefaultConfiguration() {
@NonNull
@Override
public String getPublicKey() {
return "DONT-NEED-IT";
}

@Nullable
@Override
public Cache getCache() {
return Billing.newCache();
}

@Override
public PurchaseVerifier getPurchaseVerifier() {
return new HabiticaPurchaseVerifier(HabiticaBaseApplication.this,
lazyApiHelper.get());
}
});

checkout = Checkout.forApplication(billing);
}

@NonNull
public Checkout getCheckout() {
return checkout;
}

// endregion

public Billing getBilling() {


return billing;
}
}

You might also like