Commit 2d58c725 authored by Viktor De Pasquale's avatar Viktor De Pasquale

Added koin, databinding and navigation components

Converted App class and Main activity to Kotlin. With that refactored fields within App class to allow lazy initialization

BEWARE: at this point the navigation is very much broken, won't let you anywhere beyond home screen
parent e035523e
...@@ -30,6 +30,10 @@ android { ...@@ -30,6 +30,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }
dataBinding {
enabled = true
}
} }
dependencies { dependencies {
...@@ -64,12 +68,13 @@ dependencies { ...@@ -64,12 +68,13 @@ dependencies {
implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}" implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}" kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
implementation ("com.github.skoumalcz:teanity:0.3.3") { def koin = "2.0.0-rc-2"
exclude group: 'com.karumi', module: 'dexter' implementation("org.koin:koin-core:${koin}")
exclude group: 'com.evernote', module: 'android-state' implementation("org.koin:koin-android:${koin}")
implementation("org.koin:koin-androidx-viewmodel:${koin}")
implementation("com.github.skoumalcz:teanity:0.3.3") {
exclude group: 'androidx.work', module: 'work-runtime-ktx' exclude group: 'androidx.work', module: 'work-runtime-ktx'
exclude group: 'androidx.room', module: 'room-runtime' exclude group: 'androidx.room', module: 'room-runtime'
exclude group: 'io.reactivex.rxjava2', module: 'rxkotlin' //hopefully not forever
exclude group: 'io.reactivex.rxjava2', module: 'rxandroid' //hopefully not forever
} }
} }
package com.topjohnwu.magisk;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import com.topjohnwu.magisk.data.database.MagiskDB;
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.ui.base.BaseActivity;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.util.concurrent.ThreadPoolExecutor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
public class App extends Application implements Application.ActivityLifecycleCallbacks {
public static App self;
public static Context deContext;
public static ThreadPoolExecutor THREAD_POOL;
// Global resources
public SharedPreferences prefs;
public MagiskDB mDB;
public RepoDatabaseHelper repoDB;
private volatile BaseActivity foreground;
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER | Shell.FLAG_USE_MAGISK_BUSYBOX);
Shell.Config.verboseLogging(BuildConfig.DEBUG);
Shell.Config.addInitializers(RootUtils.class);
Shell.Config.setTimeout(2);
THREAD_POOL = (ThreadPoolExecutor) AsyncTask.THREAD_POOL_EXECUTOR;
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
self = this;
deContext = base;
registerActivityLifecycleCallbacks(this);
if (Build.VERSION.SDK_INT >= 24) {
deContext = base.createDeviceProtectedStorageContext();
deContext.moveSharedPreferencesFrom(base,
PreferenceManager.getDefaultSharedPreferencesName(base));
}
prefs = PreferenceManager.getDefaultSharedPreferences(deContext);
mDB = new MagiskDB(base);
Networking.init(base);
LocaleManager.setLocale(this);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocaleManager.setLocale(this);
}
public static BaseActivity foreground() {
return self.foreground;
}
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {}
@Override
public void onActivityStarted(@NonNull Activity activity) {}
@Override
public synchronized void onActivityResumed(@NonNull Activity activity) {
foreground = (BaseActivity) activity;
}
@Override
public synchronized void onActivityPaused(@NonNull Activity activity) {
foreground = null;
}
@Override
public void onActivityStopped(@NonNull Activity activity) {}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {}
}
package com.topjohnwu.magisk
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.AsyncTask
import android.os.Build
import android.os.Bundle
import android.preference.PreferenceManager
import androidx.appcompat.app.AppCompatDelegate
import com.topjohnwu.magisk.data.database.MagiskDB
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.utils.LocaleManager
import com.topjohnwu.magisk.utils.RootUtils
import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import java.util.concurrent.ThreadPoolExecutor
open class App : Application(), Application.ActivityLifecycleCallbacks {
// Global resources
val prefs: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(deContext) }
val DB: MagiskDB by lazy { MagiskDB(deContext) }
@JvmField
var repoDB: RepoDatabaseHelper? = null
@Volatile
private var foreground: Activity? = null
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@App)
modules(koinModules)
}
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
self = this
deContext = base
registerActivityLifecycleCallbacks(this)
if (Build.VERSION.SDK_INT >= 24) {
deContext = base.createDeviceProtectedStorageContext()
deContext.moveSharedPreferencesFrom(
base,
PreferenceManager.getDefaultSharedPreferencesName(base)
)
}
Networking.init(base)
LocaleManager.setLocale(this)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
LocaleManager.setLocale(this)
}
//region ActivityLifecycleCallbacks
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
@Synchronized
override fun onActivityResumed(activity: Activity) {
foreground = activity
}
@Synchronized
override fun onActivityPaused(activity: Activity) {
foreground = null
}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
//endregion
companion object {
//fixme this should be at least weak reference, me no likey
@SuppressLint("StaticFieldLeak")
@JvmStatic
lateinit var self: App
//fixme this should be at least weak reference, me no likey
@SuppressLint("StaticFieldLeak")
@JvmStatic
lateinit var deContext: Context
//fixme me no likey
@JvmField
var THREAD_POOL: ThreadPoolExecutor
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER or Shell.FLAG_USE_MAGISK_BUSYBOX)
Shell.Config.verboseLogging(BuildConfig.DEBUG)
Shell.Config.addInitializers(RootUtils::class.java)
Shell.Config.setTimeout(2)
THREAD_POOL = AsyncTask.THREAD_POOL_EXECUTOR as ThreadPoolExecutor
}
//fixme me no likey
@JvmStatic
fun foreground(): Activity? {
return self.foreground
}
}
}
...@@ -3,8 +3,6 @@ package com.topjohnwu.magisk; ...@@ -3,8 +3,6 @@ package com.topjohnwu.magisk;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Xml; import android.util.Xml;
import androidx.collection.ArrayMap;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.ShellUtils;
...@@ -17,6 +15,8 @@ import org.xmlpull.v1.XmlPullParserException; ...@@ -17,6 +15,8 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import androidx.collection.ArrayMap;
public class Config { public class Config {
// Current status // Current status
...@@ -109,14 +109,14 @@ public class Config { ...@@ -109,14 +109,14 @@ public class Config {
public static void export() { public static void export() {
// Flush prefs to disk // Flush prefs to disk
App app = App.self; App app = App.self;
app.prefs.edit().commit(); app.getPrefs().edit().commit();
File xml = new File(App.deContext.getFilesDir().getParent() + "/shared_prefs", File xml = new File(App.deContext.getFilesDir().getParent() + "/shared_prefs",
app.getPackageName() + "_preferences.xml"); app.getPackageName() + "_preferences.xml");
Shell.su(Utils.fmt("cat %s > /data/adb/%s", xml, Const.MANAGER_CONFIGS)).exec(); Shell.su(Utils.fmt("cat %s > /data/adb/%s", xml, Const.MANAGER_CONFIGS)).exec();
} }
public static void initialize() { public static void initialize() {
SharedPreferences pref = App.self.prefs; SharedPreferences pref = App.self.getPrefs();
SharedPreferences.Editor editor = pref.edit(); SharedPreferences.Editor editor = pref.edit();
File config = SuFile.open("/data/adb", Const.MANAGER_CONFIGS); File config = SuFile.open("/data/adb", Const.MANAGER_CONFIGS);
if (config.exists()) { if (config.exists()) {
...@@ -238,19 +238,19 @@ public class Config { ...@@ -238,19 +238,19 @@ public class Config {
App app = App.self; App app = App.self;
switch (getConfigType(key)) { switch (getConfigType(key)) {
case PREF_INT: case PREF_INT:
return (T) (Integer) app.prefs.getInt(key, getDef(key)); return (T) (Integer) app.getPrefs().getInt(key, getDef(key));
case PREF_STR_INT: case PREF_STR_INT:
return (T) (Integer) Utils.getPrefsInt(app.prefs, key, getDef(key)); return (T) (Integer) Utils.getPrefsInt(app.getPrefs(), key, getDef(key));
case PREF_BOOL: case PREF_BOOL:
return (T) (Boolean) app.prefs.getBoolean(key, getDef(key)); return (T) (Boolean) app.getPrefs().getBoolean(key, getDef(key));
case PREF_STR: case PREF_STR:
return (T) app.prefs.getString(key, getDef(key)); return (T) app.getPrefs().getString(key, getDef(key));
case DB_INT: case DB_INT:
return (T) (Integer) app.mDB.getSettings(key, getDef(key)); return (T) (Integer) app.getDB().getSettings(key, getDef(key));
case DB_BOOL: case DB_BOOL:
return (T) (Boolean) (app.mDB.getSettings(key, getDef(key) ? 1 : 0) != 0); return (T) (Boolean) (app.getDB().getSettings(key, getDef(key) ? 1 : 0) != 0);
case DB_STR: case DB_STR:
return (T) app.mDB.getStrings(key, getDef(key)); return (T) app.getDB().getStrings(key, getDef(key));
} }
/* Will never get here (IllegalArgumentException in getConfigType) */ /* Will never get here (IllegalArgumentException in getConfigType) */
return null; return null;
...@@ -260,25 +260,25 @@ public class Config { ...@@ -260,25 +260,25 @@ public class Config {
App app = App.self; App app = App.self;
switch (getConfigType(key)) { switch (getConfigType(key)) {
case PREF_INT: case PREF_INT:
app.prefs.edit().putInt(key, (int) val).apply(); app.getPrefs().edit().putInt(key, (int) val).apply();
break; break;
case PREF_STR_INT: case PREF_STR_INT:
app.prefs.edit().putString(key, String.valueOf(val)).apply(); app.getPrefs().edit().putString(key, String.valueOf(val)).apply();
break; break;
case PREF_BOOL: case PREF_BOOL:
app.prefs.edit().putBoolean(key, (boolean) val).apply(); app.getPrefs().edit().putBoolean(key, (boolean) val).apply();
break; break;
case PREF_STR: case PREF_STR:
app.prefs.edit().putString(key, (String) val).apply(); app.getPrefs().edit().putString(key, (String) val).apply();
break; break;
case DB_INT: case DB_INT:
app.mDB.setSettings(key, (int) val); app.getDB().setSettings(key, (int) val);
break; break;
case DB_BOOL: case DB_BOOL:
app.mDB.setSettings(key, (boolean) val ? 1 : 0); app.getDB().setSettings(key, (boolean) val ? 1 : 0);
break; break;
case DB_STR: case DB_STR:
app.mDB.setStrings(key, (String) val); app.getDB().setStrings(key, (String) val);
break; break;
} }
} }
...@@ -290,14 +290,14 @@ public class Config { ...@@ -290,14 +290,14 @@ public class Config {
case PREF_STR_INT: case PREF_STR_INT:
case PREF_BOOL: case PREF_BOOL:
case PREF_STR: case PREF_STR:
app.prefs.edit().remove(key).apply(); app.getPrefs().edit().remove(key).apply();
break; break;
case DB_BOOL: case DB_BOOL:
case DB_INT: case DB_INT:
app.mDB.rmSettings(key); app.getDB().rmSettings(key);
break; break;
case DB_STR: case DB_STR:
app.mDB.setStrings(key, null); app.getDB().setStrings(key, null);
break; break;
} }
} }
...@@ -365,13 +365,13 @@ public class Config { ...@@ -365,13 +365,13 @@ public class Config {
switch (type) { switch (type) {
case DB_INT: case DB_INT:
editor.putString(key, String.valueOf( editor.putString(key, String.valueOf(
app.mDB.getSettings(key, (Integer) defs.get(key)))); app.getDB().getSettings(key, (Integer) defs.get(key))));
continue; continue;
case DB_STR: case DB_STR:
editor.putString(key, app.mDB.getStrings(key, (String) defs.get(key))); editor.putString(key, app.getDB().getStrings(key, (String) defs.get(key)));
continue; continue;
case DB_BOOL: case DB_BOOL:
int bs = app.mDB.getSettings(key, -1); int bs = app.getDB().getSettings(key, -1);
editor.putBoolean(key, bs < 0 ? (Boolean) defs.get(key) : bs != 0); editor.putBoolean(key, bs < 0 ? (Boolean) defs.get(key) : bs != 0);
continue; continue;
} }
......
package com.topjohnwu.magisk.di
import android.content.Context
import com.skoumal.teanity.rxbus.RxBus
import org.koin.dsl.module
val applicationModule = module {
single { RxBus() }
single { get<Context>().resources }
}
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val databaseModule = module {}
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val miscModule = module {
// define miscs here
}
package com.topjohnwu.magisk.di
val koinModules = listOf(
applicationModule,
networkingModule,
databaseModule,
repositoryModule,
viewModelModules,
miscModule
)
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val networkingModule = module {}
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val repositoryModule = module {}
package com.topjohnwu.magisk.di
import com.topjohnwu.magisk.ui.MainViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val viewModelModules = module {
viewModel { MainViewModel() }
}
package com.topjohnwu.magisk.model.navigation
object Navigation
...@@ -61,12 +61,12 @@ public class GeneralReceiver extends BroadcastReceiver { ...@@ -61,12 +61,12 @@ public class GeneralReceiver extends BroadcastReceiver {
case Intent.ACTION_PACKAGE_REPLACED: case Intent.ACTION_PACKAGE_REPLACED:
// This will only work pre-O // This will only work pre-O
if (Config.get(Config.Key.SU_REAUTH)) { if (Config.get(Config.Key.SU_REAUTH)) {
app.mDB.deletePolicy(getPkg(intent)); app.getDB().deletePolicy(getPkg(intent));
} }
break; break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED: case Intent.ACTION_PACKAGE_FULLY_REMOVED:
String pkg = getPkg(intent); String pkg = getPkg(intent);
app.mDB.deletePolicy(pkg); app.getDB().deletePolicy(pkg);
Shell.su("magiskhide --rm " + pkg).submit(); Shell.su("magiskhide --rm " + pkg).submit();
break; break;
case Intent.ACTION_LOCALE_CHANGED: case Intent.ACTION_LOCALE_CHANGED:
......
package com.topjohnwu.magisk.ui;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.google.android.material.navigation.NavigationView;
import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.ui.base.BaseActivity;
import com.topjohnwu.magisk.ui.hide.MagiskHideFragment;
import com.topjohnwu.magisk.ui.home.MagiskFragment;
import com.topjohnwu.magisk.ui.log.LogFragment;
import com.topjohnwu.magisk.ui.module.ModulesFragment;
import com.topjohnwu.magisk.ui.module.ReposFragment;
import com.topjohnwu.magisk.ui.settings.SettingsFragment;
import com.topjohnwu.magisk.ui.superuser.SuperuserFragment;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.Toolbar;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import butterknife.BindView;
public class MainActivity extends BaseActivity
implements NavigationView.OnNavigationItemSelectedListener {
private final Handler mDrawerHandler = new Handler();
private int mDrawerItem;
private static boolean fromShortcut = false;
@BindView(R.id.toolbar) public Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.nav_view) NavigationView navigationView;
private float toolbarElevation;
@Override
public int getDarkTheme() {
return R.style.AppTheme_Dark;
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (!SplashActivity.DONE) {
startActivity(new Intent(this, ClassMap.get(SplashActivity.class)));
finish();
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MainActivity_ViewBinding(this);
checkHideSection();
setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.magisk, R.string.magisk) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed tate
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, 0); // this disables the animation
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbarElevation = toolbar.getElevation();
}
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null) {
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
fromShortcut = section != null;
navigate(section);
}
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(navigationView)) {
drawer.closeDrawer(navigationView);
} else if (mDrawerItem != R.id.magisk && !fromShortcut) {
navigate(R.id.magisk);
} else {
finish();
}
}
@Override
public boolean onNavigationItemSelected(@NonNull final MenuItem menuItem) {
mDrawerHandler.removeCallbacksAndMessages(null);
mDrawerHandler.postDelayed(() -> navigate(menuItem.getItemId()), 250);
drawer.closeDrawer(navigationView);
return true;
}
public void checkHideSection() {
Menu menu = navigationView.getMenu();
menu.findItem(R.id.magiskhide).setVisible(Shell.rootAccess() &&
(boolean) Config.get(Config.Key.MAGISKHIDE));
menu.findItem(R.id.modules).setVisible(Shell.rootAccess() && Config.magiskVersionCode >= 0);
menu.findItem(R.id.downloads).setVisible(Networking.checkNetworkStatus(this)
&& Shell.rootAccess() && Config.magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(Utils.showSuperUser());
}
public void navigate(String item) {
int itemId = R.id.magisk;
if (item != null) {
switch (item) {
case "superuser":
itemId = R.id.superuser;
break;
case "modules":
itemId = R.id.modules;
break;
case "downloads":
itemId = R.id.downloads;
break;
case "magiskhide":
itemId = R.id.magiskhide;
break;
case "log":
itemId = R.id.log;
break;
case "settings":
itemId = R.id.settings;
break;
}
}
navigate(itemId);
}
public void navigate(int itemId) {
mDrawerItem = itemId;
navigationView.setCheckedItem(itemId);
switch (itemId) {
case R.id.magisk:
fromShortcut = false;
displayFragment(new MagiskFragment(), true);
break;
case R.id.superuser:
displayFragment(new SuperuserFragment(), true);
break;
case R.id.modules:
displayFragment(new ModulesFragment(), true);
break;
case R.id.downloads:
displayFragment(new ReposFragment(), true);
break;
case R.id.magiskhide:
displayFragment(new MagiskHideFragment(), true);
break;
case R.id.log:
displayFragment(new LogFragment(), false);
break;
case R.id.settings:
displayFragment(new SettingsFragment(), true);
break;
}
}
private void displayFragment(@NonNull Fragment navFragment, boolean setElevation) {
supportInvalidateOptionsMenu();
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_frame, navFragment)
.commitNow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbar.setElevation(setElevation ? toolbarElevation : 0);
}
}
}
package com.topjohnwu.magisk.ui
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.fragment.app.Fragment
import com.google.android.material.navigation.NavigationView
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ActivityMainBinding
import com.topjohnwu.magisk.ui.base.MagiskActivity
import com.topjohnwu.magisk.ui.hide.MagiskHideFragment
import com.topjohnwu.magisk.ui.home.MagiskFragment
import com.topjohnwu.magisk.ui.log.LogFragment
import com.topjohnwu.magisk.ui.module.ModulesFragment
import com.topjohnwu.magisk.ui.module.ReposFragment
import com.topjohnwu.magisk.ui.settings.SettingsFragment
import com.topjohnwu.magisk.ui.superuser.SuperuserFragment
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell
import kotlinx.android.synthetic.main.toolbar.*
import org.koin.androidx.viewmodel.ext.android.viewModel
open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>(),
NavigationView.OnNavigationItemSelectedListener {
override val layoutRes: Int = R.layout.activity_main
override val viewModel: MainViewModel by viewModel()
override val navHostId: Int = R.id.main_nav_host
private val mDrawerHandler = Handler()
private var mDrawerItem: Int = 0
private var toolbarElevation: Float = 0.toFloat()
/*override fun getDarkTheme(): Int {
return R.style.AppTheme_Dark
}*/
override fun onCreate(savedInstanceState: Bundle?) {
if (!SplashActivity.DONE) {
startActivity(Intent(this, ClassMap.get<Any>(SplashActivity::class.java)))
finish()
}
super.onCreate(savedInstanceState)
checkHideSection()
setSupportActionBar(toolbar)
val toggle = object :
ActionBarDrawerToggle(
this,
binding.drawerLayout,
toolbar,
R.string.magisk,
R.string.magisk
) {
override fun onDrawerOpened(drawerView: View) {
super.onDrawerOpened(drawerView)
super.onDrawerSlide(drawerView, 0f) // this disables the arrow @ completed tate
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
super.onDrawerSlide(drawerView, 0f) // this disables the animation
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbarElevation = toolbar!!.elevation
}
binding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
if (savedInstanceState == null) {
val section = intent.getStringExtra(Const.Key.OPEN_SECTION)
fromShortcut = section != null
navigate(section)
}
binding.navView.setNavigationItemSelectedListener(this)
}
override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(binding.navView)) {
binding.drawerLayout.closeDrawer(binding.navView)
} else if (mDrawerItem != R.id.magisk && !fromShortcut) {
navigate(R.id.magisk)
} else {
finish()
}
}
override fun onNavigationItemSelected(menuItem: MenuItem): Boolean {
mDrawerHandler.removeCallbacksAndMessages(null)
mDrawerHandler.postDelayed({ navigate(menuItem.itemId) }, 250)
binding.drawerLayout.closeDrawer(binding.navView)
return true
}
fun checkHideSection() {
val menu = binding.navView.menu
menu.findItem(R.id.magiskhide).isVisible =
Shell.rootAccess() && Config.get<Any>(Config.Key.MAGISKHIDE) as Boolean
menu.findItem(R.id.modules).isVisible = Shell.rootAccess() && Config.magiskVersionCode >= 0
menu.findItem(R.id.downloads).isVisible = (Networking.checkNetworkStatus(this)
&& Shell.rootAccess() && Config.magiskVersionCode >= 0)
menu.findItem(R.id.log).isVisible = Shell.rootAccess()
menu.findItem(R.id.superuser).isVisible = Utils.showSuperUser()
}
fun navigate(item: String?) {
var itemId = R.id.magisk
if (item != null) {
when (item) {
"superuser" -> itemId = R.id.superuser
"modules" -> itemId = R.id.modules
"downloads" -> itemId = R.id.downloads
"magiskhide" -> itemId = R.id.magiskhide
"log" -> itemId = R.id.log
"settings" -> itemId = R.id.settings
}
}
navigate(itemId)
}
fun navigate(itemId: Int) {
mDrawerItem = itemId
binding.navView.setCheckedItem(itemId)
when (itemId) {
R.id.magisk -> {
fromShortcut = false
displayFragment(MagiskFragment(), true)
}
R.id.superuser -> displayFragment(SuperuserFragment(), true)
R.id.modules -> displayFragment(ModulesFragment(), true)
R.id.downloads -> displayFragment(ReposFragment(), true)
R.id.magiskhide -> displayFragment(MagiskHideFragment(), true)
R.id.log -> displayFragment(LogFragment(), false)
R.id.settings -> displayFragment(SettingsFragment(), true)
}
}
@Deprecated("")
private fun displayFragment(navFragment: Fragment, setElevation: Boolean) {
/*supportInvalidateOptionsMenu();
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_frame, navFragment)
.commitNow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
toolbar.setElevation(setElevation ? toolbarElevation : 0);
}*/
}
companion object {
private var fromShortcut = false
}
}
package com.topjohnwu.magisk.ui
import com.topjohnwu.magisk.ui.base.MagiskViewModel
class MainViewModel : MagiskViewModel()
...@@ -153,7 +153,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Event.Au ...@@ -153,7 +153,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Event.Au
@Override @Override
public SharedPreferences getSharedPreferences(String name, int mode) { public SharedPreferences getSharedPreferences(String name, int mode) {
if (TextUtils.equals(name, getPackageName() + "_preferences")) if (TextUtils.equals(name, getPackageName() + "_preferences"))
return app.prefs; return app.getPrefs();
return super.getSharedPreferences(name, mode); return super.getSharedPreferences(name, mode);
} }
} }
...@@ -28,14 +28,14 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat ...@@ -28,14 +28,14 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = super.onCreateView(inflater, container, savedInstanceState); View v = super.onCreateView(inflater, container, savedInstanceState);
app.prefs.registerOnSharedPreferenceChangeListener(this); app.getPrefs().registerOnSharedPreferenceChangeListener(this);
Event.register(this); Event.register(this);
return v; return v;
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
app.prefs.unregisterOnSharedPreferenceChangeListener(this); app.getPrefs().unregisterOnSharedPreferenceChangeListener(this);
Event.unregister(this); Event.unregister(this);
super.onDestroyView(); super.onDestroyView();
} }
......
package com.topjohnwu.magisk.ui.base
import androidx.databinding.ViewDataBinding
import com.skoumal.teanity.view.TeanityActivity
abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
TeanityActivity<ViewModel, Binding>()
package com.topjohnwu.magisk.ui.base
import androidx.databinding.ViewDataBinding
import com.skoumal.teanity.view.TeanityFragment
abstract class MagiskFragment<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
TeanityFragment<ViewModel, Binding>()
package com.topjohnwu.magisk.ui.base
import com.skoumal.teanity.viewmodel.TeanityViewModel
abstract class MagiskViewModel : TeanityViewModel()
package com.topjohnwu.magisk.ui.log; package com.topjohnwu.magisk.ui.log;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
...@@ -10,7 +9,6 @@ import android.view.ViewGroup; ...@@ -10,7 +9,6 @@ import android.view.ViewGroup;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.model.adapters.TabFragmentAdapter; import com.topjohnwu.magisk.model.adapters.TabFragmentAdapter;
import com.topjohnwu.magisk.ui.MainActivity;
import com.topjohnwu.magisk.ui.base.BaseFragment; import com.topjohnwu.magisk.ui.base.BaseFragment;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
...@@ -28,9 +26,9 @@ public class LogFragment extends BaseFragment { ...@@ -28,9 +26,9 @@ public class LogFragment extends BaseFragment {
View v = inflater.inflate(R.layout.fragment_log, container, false); View v = inflater.inflate(R.layout.fragment_log, container, false);
unbinder = new LogFragment_ViewBinding(this, v); unbinder = new LogFragment_ViewBinding(this, v);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
((MainActivity) requireActivity()).toolbar.setElevation(0); ((MainActivity) requireActivity()).toolbar.setElevation(0);
} }*/
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager()); TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
......
...@@ -42,7 +42,7 @@ public class SuLogFragment extends BaseFragment { ...@@ -42,7 +42,7 @@ public class SuLogFragment extends BaseFragment {
// Inflate the layout for this fragment // Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_su_log, container, false); View v = inflater.inflate(R.layout.fragment_su_log, container, false);
unbinder = new SuLogFragment_ViewBinding(this, v); unbinder = new SuLogFragment_ViewBinding(this, v);
adapter = new SuLogAdapter(app.mDB); adapter = new SuLogAdapter(app.getDB());
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
updateList(); updateList();
...@@ -69,7 +69,7 @@ public class SuLogFragment extends BaseFragment { ...@@ -69,7 +69,7 @@ public class SuLogFragment extends BaseFragment {
updateList(); updateList();
return true; return true;
case R.id.menu_clear: case R.id.menu_clear:
app.mDB.clearLogs(); app.getDB().clearLogs();
updateList(); updateList();
return true; return true;
default: default:
......
...@@ -46,7 +46,7 @@ public class SettingsFragment extends BasePreferenceFragment { ...@@ -46,7 +46,7 @@ public class SettingsFragment extends BasePreferenceFragment {
requireActivity().setTitle(R.string.settings); requireActivity().setTitle(R.string.settings);
boolean showSuperuser = Utils.showSuperUser(); boolean showSuperuser = Utils.showSuperUser();
app.prefs.edit() app.getPrefs().edit()
.putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint()) .putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
.apply(); .apply();
...@@ -66,7 +66,7 @@ public class SettingsFragment extends BasePreferenceFragment { ...@@ -66,7 +66,7 @@ public class SettingsFragment extends BasePreferenceFragment {
return true; return true;
}); });
findPreference("clear").setOnPreferenceClickListener(pref -> { findPreference("clear").setOnPreferenceClickListener(pref -> {
app.prefs.edit().remove(Config.Key.ETAG_KEY).apply(); app.getPrefs().edit().remove(Config.Key.ETAG_KEY).apply();
app.repoDB.clearRepo(); app.repoDB.clearRepo();
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT); Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
return true; return true;
...@@ -94,7 +94,7 @@ public class SettingsFragment extends BasePreferenceFragment { ...@@ -94,7 +94,7 @@ public class SettingsFragment extends BasePreferenceFragment {
if (channel == Config.Value.CUSTOM_CHANNEL) { if (channel == Config.Value.CUSTOM_CHANNEL) {
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null); View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
EditText url = v.findViewById(R.id.custom_url); EditText url = v.findViewById(R.id.custom_url);
url.setText(app.prefs.getString(Config.Key.CUSTOM_CHANNEL, "")); url.setText(app.getPrefs().getString(Config.Key.CUSTOM_CHANNEL, ""));
new AlertDialog.Builder(requireActivity()) new AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom) .setTitle(R.string.settings_update_custom)
.setView(v) .setView(v)
...@@ -183,7 +183,7 @@ public class SettingsFragment extends BasePreferenceFragment { ...@@ -183,7 +183,7 @@ public class SettingsFragment extends BasePreferenceFragment {
case Config.Key.ROOT_ACCESS: case Config.Key.ROOT_ACCESS:
case Config.Key.SU_MULTIUSER_MODE: case Config.Key.SU_MULTIUSER_MODE:
case Config.Key.SU_MNT_NS: case Config.Key.SU_MNT_NS:
app.mDB.setSettings(key, Utils.getPrefsInt(prefs, key)); app.getDB().setSettings(key, Utils.getPrefsInt(prefs, key));
break; break;
case Config.Key.DARK_THEME: case Config.Key.DARK_THEME:
requireActivity().recreate(); requireActivity().recreate();
......
...@@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment { ...@@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment {
} }
private void displayPolicyList() { private void displayPolicyList() {
List<Policy> policyList = app.mDB.getPolicyList(); List<Policy> policyList = app.getDB().getPolicyList();
if (policyList.size() == 0) { if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE); emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE); recyclerView.setVisibility(View.GONE);
} else { } else {
recyclerView.setAdapter(new PolicyAdapter(policyList, app.mDB, pm)); recyclerView.setAdapter(new PolicyAdapter(policyList, app.getDB(), pm));
emptyRv.setVisibility(View.GONE); emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.VISIBLE);
} }
......
...@@ -107,8 +107,8 @@ public class SuRequestActivity extends BaseActivity { ...@@ -107,8 +107,8 @@ public class SuRequestActivity extends BaseActivity {
}; };
Bundle bundle = connector.readSocketInput(); Bundle bundle = connector.readSocketInput();
int uid = Integer.parseInt(bundle.getString("uid")); int uid = Integer.parseInt(bundle.getString("uid"));
app.mDB.clearOutdated(); app.getDB().clearOutdated();
policy = app.mDB.getPolicy(uid); policy = app.getDB().getPolicy(uid);
if (policy == null) { if (policy == null) {
policy = new Policy(uid, getPackageManager()); policy = new Policy(uid, getPackageManager());
} }
...@@ -136,7 +136,7 @@ public class SuRequestActivity extends BaseActivity { ...@@ -136,7 +136,7 @@ public class SuRequestActivity extends BaseActivity {
if (time >= 0) { if (time >= 0) {
policy.until = (time == 0) ? 0 policy.until = (time == 0) ? 0
: (System.currentTimeMillis() / 1000 + time * 60); : (System.currentTimeMillis() / 1000 + time * 60);
app.mDB.updatePolicy(policy); app.getDB().updatePolicy(policy);
} }
handleAction(); handleAction();
} }
......
...@@ -37,7 +37,7 @@ public class SuLogger { ...@@ -37,7 +37,7 @@ public class SuLogger {
} }
} else { } else {
// Doesn't report whether notify or not, check database ourselves // Doesn't report whether notify or not, check database ourselves
policy = app.mDB.getPolicy(fromUid); policy = app.getDB().getPolicy(fromUid);
if (policy == null) if (policy == null)
return; return;
notify = policy.notification; notify = policy.notification;
...@@ -62,7 +62,7 @@ public class SuLogger { ...@@ -62,7 +62,7 @@ public class SuLogger {
log.fromPid = pid; log.fromPid = pid;
log.command = command; log.command = command;
log.date = new Date(); log.date = new Date();
app.mDB.addLog(log); app.getDB().addLog(log);
} }
private static void handleNotify(Policy policy) { private static void handleNotify(Policy policy) {
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.topjohnwu.magisk.ui.MainViewModel" />
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:openDrawer="start"> tools:openDrawer="start">
<FrameLayout <include
android:layout_width="match_parent" layout="@layout/activity_main_content"
android:layout_height="match_parent" viewModel="@{viewModel}" />
android:background="?android:windowBackground"
android:orientation="vertical">
<FrameLayout
android:layout_marginTop="?attr/actionBarSize"
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="@layout/toolbar" />
</FrameLayout>
<com.google.android.material.navigation.NavigationView <com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view" android:id="@+id/nav_view"
...@@ -32,4 +30,7 @@ ...@@ -32,4 +30,7 @@
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
app:menu="@menu/drawer" /> app:menu="@menu/drawer" />
</androidx.drawerlayout.widget.DrawerLayout> </androidx.drawerlayout.widget.DrawerLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.topjohnwu.magisk.ui.MainViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/toolbar" />
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/main_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
app:defaultNavHost="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:navGraph="@navigation/navigation_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" <androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
android:elevation="4dp"/> app:elevation="4dp" />
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_main"
app:startDestination="@id/magiskFragment">
<fragment
android:id="@+id/magiskFragment"
android:name="com.topjohnwu.magisk.ui.home.MagiskFragment"
android:label="fragment_magisk"
tools:layout="@layout/fragment_magisk" />
</navigation>
...@@ -16,8 +16,8 @@ buildscript { ...@@ -16,8 +16,8 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools:r8:1.4.79' classpath 'com.android.tools:r8:1.4.79'
classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21" classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.0.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
...@@ -36,7 +36,9 @@ subprojects { ...@@ -36,7 +36,9 @@ subprojects {
repositories { repositories {
google() google()
jcenter() jcenter()
maven { url "https://maven.fabric.io/public" }
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
maven { url "http://oss.sonatype.org/content/repositories/snapshots" }
} }
afterEvaluate { afterEvaluate {
if (getPlugins().hasPlugin('com.android.library') || if (getPlugins().hasPlugin('com.android.library') ||
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment