diff --git a/app/build.gradle b/app/build.gradle index e4e77b7a3..84ac3affd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 } } diff --git a/app/src/main/java/com/topjohnwu/magisk/App.java b/app/src/main/java/com/topjohnwu/magisk/App.java deleted file mode 100644 index 179419249..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/App.java +++ /dev/null @@ -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) {} -} diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt new file mode 100644 index 000000000..2d9b5d679 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/App.kt @@ -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 + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/Config.java b/app/src/main/java/com/topjohnwu/magisk/Config.java index 10f4119ea..76f4580ba 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Config.java +++ b/app/src/main/java/com/topjohnwu/magisk/Config.java @@ -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; } diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt new file mode 100644 index 000000000..09fd26d68 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/ApplicationModule.kt @@ -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().resources } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt new file mode 100644 index 000000000..b3c44dc0d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.di + +import org.koin.dsl.module + + +val databaseModule = module {} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/MiscModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/MiscModule.kt new file mode 100644 index 000000000..037a9edd6 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/MiscModule.kt @@ -0,0 +1,10 @@ +package com.topjohnwu.magisk.di + +import org.koin.dsl.module + + +val miscModule = module { + + // define miscs here + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/Modules.kt b/app/src/main/java/com/topjohnwu/magisk/di/Modules.kt new file mode 100644 index 000000000..850e09c88 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/Modules.kt @@ -0,0 +1,10 @@ +package com.topjohnwu.magisk.di + +val koinModules = listOf( + applicationModule, + networkingModule, + databaseModule, + repositoryModule, + viewModelModules, + miscModule +) diff --git a/app/src/main/java/com/topjohnwu/magisk/di/NetworkingModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/NetworkingModule.kt new file mode 100644 index 000000000..e3cd89d17 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/NetworkingModule.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.di + +import org.koin.dsl.module + + +val networkingModule = module {} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt new file mode 100644 index 000000000..0d55b410c --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.di + +import org.koin.dsl.module + + +val repositoryModule = module {} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt new file mode 100644 index 000000000..523a7bdfc --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -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() } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt b/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt new file mode 100644 index 000000000..133bb88fe --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt @@ -0,0 +1,4 @@ +package com.topjohnwu.magisk.model.navigation + + +object Navigation diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java index dd71c7f09..0a7432c4d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java @@ -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: diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.java b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.java deleted file mode 100644 index 3da71cf37..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.java +++ /dev/null @@ -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); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt new file mode 100644 index 000000000..33040ba88 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt @@ -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(), + 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(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(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 + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt new file mode 100644 index 000000000..c77002d3e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.ui + +import com.topjohnwu.magisk.ui.base.MagiskViewModel + + +class MainViewModel : MagiskViewModel() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseActivity.java b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseActivity.java index ed42d5b10..8abb0602b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseActivity.java @@ -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); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/BasePreferenceFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/base/BasePreferenceFragment.java index 02e04ac3e..89e072b26 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/BasePreferenceFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/BasePreferenceFragment.java @@ -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(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt new file mode 100644 index 000000000..f93e766e0 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt @@ -0,0 +1,8 @@ +package com.topjohnwu.magisk.ui.base + +import androidx.databinding.ViewDataBinding +import com.skoumal.teanity.view.TeanityActivity + + +abstract class MagiskActivity : + TeanityActivity() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt new file mode 100644 index 000000000..024b00492 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt @@ -0,0 +1,8 @@ +package com.topjohnwu.magisk.ui.base + +import androidx.databinding.ViewDataBinding +import com.skoumal.teanity.view.TeanityFragment + + +abstract class MagiskFragment : + TeanityFragment() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt new file mode 100644 index 000000000..ca82d4039 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt @@ -0,0 +1,6 @@ +package com.topjohnwu.magisk.ui.base + +import com.skoumal.teanity.viewmodel.TeanityViewModel + + +abstract class MagiskViewModel : TeanityViewModel() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java index d684e1d6f..871563a0b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java @@ -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()); diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java index 9f6595d00..07e42adaf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java @@ -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: diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.java index 7938275b8..f5ec2f56d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.java @@ -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(); diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.java b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.java index 2f5beaf7b..a78ca91ed 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.java @@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment { } private void displayPolicyList() { - List policyList = app.mDB.getPolicyList(); + List 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); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.java b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.java index 481956be5..674f62c44 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.java @@ -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(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.java b/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.java index 888a65262..17d7c9286 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.java @@ -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) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3489c737c..702fc71b1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,35 +1,36 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + + + + - - - - - - - - + tools:openDrawer="start"> - + + + + + + + + diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml new file mode 100644 index 000000000..b86eafce2 --- /dev/null +++ b/app/src/main/res/layout/activity_main_content.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index f96cb2eb8..a02d7099c 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -1,7 +1,8 @@ - + app:elevation="4dp" /> diff --git a/app/src/main/res/navigation/navigation_main.xml b/app/src/main/res/navigation/navigation_main.xml new file mode 100644 index 000000000..ee4201d1b --- /dev/null +++ b/app/src/main/res/navigation/navigation_main.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/build.gradle b/build.gradle index 471d50845..7f770a079 100644 --- a/build.gradle +++ b/build.gradle @@ -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'