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
This commit is contained in:
Viktor De Pasquale 2019-04-11 20:01:49 +02:00
parent e035523eb8
commit 2d58c725e0
32 changed files with 524 additions and 380 deletions

View File

@ -30,6 +30,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
}
dependencies {
@ -64,12 +68,13 @@ dependencies {
implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
implementation ("com.github.skoumalcz:teanity:0.3.3") {
exclude group: 'com.karumi', module: 'dexter'
exclude group: 'com.evernote', module: 'android-state'
def koin = "2.0.0-rc-2"
implementation("org.koin:koin-core:${koin}")
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.room', module: 'room-runtime'
exclude group: 'io.reactivex.rxjava2', module: 'rxkotlin' //hopefully not forever
exclude group: 'io.reactivex.rxjava2', module: 'rxandroid' //hopefully not forever
}
}

View File

@ -1,101 +0,0 @@
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) {}
}

View File

@ -0,0 +1,120 @@
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
}
}
}

View File

@ -3,8 +3,6 @@ package com.topjohnwu.magisk;
import android.content.SharedPreferences;
import android.util.Xml;
import androidx.collection.ArrayMap;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
@ -17,6 +15,8 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.IOException;
import androidx.collection.ArrayMap;
public class Config {
// Current status
@ -109,14 +109,14 @@ public class Config {
public static void export() {
// Flush prefs to disk
App app = App.self;
app.prefs.edit().commit();
app.getPrefs().edit().commit();
File xml = new File(App.deContext.getFilesDir().getParent() + "/shared_prefs",
app.getPackageName() + "_preferences.xml");
Shell.su(Utils.fmt("cat %s > /data/adb/%s", xml, Const.MANAGER_CONFIGS)).exec();
}
public static void initialize() {
SharedPreferences pref = App.self.prefs;
SharedPreferences pref = App.self.getPrefs();
SharedPreferences.Editor editor = pref.edit();
File config = SuFile.open("/data/adb", Const.MANAGER_CONFIGS);
if (config.exists()) {
@ -238,19 +238,19 @@ public class Config {
App app = App.self;
switch (getConfigType(key)) {
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:
return (T) (Integer) Utils.getPrefsInt(app.prefs, key, getDef(key));
return (T) (Integer) Utils.getPrefsInt(app.getPrefs(), key, getDef(key));
case PREF_BOOL:
return (T) (Boolean) app.prefs.getBoolean(key, getDef(key));
return (T) (Boolean) app.getPrefs().getBoolean(key, getDef(key));
case PREF_STR:
return (T) app.prefs.getString(key, getDef(key));
return (T) app.getPrefs().getString(key, getDef(key));
case DB_INT:
return (T) (Integer) app.mDB.getSettings(key, getDef(key));
return (T) (Integer) app.getDB().getSettings(key, getDef(key));
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:
return (T) app.mDB.getStrings(key, getDef(key));
return (T) app.getDB().getStrings(key, getDef(key));
}
/* Will never get here (IllegalArgumentException in getConfigType) */
return null;
@ -260,25 +260,25 @@ public class Config {
App app = App.self;
switch (getConfigType(key)) {
case PREF_INT:
app.prefs.edit().putInt(key, (int) val).apply();
app.getPrefs().edit().putInt(key, (int) val).apply();
break;
case PREF_STR_INT:
app.prefs.edit().putString(key, String.valueOf(val)).apply();
app.getPrefs().edit().putString(key, String.valueOf(val)).apply();
break;
case PREF_BOOL:
app.prefs.edit().putBoolean(key, (boolean) val).apply();
app.getPrefs().edit().putBoolean(key, (boolean) val).apply();
break;
case PREF_STR:
app.prefs.edit().putString(key, (String) val).apply();
app.getPrefs().edit().putString(key, (String) val).apply();
break;
case DB_INT:
app.mDB.setSettings(key, (int) val);
app.getDB().setSettings(key, (int) val);
break;
case DB_BOOL:
app.mDB.setSettings(key, (boolean) val ? 1 : 0);
app.getDB().setSettings(key, (boolean) val ? 1 : 0);
break;
case DB_STR:
app.mDB.setStrings(key, (String) val);
app.getDB().setStrings(key, (String) val);
break;
}
}
@ -290,14 +290,14 @@ public class Config {
case PREF_STR_INT:
case PREF_BOOL:
case PREF_STR:
app.prefs.edit().remove(key).apply();
app.getPrefs().edit().remove(key).apply();
break;
case DB_BOOL:
case DB_INT:
app.mDB.rmSettings(key);
app.getDB().rmSettings(key);
break;
case DB_STR:
app.mDB.setStrings(key, null);
app.getDB().setStrings(key, null);
break;
}
}
@ -365,13 +365,13 @@ public class Config {
switch (type) {
case DB_INT:
editor.putString(key, String.valueOf(
app.mDB.getSettings(key, (Integer) defs.get(key))));
app.getDB().getSettings(key, (Integer) defs.get(key))));
continue;
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;
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);
continue;
}

View File

@ -0,0 +1,11 @@
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 }
}

View File

@ -0,0 +1,6 @@
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val databaseModule = module {}

View File

@ -0,0 +1,10 @@
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val miscModule = module {
// define miscs here
}

View File

@ -0,0 +1,10 @@
package com.topjohnwu.magisk.di
val koinModules = listOf(
applicationModule,
networkingModule,
databaseModule,
repositoryModule,
viewModelModules,
miscModule
)

View File

@ -0,0 +1,6 @@
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val networkingModule = module {}

View File

@ -0,0 +1,6 @@
package com.topjohnwu.magisk.di
import org.koin.dsl.module
val repositoryModule = module {}

View File

@ -0,0 +1,10 @@
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() }
}

View File

@ -0,0 +1,4 @@
package com.topjohnwu.magisk.model.navigation
object Navigation

View File

@ -61,12 +61,12 @@ public class GeneralReceiver extends BroadcastReceiver {
case Intent.ACTION_PACKAGE_REPLACED:
// This will only work pre-O
if (Config.get(Config.Key.SU_REAUTH)) {
app.mDB.deletePolicy(getPkg(intent));
app.getDB().deletePolicy(getPkg(intent));
}
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
String pkg = getPkg(intent);
app.mDB.deletePolicy(pkg);
app.getDB().deletePolicy(pkg);
Shell.su("magiskhide --rm " + pkg).submit();
break;
case Intent.ACTION_LOCALE_CHANGED:

View File

@ -1,193 +0,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.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);
}
}
}

View File

@ -0,0 +1,166 @@
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
}
}

View File

@ -0,0 +1,6 @@
package com.topjohnwu.magisk.ui
import com.topjohnwu.magisk.ui.base.MagiskViewModel
class MainViewModel : MagiskViewModel()

View File

@ -153,7 +153,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Event.Au
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
if (TextUtils.equals(name, getPackageName() + "_preferences"))
return app.prefs;
return app.getPrefs();
return super.getSharedPreferences(name, mode);
}
}

View File

@ -28,14 +28,14 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = super.onCreateView(inflater, container, savedInstanceState);
app.prefs.registerOnSharedPreferenceChangeListener(this);
app.getPrefs().registerOnSharedPreferenceChangeListener(this);
Event.register(this);
return v;
}
@Override
public void onDestroyView() {
app.prefs.unregisterOnSharedPreferenceChangeListener(this);
app.getPrefs().unregisterOnSharedPreferenceChangeListener(this);
Event.unregister(this);
super.onDestroyView();
}

View File

@ -0,0 +1,8 @@
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>()

View File

@ -0,0 +1,8 @@
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>()

View File

@ -0,0 +1,6 @@
package com.topjohnwu.magisk.ui.base
import com.skoumal.teanity.viewmodel.TeanityViewModel
abstract class MagiskViewModel : TeanityViewModel()

View File

@ -1,7 +1,6 @@
package com.topjohnwu.magisk.ui.log;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -10,7 +9,6 @@ import android.view.ViewGroup;
import com.google.android.material.tabs.TabLayout;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.model.adapters.TabFragmentAdapter;
import com.topjohnwu.magisk.ui.MainActivity;
import com.topjohnwu.magisk.ui.base.BaseFragment;
import androidx.viewpager.widget.ViewPager;
@ -28,9 +26,9 @@ public class LogFragment extends BaseFragment {
View v = inflater.inflate(R.layout.fragment_log, container, false);
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);
}
}*/
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());

View File

@ -42,7 +42,7 @@ public class SuLogFragment extends BaseFragment {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
unbinder = new SuLogFragment_ViewBinding(this, v);
adapter = new SuLogAdapter(app.mDB);
adapter = new SuLogAdapter(app.getDB());
recyclerView.setAdapter(adapter);
updateList();
@ -69,7 +69,7 @@ public class SuLogFragment extends BaseFragment {
updateList();
return true;
case R.id.menu_clear:
app.mDB.clearLogs();
app.getDB().clearLogs();
updateList();
return true;
default:

View File

@ -46,7 +46,7 @@ public class SettingsFragment extends BasePreferenceFragment {
requireActivity().setTitle(R.string.settings);
boolean showSuperuser = Utils.showSuperUser();
app.prefs.edit()
app.getPrefs().edit()
.putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
.apply();
@ -66,7 +66,7 @@ public class SettingsFragment extends BasePreferenceFragment {
return true;
});
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();
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
return true;
@ -94,7 +94,7 @@ public class SettingsFragment extends BasePreferenceFragment {
if (channel == Config.Value.CUSTOM_CHANNEL) {
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
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())
.setTitle(R.string.settings_update_custom)
.setView(v)
@ -183,7 +183,7 @@ public class SettingsFragment extends BasePreferenceFragment {
case Config.Key.ROOT_ACCESS:
case Config.Key.SU_MULTIUSER_MODE:
case Config.Key.SU_MNT_NS:
app.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
app.getDB().setSettings(key, Utils.getPrefsInt(prefs, key));
break;
case Config.Key.DARK_THEME:
requireActivity().recreate();

View File

@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment {
}
private void displayPolicyList() {
List<Policy> policyList = app.mDB.getPolicyList();
List<Policy> policyList = app.getDB().getPolicyList();
if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
recyclerView.setAdapter(new PolicyAdapter(policyList, app.mDB, pm));
recyclerView.setAdapter(new PolicyAdapter(policyList, app.getDB(), pm));
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}

View File

@ -107,8 +107,8 @@ public class SuRequestActivity extends BaseActivity {
};
Bundle bundle = connector.readSocketInput();
int uid = Integer.parseInt(bundle.getString("uid"));
app.mDB.clearOutdated();
policy = app.mDB.getPolicy(uid);
app.getDB().clearOutdated();
policy = app.getDB().getPolicy(uid);
if (policy == null) {
policy = new Policy(uid, getPackageManager());
}
@ -136,7 +136,7 @@ public class SuRequestActivity extends BaseActivity {
if (time >= 0) {
policy.until = (time == 0) ? 0
: (System.currentTimeMillis() / 1000 + time * 60);
app.mDB.updatePolicy(policy);
app.getDB().updatePolicy(policy);
}
handleAction();
}

View File

@ -37,7 +37,7 @@ public class SuLogger {
}
} else {
// Doesn't report whether notify or not, check database ourselves
policy = app.mDB.getPolicy(fromUid);
policy = app.getDB().getPolicy(fromUid);
if (policy == null)
return;
notify = policy.notification;
@ -62,7 +62,7 @@ public class SuLogger {
log.fromPid = pid;
log.command = command;
log.date = new Date();
app.mDB.addLog(log);
app.getDB().addLog(log);
}
private static void handleNotify(Policy policy) {

View File

@ -1,35 +1,36 @@
<?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:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
<data>
<variable
name="viewModel"
type="com.topjohnwu.magisk.ui.MainViewModel" />
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
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
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/drawer" />
tools:openDrawer="start">
</androidx.drawerlayout.widget.DrawerLayout>
<include
layout="@layout/activity_main_content"
viewModel="@{viewModel}" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>

View File

@ -0,0 +1,40 @@
<?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>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.appcompat.widget.Toolbar 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_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"/>
app:elevation="4dp" />

View File

@ -0,0 +1,14 @@
<?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>

View File

@ -7,7 +7,7 @@ if (configPath.exists())
configPath.withInputStream { is -> props.load(is) }
buildscript {
repositories {
google()
jcenter()
@ -16,8 +16,8 @@ buildscript {
dependencies {
classpath 'com.android.tools:r8:1.4.79'
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
// in the individual module build.gradle files
@ -36,11 +36,13 @@ subprojects {
repositories {
google()
jcenter()
maven { url "https://maven.fabric.io/public" }
maven { url "https://jitpack.io" }
maven { url "http://oss.sonatype.org/content/repositories/snapshots" }
}
afterEvaluate {
if (getPlugins().hasPlugin('com.android.library') ||
getPlugins().hasPlugin('com.android.application')) {
getPlugins().hasPlugin('com.android.application')) {
android {
compileSdkVersion 'android-Q'
buildToolsVersion '29.0.0-rc2'