diff --git a/README.MD b/README.MD index 30e1f2f38..fe265eb69 100644 --- a/README.MD +++ b/README.MD @@ -38,6 +38,27 @@ Default string resources for Magisk Manager are scattered throughout Translate each and place them in the respective locations (`/src/main/res/values-/strings.xml`). +## Signature Verification + +Official release zips and APKs are signed with my personal private key. You can verify the key certificate to make sure the binaries you downloaded are not manipulated in anyway. + +``` bash +# Use the keytool command from JDK to print certificates +keytool -printcert -jarfile + +# The output should contain the following signature +Owner: CN=John Wu, L=Taipei, C=TW +Issuer: CN=John Wu, L=Taipei, C=TW +Serial number: 50514879 +Valid from: Sun Aug 14 13:23:44 EDT 2016 until: Tue Jul 21 13:23:44 EDT 2116 +Certificate fingerprints: + MD5: CE:DA:68:C1:E1:74:71:0A:EF:58:89:7D:AE:6E:AB:4F + SHA1: DC:0F:2B:61:CB:D7:E9:D3:DB:BE:06:0B:2B:87:0D:46:BB:06:02:11 + SHA256: B4:CB:83:B4:DA:D9:9F:99:7D:BE:87:2F:01:3A:A1:6C:14:EE:C4:1D:16:70:21:F3:71:F7:E1:33:0F:27:3E:E6 + Signature algorithm name: SHA256withRSA + Version: 3 +``` + ## License Magisk, including all git submodules are free software: diff --git a/app/build.gradle b/app/build.gradle index dbc98c4fa..fbdb42cf9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,10 +59,6 @@ dependencies { implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" implementation "com.github.topjohnwu.libsu:io:${libsuVersion}" - def butterKnifeVersion = '10.1.0' - implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}" - kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}" - def koin = "2.0.0-rc-2" implementation "org.koin:koin-core:${koin}" implementation "org.koin:koin-android:${koin}" diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt index 0c59ce6cf..9983734a8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -1,6 +1,5 @@ package com.topjohnwu.magisk.di -import android.content.Intent import android.net.Uri import com.topjohnwu.magisk.ui.MainViewModel import com.topjohnwu.magisk.ui.flash.FlashViewModel @@ -10,7 +9,6 @@ import com.topjohnwu.magisk.ui.log.LogViewModel import com.topjohnwu.magisk.ui.module.ModuleViewModel import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel -import com.topjohnwu.magisk.ui.surequest._SuRequestViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module @@ -23,8 +21,5 @@ val viewModelModules = module { viewModel { ModuleViewModel(get(), get()) } viewModel { LogViewModel(get(), get()) } viewModel { (action: String, uri: Uri?) -> FlashViewModel(action, uri, get()) } - viewModel { (intent: Intent, action: String?) -> - _SuRequestViewModel(intent, action.orEmpty(), get(), get()) - } viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/state/IndeterminateState.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/state/IndeterminateState.kt index ba381e695..43b97f12d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/state/IndeterminateState.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/state/IndeterminateState.kt @@ -1,5 +1,5 @@ package com.topjohnwu.magisk.model.entity.state enum class IndeterminateState { - INDETERMINATE, CHECKED, UNCHECKED -} \ No newline at end of file + CHECKED, INDETERMINATE, UNCHECKED +} 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 index 361c79cb9..a08e4c15a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt @@ -1,7 +1,7 @@ package com.topjohnwu.magisk.model.navigation import com.topjohnwu.magisk.ui.hide.MagiskHideFragment -import com.topjohnwu.magisk.ui.home.MagiskFragment +import com.topjohnwu.magisk.ui.home.HomeFragment import com.topjohnwu.magisk.ui.log.LogFragment import com.topjohnwu.magisk.ui.module.ModulesFragment import com.topjohnwu.magisk.ui.module.ReposFragment @@ -12,8 +12,8 @@ import com.topjohnwu.magisk.ui.superuser.SuperuserFragment object Navigation { fun home() = MagiskNavigationEvent { - navDirections { destination = MagiskFragment::class } - navOptions { popUpTo = MagiskFragment::class } + navDirections { destination = HomeFragment::class } + navOptions { popUpTo = HomeFragment::class } } fun superuser() = MagiskNavigationEvent { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt index 6ab8b1e81..b21e89a5e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt @@ -12,6 +12,7 @@ import com.topjohnwu.magisk.databinding.ActivityMainBinding import com.topjohnwu.magisk.model.navigation.Navigation import com.topjohnwu.magisk.ui.base.MagiskActivity import com.topjohnwu.magisk.ui.hide.MagiskHideFragment +import com.topjohnwu.magisk.ui.home.HomeFragment import com.topjohnwu.magisk.ui.log.LogFragment import com.topjohnwu.magisk.ui.module.ModulesFragment import com.topjohnwu.magisk.ui.module.ReposFragment @@ -22,7 +23,6 @@ import com.topjohnwu.net.Networking import com.topjohnwu.superuser.Shell import org.koin.androidx.viewmodel.ext.android.viewModel import kotlin.reflect.KClass -import com.topjohnwu.magisk.ui.home.MagiskFragment as HomeFragment open class MainActivity : MagiskActivity() { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt index 897196b3a..2e60d5d5a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt @@ -14,6 +14,7 @@ import com.topjohnwu.magisk.model.entity.HideAppInfo import com.topjohnwu.magisk.model.entity.HideTarget import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem import com.topjohnwu.magisk.model.entity.recycler.HideRvItem +import com.topjohnwu.magisk.model.entity.state.IndeterminateState import com.topjohnwu.magisk.model.events.HideProcessEvent import com.topjohnwu.magisk.ui.base.MagiskViewModel import com.topjohnwu.magisk.utils.Utils @@ -72,7 +73,8 @@ class HideViewModel( .filter { it.processes.isNotEmpty() } .map { HideRvItem(it, hideTargets.blockingGet()) } .toList() - .map { it.sortBy { it.item.info.name }; it } + .map { it.sortWith(compareBy( + {it.isHiddenState.value}, {it.item.info.name}, {it.packageName})); it } .doOnSuccess { allItems.update(it) } .flatMap { queryRaw() } .applyViewModel(this) @@ -94,7 +96,10 @@ class HideViewModel( it.item.name.contains(query, ignoreCase = true) || it.item.processes.any { it.contains(query, ignoreCase = true) } } - .filter { if (showSystem) true else it.item.info.flags and ApplicationInfo.FLAG_SYSTEM == 0 } + .filter { + showSystem || (it.isHiddenState.value != IndeterminateState.UNCHECKED) || + (it.item.info.flags and ApplicationInfo.FLAG_SYSTEM == 0) + } .toList() .map { it to items.calculateDiff(it) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt similarity index 76% rename from app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt rename to app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt index 11a4d8554..a04f3ee3e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt @@ -1,24 +1,22 @@ package com.topjohnwu.magisk.ui.home +import android.app.Activity import com.skoumal.teanity.viewevents.ViewEvent -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.databinding.FragmentMagiskBinding import com.topjohnwu.magisk.model.events.* import com.topjohnwu.magisk.ui.base.MagiskActivity +import com.topjohnwu.magisk.ui.base.MagiskFragment import com.topjohnwu.magisk.utils.ISafetyNetHelper import com.topjohnwu.magisk.view.MarkDownWindow -import com.topjohnwu.magisk.view.SafetyNet -import com.topjohnwu.magisk.view.SafetyNet.EXT_APK import com.topjohnwu.magisk.view.dialogs.* import com.topjohnwu.net.Networking import com.topjohnwu.superuser.Shell +import dalvik.system.DexClassLoader import org.koin.androidx.viewmodel.ext.android.viewModel -import com.topjohnwu.magisk.ui.base.MagiskFragment as NewMagiskFragment +import java.io.File -class MagiskFragment : NewMagiskFragment(), +class HomeFragment : MagiskFragment(), ISafetyNetHelper.Callback { override val layoutRes: Int = R.layout.fragment_magisk @@ -83,7 +81,16 @@ class MagiskFragment : NewMagiskFragment() private fun updateSafetyNet(dieOnError: Boolean) { try { - SafetyNet.dyRun(requireActivity(), this) + val loader = DexClassLoader(EXT_APK.path, EXT_APK.parent, null, + ISafetyNetHelper::class.java.classLoader) + val clazz = loader.loadClass("com.topjohnwu.snet.Snet") + val helper = clazz.getMethod("newHelper", + Class::class.java, String::class.java, Activity::class.java, Any::class.java) + .invoke(null, ISafetyNetHelper::class.java, EXT_APK.path, + requireActivity(), this) as ISafetyNetHelper + if (helper.version < Const.SNET_EXT_VER) + throw Exception() + helper.attest() } catch (e: Exception) { if (dieOnError) { viewModel.finishSafetyNetCheck(-1) @@ -94,5 +101,9 @@ class MagiskFragment : NewMagiskFragment() downloadSafetyNet(!dieOnError) } } + + companion object { + val EXT_APK = File("${App.self.filesDir.parent}/snet", "snet.apk") + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestActivity.kt deleted file mode 100644 index 4bfefa221..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestActivity.kt +++ /dev/null @@ -1,166 +0,0 @@ -package com.topjohnwu.magisk.ui.surequest - -import android.hardware.fingerprint.FingerprintManager -import android.os.CountDownTimer -import android.text.SpannableStringBuilder -import android.widget.Toast -import androidx.core.text.bold -import com.skoumal.teanity.viewevents.ViewEvent -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.databinding.ActivitySuRequestBinding -import com.topjohnwu.magisk.model.entity.Policy -import com.topjohnwu.magisk.model.events.DieEvent -import com.topjohnwu.magisk.model.events.SuDialogEvent -import com.topjohnwu.magisk.ui.base.MagiskActivity -import com.topjohnwu.magisk.utils.FingerprintHelper -import com.topjohnwu.magisk.utils.feature.WIP -import com.topjohnwu.magisk.view.MagiskDialog -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf -import timber.log.Timber -import java.util.concurrent.TimeUnit.MILLISECONDS -import java.util.concurrent.TimeUnit.SECONDS - -@WIP -open class _SuRequestActivity : MagiskActivity<_SuRequestViewModel, ActivitySuRequestBinding>() { - - override val layoutRes: Int = R.layout.activity_su_request - override val viewModel: _SuRequestViewModel by viewModel { - parametersOf(intent, intent.action) - } - - //private val timeoutPrefs: SharedPreferences by inject(SUTimeout) - private val canUseFingerprint get() = FingerprintHelper.useFingerprint() - - private val countdown by lazy { - val seconds = Config.get(Config.Key.SU_REQUEST_TIMEOUT).toLong() - val millis = SECONDS.toMillis(seconds) - object : CountDownTimer(millis, 1000) { - override fun onFinish() { - viewModel.deny() - } - - override fun onTick(millisUntilFinished: Long) { - dialog.applyButton(MagiskDialog.ButtonType.NEGATIVE) { - Timber.e("Tick, tock") - title = "%s (%d)".format( - getString(R.string.deny), - MILLISECONDS.toSeconds(millisUntilFinished) - ) - } - } - } - } - - private var fingerprintHelper: SuFingerprint? = null - - private lateinit var dialog: MagiskDialog - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is SuDialogEvent -> showDialog(event.policy) - is DieEvent -> finish() - } - } - - override fun onBackPressed() { - if (::dialog.isInitialized && dialog.isShowing) { - return - } - super.onBackPressed() - } - - override fun onDestroy() { - if (this::dialog.isInitialized && dialog.isShowing) { - dialog.dismiss() - } - fingerprintHelper?.cancel() - countdown.cancel() - super.onDestroy() - } - - private fun showDialog(policy: Policy) { - val titleText = SpannableStringBuilder("Allow ") - .bold { append(policy.appName) } - .append(" to access superuser rights?") - - val messageText = StringBuilder() - .appendln(policy.packageName) - .append(getString(R.string.su_warning)) - - dialog = MagiskDialog(this) - .applyIcon(policy.info.loadIcon(packageManager)) - .applyTitle(titleText) - .applyMessage(messageText) - //.applyView()) {} //todo add a spinner - .cancellable(false) - .applyButton(MagiskDialog.ButtonType.POSITIVE) { - titleRes = R.string.grant - onClick { viewModel.grant() } - if (canUseFingerprint) { - icon = R.drawable.ic_fingerprint - } - } - .applyButton(MagiskDialog.ButtonType.NEUTRAL) { - title = "%s %s".format(getString(R.string.grant), getString(R.string.once)) - onClick { viewModel.grant(-1) } - } - .applyButton(MagiskDialog.ButtonType.NEGATIVE) { - titleRes = R.string.deny - onClick { viewModel.deny() } - } - .onDismiss { finish() } - .onShow { - startTimer().also { Timber.e("Starting timer") } - if (canUseFingerprint) { - startFingerprintQuery() - } - } - .reveal() - } - - private fun startTimer() { - countdown.start() - } - - private fun startFingerprintQuery() { - val result = runCatching { - fingerprintHelper = SuFingerprint().apply { authenticate() } - } - - if (result.isFailure) { - dialog.applyButton(MagiskDialog.ButtonType.POSITIVE) { - icon = 0 - } - } - } - - private inner class SuFingerprint @Throws(Exception::class) - internal constructor() : FingerprintHelper() { - - override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { - Toast.makeText(this@_SuRequestActivity, errString, Toast.LENGTH_LONG).show() - } - - override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) { - Toast.makeText(this@_SuRequestActivity, helpString, Toast.LENGTH_LONG).show() - } - - override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { - viewModel.grant() - } - - override fun onAuthenticationFailed() { - Toast.makeText(this@_SuRequestActivity, R.string.auth_fail, Toast.LENGTH_LONG).show() - } - } - - companion object { - - const val REQUEST = "request" - const val LOG = "log" - const val NOTIFY = "notify" - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestViewModel.kt deleted file mode 100644 index 4ac1c1ea0..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/_SuRequestViewModel.kt +++ /dev/null @@ -1,112 +0,0 @@ -package com.topjohnwu.magisk.ui.surequest - -import android.content.Intent -import android.content.pm.PackageManager -import com.skoumal.teanity.extensions.subscribeK -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.data.database.MagiskDB -import com.topjohnwu.magisk.model.entity.Policy -import com.topjohnwu.magisk.model.events.DieEvent -import com.topjohnwu.magisk.model.events.SuDialogEvent -import com.topjohnwu.magisk.ui.base.MagiskViewModel -import com.topjohnwu.magisk.utils.SuConnector -import com.topjohnwu.magisk.utils.SuLogger -import com.topjohnwu.magisk.utils.feature.WIP -import com.topjohnwu.magisk.utils.now -import io.reactivex.Single -import timber.log.Timber -import java.util.concurrent.TimeUnit.MILLISECONDS -import java.util.concurrent.TimeUnit.MINUTES - -@WIP -class _SuRequestViewModel( - intent: Intent, - action: String, - private val packageManager: PackageManager, - private val database: MagiskDB -) : MagiskViewModel() { - - private val connector: Single = Single.fromCallable { - val socketName = intent.extras?.getString("socket") ?: let { - deny() - throw IllegalStateException("Socket is empty or null") - } - object : SuConnector(socketName) { - override fun onResponse() { - policy.subscribeK { out.writeInt(it.policy) } //this just might be incorrect, lol - } - } as SuConnector - }.cache() - - private val policy: Single = connector.map { - val bundle = it.readSocketInput() ?: throw IllegalStateException("Socket bundle is null") - val uid = bundle.getString("uid")?.toIntOrNull() ?: let { - deny() - throw IllegalStateException("UID is empty or null") - } - database.clearOutdated() - database.getPolicy(uid) ?: Policy(uid, packageManager) - }.cache() - - init { - when (action) { - SuRequestActivity.LOG -> SuLogger.handleLogs(intent).also { die() } - SuRequestActivity.NOTIFY -> SuLogger.handleNotify(intent).also { die() } - SuRequestActivity.REQUEST -> process() - else -> back() // invalid action, should ignore - } - } - - private fun process() { - policy.subscribeK(onError = ::deny) { process(it) } - } - - private fun process(policy: Policy) { - if (policy.packageName == BuildConfig.APPLICATION_ID) - deny().also { return } - - if (policy.policy != Policy.INTERACTIVE) - grant().also { return } - - when (Config.get(Config.Key.SU_AUTO_RESPONSE)) { - Config.Value.SU_AUTO_DENY -> deny().also { return } - Config.Value.SU_AUTO_ALLOW -> grant().also { return } - } - - requestDialog(policy) - } - - fun deny(e: Throwable? = null) = updatePolicy(Policy.DENY, 0).also { Timber.e(e) } - fun grant(time: Long = 0) = updatePolicy(Policy.ALLOW, time) - - private fun updatePolicy(action: Int, time: Long) { - - fun finish(e: Throwable? = null) = die().also { Timber.e(e) } - - policy - .map { it.policy = action; it } - .doOnSuccess { - if (time >= 0) { - it.until = if (time == 0L) { - 0 - } else { - MILLISECONDS.toSeconds(now) + MINUTES.toSeconds(time) - } - database.updatePolicy(it) - } - } - .flatMap { connector } - .subscribeK(onError = ::finish) { - it.response() - finish() - } - } - - private fun requestDialog(policy: Policy) { - SuDialogEvent(policy).publish() - } - - private fun die() = DieEvent().publish() - -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java b/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java deleted file mode 100644 index e6a8615d1..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.topjohnwu.magisk.view; - -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.topjohnwu.magisk.App; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; -import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog; -import com.topjohnwu.net.Networking; -import com.topjohnwu.superuser.Shell; - -import java.io.File; - -import androidx.annotation.StringRes; -import androidx.cardview.widget.CardView; -import butterknife.BindColor; -import butterknife.BindView; -import butterknife.OnClick; -import butterknife.Unbinder; -import dalvik.system.DexClassLoader; - -public class SafetyNet implements ISafetyNetHelper.Callback { - - public static final File EXT_APK = - new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk"); - - /*@BindView(R.id.safetyNet_card) */ CardView safetyNetCard; - @BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon; - @BindView(R.id.safetyNet_status) TextView safetyNetStatusText; - @BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress; - @BindView(R.id.safetyNet_expand) ViewGroup expandLayout; - @BindView(R.id.cts_status_icon) ImageView ctsStatusIcon; - @BindView(R.id.cts_status) TextView ctsStatusText; - @BindView(R.id.basic_status_icon) ImageView basicStatusIcon; - @BindView(R.id.basic_status) TextView basicStatusText; - - @BindColor(R.color.red500) int colorBad; - @BindColor(R.color.green500) int colorOK; - - public Unbinder unbinder; - private final ExpandableViewHolder expandable; - - public SafetyNet(View v) { - unbinder = new SafetyNet_ViewBinding(this, v); - expandable = new ExpandableViewHolder(expandLayout); - Context context = v.getContext(); - safetyNetCard.setVisibility(hasGms(context) && Networking.checkNetworkStatus(context) ? - View.VISIBLE : View.GONE); - } - - public static void dyRun(Activity activity, Object callback) throws Exception { - DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(), - null, ISafetyNetHelper.class.getClassLoader()); - Class clazz = loader.loadClass("com.topjohnwu.snet.Snet"); - ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper", - Class.class, String.class, Activity.class, Object.class) - .invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, callback); - if (helper.getVersion() < Const.SNET_EXT_VER) - throw new Exception(); - helper.attest(); - } - - public void reset() { - safetyNetStatusText.setText(R.string.safetyNet_check_text); - expandable.setExpanded(false); - } - - @Override - public void onResponse(int response) { - safetyNetProgress.setVisibility(View.GONE); - safetyNetRefreshIcon.setVisibility(View.VISIBLE); - if ((response & 0x0F) == 0) { - safetyNetStatusText.setText(R.string.safetyNet_check_success); - - boolean b; - b = (response & ISafetyNetHelper.CTS_PASS) != 0; - ctsStatusText.setText("ctsProfile: " + b); - ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel); - ctsStatusIcon.setColorFilter(b ? colorOK : colorBad); - - b = (response & ISafetyNetHelper.BASIC_PASS) != 0; - basicStatusText.setText("basicIntegrity: " + b); - basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel); - basicStatusIcon.setColorFilter(b ? colorOK : colorBad); - - expandable.expand(); - } else { - @StringRes int resid; - switch (response) { - case ISafetyNetHelper.RESPONSE_ERR: - resid = R.string.safetyNet_res_invalid; - break; - case ISafetyNetHelper.CONNECTION_FAIL: - default: - resid = R.string.safetyNet_api_error; - break; - } - safetyNetStatusText.setText(resid); - } - } - - @OnClick(R.id.safetyNet_refresh) - void safetyNet(View v) { - Runnable task = () -> { - safetyNetProgress.setVisibility(View.VISIBLE); - safetyNetRefreshIcon.setVisibility(View.INVISIBLE); - safetyNetStatusText.setText(R.string.checking_safetyNet_status); - check((Activity) v.getContext()); - expandable.collapse(); - }; - if (!EXT_APK.exists()) { - // Show dialog - new CustomAlertDialog(v.getContext()) - .setTitle(R.string.proprietary_title) - .setMessage(R.string.proprietary_notice) - .setCancelable(true) - .setPositiveButton(R.string.yes, (d, i) -> task.run()) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } else { - task.run(); - } - } - - private void check(Activity activity) { - try { - dyRun(activity, this); - } catch (Exception ignored) { - Shell.sh("rm -rf " + EXT_APK.getParent()).exec(); - EXT_APK.getParentFile().mkdir(); - Networking.get(Const.Url.SNET_URL).getAsFile(EXT_APK, f -> { - try { - dyRun(activity, this); - } catch (Exception e) { - e.printStackTrace(); - onResponse(-1); - } - }); - } - } - - private boolean hasGms(Context context) { - PackageManager pm = context.getPackageManager(); - PackageInfo info; - try { - info = pm.getPackageInfo("com.google.android.gms", 0); - } catch (PackageManager.NameNotFoundException e) { - return false; - } - return info.applicationInfo.enabled; - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java index 2425f0e0c..2dd8a501c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java @@ -4,18 +4,14 @@ import android.content.Context; import android.content.DialogInterface; import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.topjohnwu.magisk.R; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StyleRes; import androidx.appcompat.app.AlertDialog; -import butterknife.BindView; + +import com.topjohnwu.magisk.databinding.AlertDialogBinding; public class CustomAlertDialog extends AlertDialog.Builder { @@ -24,32 +20,16 @@ public class CustomAlertDialog extends AlertDialog.Builder { private DialogInterface.OnClickListener neutralListener; protected AlertDialog dialog; - protected ViewHolder vh; - - public class ViewHolder { - @BindView(R.id.dialog_layout) public LinearLayout dialogLayout; - @BindView(R.id.button_panel) public LinearLayout buttons; - - @BindView(R.id.message) public TextView messageView; - @BindView(R.id.negative) public Button negative; - @BindView(R.id.positive) public Button positive; - @BindView(R.id.neutral) public Button neutral; - - ViewHolder(View v) { - new CustomAlertDialog$ViewHolder_ViewBinding(this, v); - messageView.setVisibility(View.GONE); - negative.setVisibility(View.GONE); - positive.setVisibility(View.GONE); - neutral.setVisibility(View.GONE); - buttons.setVisibility(View.GONE); - } - } + protected AlertDialogBinding binding; { - View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null); - vh = new ViewHolder(v); - super.setView(v); - + binding = AlertDialogBinding.inflate(LayoutInflater.from(getContext())); + super.setView(binding.getRoot()); + binding.message.setVisibility(View.GONE); + binding.negative.setVisibility(View.GONE); + binding.positive.setVisibility(View.GONE); + binding.neutral.setVisibility(View.GONE); + binding.buttonPanel.setVisibility(View.GONE); } public CustomAlertDialog(@NonNull Context context) { @@ -60,10 +40,6 @@ public class CustomAlertDialog extends AlertDialog.Builder { super(context, themeResId); } - public ViewHolder getViewHolder() { - return vh; - } - @Override public CustomAlertDialog setView(int layoutResId) { return this; } @@ -72,8 +48,8 @@ public class CustomAlertDialog extends AlertDialog.Builder { @Override public CustomAlertDialog setMessage(@Nullable CharSequence message) { - vh.messageView.setVisibility(View.VISIBLE); - vh.messageView.setText(message); + binding.message.setVisibility(View.VISIBLE); + binding.message.setText(message); return this; } @@ -84,11 +60,11 @@ public class CustomAlertDialog extends AlertDialog.Builder { @Override public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { - vh.buttons.setVisibility(View.VISIBLE); - vh.positive.setVisibility(View.VISIBLE); - vh.positive.setText(text); + binding.buttonPanel.setVisibility(View.VISIBLE); + binding.positive.setVisibility(View.VISIBLE); + binding.positive.setText(text); positiveListener = listener; - vh.positive.setOnClickListener(v -> { + binding.positive.setOnClickListener(v -> { if (positiveListener != null) { positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); } @@ -104,11 +80,11 @@ public class CustomAlertDialog extends AlertDialog.Builder { @Override public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { - vh.buttons.setVisibility(View.VISIBLE); - vh.negative.setVisibility(View.VISIBLE); - vh.negative.setText(text); + binding.buttonPanel.setVisibility(View.VISIBLE); + binding.negative.setVisibility(View.VISIBLE); + binding.negative.setText(text); negativeListener = listener; - vh.negative.setOnClickListener(v -> { + binding.negative.setOnClickListener(v -> { if (negativeListener != null) { negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); } @@ -124,11 +100,11 @@ public class CustomAlertDialog extends AlertDialog.Builder { @Override public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) { - vh.buttons.setVisibility(View.VISIBLE); - vh.neutral.setVisibility(View.VISIBLE); - vh.neutral.setText(text); + binding.buttonPanel.setVisibility(View.VISIBLE); + binding.neutral.setVisibility(View.VISIBLE); + binding.neutral.setText(text); neutralListener = listener; - vh.neutral.setOnClickListener(v -> { + binding.neutral.setOnClickListener(v -> { if (neutralListener != null) { neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL); } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java index eaf71b846..bd0fd0ad6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java @@ -36,9 +36,9 @@ public class FingerprintAuthDialog extends CustomAlertDialog { TypedArray ta = theme.obtainStyledAttributes(new int[] {R.attr.imageColorTint}); fingerprint.setTint(ta.getColor(0, Color.GRAY)); ta.recycle(); - vh.messageView.setCompoundDrawables(null, null, null, fingerprint); - vh.messageView.setCompoundDrawablePadding(Utils.dpInPx(20)); - vh.messageView.setGravity(Gravity.CENTER); + binding.message.setCompoundDrawables(null, null, null, fingerprint); + binding.message.setCompoundDrawablePadding(Utils.dpInPx(20)); + binding.message.setGravity(Gravity.CENTER); setMessage(R.string.auth_fingerprint); setNegativeButton(R.string.close, (d, w) -> { helper.cancel(); @@ -81,20 +81,20 @@ public class FingerprintAuthDialog extends CustomAlertDialog { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { - vh.messageView.setTextColor(Color.RED); - vh.messageView.setText(errString); + binding.message.setTextColor(Color.RED); + binding.message.setText(errString); } @Override public void onAuthenticationHelp(int helpCode, CharSequence helpString) { - vh.messageView.setTextColor(Color.RED); - vh.messageView.setText(helpString); + binding.message.setTextColor(Color.RED); + binding.message.setText(helpString); } @Override public void onAuthenticationFailed() { - vh.messageView.setTextColor(Color.RED); - vh.messageView.setText(R.string.auth_fail); + binding.message.setTextColor(Color.RED); + binding.message.setText(R.string.auth_fail); } @Override diff --git a/app/src/main/res/layout/alert_dialog.xml b/app/src/main/res/layout/alert_dialog.xml index 87b9fa730..3a9ef0268 100644 --- a/app/src/main/res/layout/alert_dialog.xml +++ b/app/src/main/res/layout/alert_dialog.xml @@ -1,63 +1,65 @@ - - - - + + android:orientation="vertical" + android:paddingTop="5dp"> - + - + - + + + + + + + - - + diff --git a/app/src/main/res/raw/changelog.md b/app/src/main/res/raw/changelog.md index 6d8aa77c5..8236d14b7 100644 --- a/app/src/main/res/raw/changelog.md +++ b/app/src/main/res/raw/changelog.md @@ -1,9 +1,3 @@ -# 7.1.1 -- Fix a bug that causes some modules using new format not showing up - -# v7.1.0 -- Support the new module format -- Support per-application component granularity MagiskHide targets (only on v19+) -- Ask for fingerprint before deleting rules if enabled -- Fix the bug that causes repackaging to lose settings -- Several UI fixes +# v7.1.2 +- Support patching Samsung AP firmware +- Much better module downloading mechanism diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 3d6e00835..424155bb3 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -160,7 +160,7 @@ Automatická odezva Časový limit požadavku Oznámení Superuser - %1$s sekund + %1$d sekund Opětovné ověření po aktualizaci Opětovné ověření oprávnění Superuser po aktualizaci aplikace Povolit ověřování otisky prstů diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml new file mode 100644 index 000000000..4a68ed532 --- /dev/null +++ b/app/src/main/res/values-mk/strings.xml @@ -0,0 +1,225 @@ + + + + Модули + Преземања + Супер-корисник + Записник + Поставки + Инсталирај + Неподдржана верзија на Magisk + Оваа верзија на Magisk Manager не ја поддржува верзијата на Magisk пониска од v18.0.\n\nМожно е да рачно да го надградите Magisk или да ја вратите апликацијата на постара верзија. + + + Magisk не е инсталиран. + Проверка за ажурирања… + Невалиден канал за ажурирања + Притисни за проверка на SafetyNet статус + Проверка на SafetyNet статус… + SafetyNet проверката е успешна + Грешка со SafetyNet API + Одговорот е невалиден. + Magisk е ажуриран + Magisk Manager е ажуриран + Напредни поставки + Задржи ја присилната енкрипција + Задржи AVB 2.0/dm-verity + Инсталирано: %1$s + Најново: %1$s + Деинсталирај + Деинсталирај го Magisk + Сите модули ќе бидат оневозможени/oтстранети. Рут привилегиите ќе бидат отстранети, а вашите податоци може да се енкриптираат ако моментално не се. + Ажурирај + (Овозможен е само основен режим) + + + (Нема информации) + Не се пронајдени модули. + Модулот ќе се ажурира при следното рестартирање. + Модулот ќе биде отстранет при следното рестартирање. + Модулот нема да биде отстранет при следното рестартирање. + Модулот ќе биде оневозможен при следното рестартирање. + Модулот ќе биде овозможен при следното рестартирање. + Направено од %1$s + Рестартирај во Recovery режим + Рестартирај во Bootloader режим + Рестартирај во Download режим + + + Достапно е ажурирање + Инсталирано + Не е инсталирано + Ажурирано на: %1$s + Начин на подредување + Подреди по име + Подреди според последното ажурирање + + + Зачувај записник + Вчитај повторно + Исчисти го записникот сега + Записникот е успешно исчистен. + Записникот е празен. + + + Листа на промени + davidtrpcevski + Преведувачи + + + Magisk Ажурирања + Известувања за прогресот + Преземањето е завршено + Грешка при преземање на фајлот + Достапно е ажурирање на Magisk! + Достапно е ажурирање на Magisk Manager! + + + Притисни за преземање и инсталирање. + Преземи само Zip датотека + Директна инсталација (Препорачано) + Инсталирај во неактивен слот (по ОТА) + Вашиот уред ќе биде ПРИНУДЕН да се подигне на тековниот неактивен слот по рестартирањето!\nОваа опција користете ја само откако OTA ажурирање е направено.\nПродолжи? + Избери метод + Дополнителни подесувања + Избери и обнови ја датотеката + Избери само image датотека (*.img) или ODIN tar датотека (*.tar) + Рестартирање за 5 секунди… + + + Затвори + Инсталирај %1$s + Дали сакате да го инсталирате %1$s сега? + Преземи + Рестартирај + Рестартирајте за да ги примените поставките. + Белешки за изданието + Кешот од репозиториумот е исчистен + Zip датотеката е сместена во:\n[Внатрешна меморија]%1$s + + DTBO е обновено! + Magisk Manager ја обнови dtbo.img датотеката. Ве молиме, рестартирајте. + Применувам + Сокриј го Magisk Manager… + Сокривањето на Magisk Manager е неуспешно. + Не е пронајдена апликација за отворање на врската. + Внимание + Целосно деинсталирање + Врати image датотеки + Враќање… + Враќањето заврши! + Не постои оригинална резервна копија! + Превземи патентиран код + Magisk Manager е FOSS апликација и затоа не содржи код од SafetyNet API кој е во сопственост на Google.\n\nДали ќе дозволите Magisk Manager да преземе проширување (содржи GoogleApiClient) за SafetyNet проверка? + Поставувањето е неуспешно. + Потребни е дополнително поставување + На Вашиот уред му е потребно дополнително поставување за Magisk да работи нормално. Ќе се преземе ZIP фајлот за поставување на Magisk, дали сакате да продолжите? + Надградба на работната околина… + Преземање %1$s + Оваа функција нема да работи без дозвола за запис на надворешната меморија. + Преземај модули еден по друг. + + + Општо + Темна тема + Овозможи темна тема. + Исчисти го кешот од репозиториумот + Исчисти ги кешираните информации за онлајн репозиториумот. Ова ја принудува апликацијата да се освежи онлајн. + Сокриј го Magisk Manager + Препакувај го Magisk Manager со случајно име на пакет. + Врати го Magisk Manager + Врати го Magisk Manager со оригиналното име на пакет + Јазик + (Стандарден системски) + Поставки за ажурирање + Провери за ажурирања + Периодично проверувај за ажурирања во позадина. + Канал за ажурирања + Стабилен + Бета + Прилагодено + Внеси прилагоден URL линк + Само Magisk Core основен режим + Овозможи ги само основните функционалности. MagiskSU и MagiskHide ќе бидет овозможени, но нема да се вчитаат модули. + Сокриј го Magisk од различни форми на откривање. + Несистемски хостови + Поддршка за несистемски хостови за Adblock апликации. + Додаден е модул за несистемски хостови + + Апликации и АДБ + Само апликации + Само АДБ + Оневозможено + 10 секунди + 15 секунди + 20 секунди + 30 секунди + 45 секунди + 60 секунди + Пристап за супер-корисник + Автоматски одговор + Временско ограничување на барање + Супер-корисник известување + %1$d секунди + Повторна автентикација по надградба + Повторна автентикација за супер-корисник дозвола по надградбата на апликацијата + Овозможи автентикација на отпечатоци + Користете скенер за отпечатоци за да дозволите супер-корисник барања + Автентикација на отпечатоци + + Режим на повеќе корисници + Само сопственикот на уредот + Управувано од сопственикот на уредот + Независно од корисникот + Само сопственикот има рут пристап. + Само сопственикот може да управува со рут пристапот и да ги прима барања за рут пристап. + Секој корисник има сопствени рут правила. + + Поставете го режимот на именски простор + Глобален именски простор + Наследи именски простор + Изолиран именски простор + Сите рут сесии го користат глобалниот именски простор. + Рут сесиите ќе го наследат именскиот простор на нивниот барател. + Секоја рут сесија ќе има свој изолиран именски простор. + Не е поддржано на Android 8.0+. + Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција. + + + Супер-корисник барање + Одбиј%1$s + Одбиј + Прашај + Одобри + Дава целосен пристап на вашиот уред.\nОдбијте ако не сте сигурни! + Засекогаш + Еднаш + 10 минути + 20 минути + 30 минути + 60 минути + На %1$s се доделени правата на супер-корисник + На %1$s се одбиени правата на супер-корисник + Не се пронајдени апликации + Правата за супер-корисник од %1$s се одобрени + Правата за супер-корисник од %1$s се одбиени + Известувањата од %1$s се овозможени + Известувањата од %1$s се оневозможени + Записникот на настани е овозможен за %1$s + Записникот на настани е оневозможен %1$s + Правата за %1$s се анулирани + Анулирај? + Дали потврдувате анулирање на поставките за пристап на %1$s? + Тост + Ниеден + Неуспешна автентикација + + + PID: %1$d + Целен UID: %1$d + Команда: %1$s + + + Прикажи ги системските апликации + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1a38c3aac..2313e72f9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -63,7 +63,7 @@ Список изменений - Displax [4PDA], igor-dyatlov, zertyuiop + Переводчики @@ -74,6 +74,18 @@ Доступно обновление Magisk! Доступно обновление Magisk Manager! + + Нажмите, чтобы загрузить и установить. + Загрузка установочного ZIP + Прямая установка (Рекомендуется) + Установка в неактивный слот (После OTA) + Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить? + Выбор способа + Дополнительная установка + Выбрать и пропатчить файл + Выберите образ ядра (*.img) или архив ODIN (*.tar) + Перезагрузка через 5 секунд… + Закрыть Установка %1$s @@ -84,19 +96,14 @@ О версии Кэш репозитория очищен Расположение архива:\n[Внутреннее Хранилище]%1$s - Нажмите, чтобы загрузить и установить. + DTBO пропатчен! Magisk Manager пропатчил dtbo.img. Перезагрузите устройство. Прошивка Маскировка Magisk Manager… Не удалось замаскировать Magisk Manager - Не найдено приложений для открытия ссылки. - Загрузка установочного ZIP - Прямая установка (Рекомендуется) - Установка в неактивный слот (После OTA) + Не найдено приложений для открытия ссылки. Предупреждение - Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить? - Выбор способа Полное удаление Восстановить разделы Восстановление… @@ -107,7 +114,6 @@ Ошибка установки. Требуется дополнительная установка Вашему устройству требуется дополнительная установка Magisk для корректной работы. Будет загружен установочный ZIP Magisk, продолжить? - Дополнительная установка Настройка рабочей среды… Загрузка %1$s Требуется разрешение на запись во внешнее хранилище. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index fa90adc55..7fad0e1a9 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -63,7 +63,7 @@ Uygulama değişiklikleri - Mevlüt TOPÇU - Muhammet Emin TURGUT + Mevlüt TOPÇU - Muhammet Emin TURGUT - XORCAN Çevirmenler @@ -74,6 +74,18 @@ Yeni Magisk Güncellemesi Mevcut! Yeni Magisk Manager Güncellemesi Mevcut! + + İndirmek ve yüklemek için tıklayın. + Sadece Zip\'i indir + Doğrudan kurulum (Önerilen) + İnaktif slota yükle (OTA\'dan sonra) + Cihazınız, yeniden başlatmanın ardından inaktif slota ön yüklemek için ZORUNLU olacaktır!\nBu seçeneği yalnızca OTA yapıldıktan sonra kullanın.\nDevam? + Yöntem seçin + Ek kurulum + Dosya seçin ve yamalayın + Bir raw yansısı (*.img) ya da ODIN tarfile dosyası (*.tar) seçin + 5 saniye içinde yeniden başlatılacak... + Kapat %1$s yükle @@ -84,19 +96,14 @@ Sürüm notları Repo önbelleği temizlendi Zip şuraya depolandı:\n[Dahili Hafıza]%1$s - İndirmek ve yüklemek için dokunun + DTBO yamalandı! Magisk Manager dtbo.img\'yi yamaladı, lütfen yeniden başlatın Yükleniyor Magisk Manager Gizleniyor… Magisk Manager\'ı Gizleme başarısız oldu… Bağlantıyı açabilecek uygulama bulunamadı… - Yalnızca Zip Dosyasını İndir - Doğrudan Yükle (Önerilen) - Pasif yuvaya yükle (OTA\'dan sonra) Uyarı - Cihazınız yeniden başlatıldıktan sonra mevcut pasif yuvaya ZORLA önyüklenecek!\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.\nDevam mı? - Yöntem Seçin Tamamen Kaldır Önyükleme İmajını Geri Yükle Geri Yükleniyor… @@ -106,8 +113,7 @@ Magisk Yöneticisi, FOSS olduğundan Google\'ın tescilli olduğu SafetyNet API kodunu içermez.\n\nMagisk Manager\'ın SafetyNet kontrolü için bir uzantıyı (GoogleApiClient içeriyor) indirmesine izin veriyor musunuz? Kurulum başarısız Ek Kurulum Gerekli -    Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz? - Ek Kurulum + Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz? Ortam kurulumu çalışıyor… %1$s indiriliyor Bu özellik harici depolamaya yazma izni olmadan çalışmaz. @@ -127,7 +133,7 @@ (Sistem Varsayılanı) Güncelleme Ayarları Güncellemeleri denetle -    Düzenli aralıklarla arka planda güncellemeleri denetle + Düzenli aralıklarla arka planda güncellemeleri denetle Güncelleme Kanalı Kararlı Beta @@ -188,10 +194,10 @@ Cihazınıza tam erişim izni verir.\nEmin değilseniz, reddedin! Daima Bir kere -    10 dakika -    20 dakika -    30 dakika -    60 dakika + 10 dakika + 20 dakika + 30 dakika + 60 dakika %1$s için yetkili kullanıcı hakları verildi %1$s için yetkili kullanıcı hakları reddedildi Hiçbir uygulama bulunamadı diff --git a/build.gradle b/build.gradle index dc6d45323..2bd42d85b 100644 --- a/build.gradle +++ b/build.gradle @@ -12,11 +12,12 @@ buildscript { google() jcenter() maven { url 'http://storage.googleapis.com/r8-releases/raw' } + maven { url 'https://kotlin.bintray.com/kotlinx' } } dependencies { - classpath 'com.android.tools:r8:1.4.79' + classpath 'com.android.tools:r8:1.4.93' classpath 'com.android.tools.build:gradle:3.5.0-alpha13' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.30" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31" // NOTE: Do not place your application dependencies here; they belong diff --git a/docs/README.md b/docs/README.md index 658662da6..76953afcf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,11 @@ # Magisk Documentations -(Updated on 2019.3.28) +(Updated on 2019.5.1) - [Installation](install.md) - [Prerequisite](install.md#prerequisite) - [Custom Recovery](install.md#custom-recovery) - [Boot Image Patching](install.md#boot-image-patching) + - [Samsung (System-as-root)](install.md#samsung-system-as-root) - [Huawei](install.md#huawei) - [Tutorials](tutorials.md) - [OTA Installation](tutorials.md#ota-installation) diff --git a/docs/install.md b/docs/install.md index 9850e6a68..c680d5538 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,6 +1,8 @@ # Installation -If you already have Magisk installed, it is **strongly recommended to upgrade directly via Magisk Manager**. -The following tutorial is for first time users. For Huawei users, please check the specific section for more information. +If you already have Magisk installed, it is **strongly recommended to upgrade directly via Magisk Manager**. The following tutorial is for first time users. + +- If you are using a Huawei device running **EMUI 8 and higher**, please check its own section. +- If you are using a Samsung device that is **launched with Android 9.0** (new devices in 2019), please check its own section. ## Prerequisite - If you plan to install custom kernels, flash the zip **AFTER** installing Magisk @@ -17,43 +19,102 @@ If your device have custom recovery support, the easiest way is to install it th ## Boot Image Patching This is the "cool" way to install Magisk on your device. Either your device does not have proper custom recoveries, your device is using the A/B partition scheme and you don't want to mix recovery and boot images together, or you have other concerns (e.g. [OTA Installation](tutorials.md#ota-installation)), you should use this method instead. -In order to use this method, you are required to obtain a copy of the stock boot image, which can be found by extracting OEM provided factory images, or extracted from OTA update zips. If you are unable to obtain one yourself, someone on the Internet might share it somewhere. The following instructions will guide you through the process after you have the copy of boot image. +In order to use this method, you are required to obtain a copy of the stock boot image, which can be found by extracting OEM provided factory images or extracting from OTA update zips. If you are unable to obtain one yourself, someone on the Internet might share it somewhere. The following instructions will guide you through the process after you have the copy of boot image. - Copy the boot image to your device - Download and install the latest Magisk Manager -- If you're planning to flash the patched boot image through ODIN (Samsung only), go to **Settings > Update Settings > Patched Boot Output Format**, and select *.img.tar*, or else leave it as the default (*.img*) -- Press **Install > Install > Patch Boot Image File**, and select your stock boot image file -- Magisk Manager will install Magisk to your boot image, and store it in -`[Internal Storage]/Download/patched_boot.img[.tar]` -- Copy the patched boot image from your device to your PC. If you can't find it via MTP, you can pull the file with ADB: -`adb pull /sdcard/Download/patched_boot.img[.tar]` -- Flash the patched boot image to your device and reboot. Here is the command if using fastboot on most devices: -`fastboot flash boot /path/to/patched_boot.img` +- Press **Install → Install → Select and Patch a File**, and select your stock boot image file +- Magisk Manager will install Magisk to your boot image, and store it in `[Internal Storage]/Download/magisk_patched.img` +- Copy the patched boot image from your device to your PC. If you can't find it via MTP, you can pull the file with ADB:
+`adb pull /sdcard/Download/magisk_patched.img` +- Flash the patched boot image to your device and reboot. Here is the command if using fastboot on most devices:
+`fastboot flash boot /path/to/magisk_patched.img` + +## Magisk in Recovery +Due to the fact that some devices no longer uses ramdisk in boot images, Magisk has no choice but to be installed in the recovery partition. For these devices, you will have to **boot to recovery every time** if you want Magisk. Since both Magisk and recovery lives in the same partition, what you actually end up getting when you choose to boot to recovery will be determined by **how long you press volume up**. + +Each OEM has its own key combo to boot into recovery. For example on Samsung it is **(Power + Bixby + Volume Up)**, and for Huawei it is **(Power + Volume Up)**. As soon as you press the combo and the device vibrates with a splash screen, the bootloader has already chosen which mode it is booting, either it be `boot`, `recovery`, or some OEM specific modes like `download`, `fastboot`, or `erecovery`. After the splash screen, release all buttons to boot into Magisk, since by default `recovery` mode will boot to the system with Magisk enabled. If you decide to boot to actual recovery, continue to press volume up until you see the recovery screen. + +**In summary, after installing Magisk:** +- **(Powering up normally) → (System with NO Magisk)** +- **(OEM Recovery Key Combo) → (Splash screen) → (Release all buttons) → (System with Magisk)** +- **(OEM Recovery Key Combo) → (Splash screen) → (Keep pressing volume up) → (Actual recovery)** + +## Samsung (System-as-root) +**If your device is NOT launched with Android 9.0 or higher (released after 2019), follow the normal tutorial** + +### Before Installing Magisk +- Installing Magisk **WILL** trip KNOX +- Installing Magisk for the first time **REQUIRES** a full data wipe, backup before continue +- You have to have your bootloader unlocked before following the instructions +- Magisk will be installed to the **recovery** partition of your device. **Please read the Magisk in Recovery section before following the instructions below!** +- After installing Magisk, you can directly upgrade Magisk within Magisk Manager without an issue. **Flashing in custom recovery is not supported for now.** + +### Unlocking Bootloader +Normally I won't provide instructions for this, but since things had changed drastically from previous Samsung devices, and there are some details that many might not know, I figure this would be helpful. +- Allow bootloader unlocking in Developer options → OEM unlocking +- Power off your device. Press *Bixby + Volume Down* and plug in your device to a PC to boot into download mode +- Long press volume up to unlock the bootloader. **This will wipe your data and automatically reboot.** + +Just when you think the bootloader is unlocked, surprise surprise, it is *actually* not! Samsung introduced `VaultKeeper` in the system, meaning the bootloader will reject any unofficial partitions before `VaultKeeper` explicitly allows it. + +- Go through the initial setup. Skip through all the steps since data will be wiped again later when we are installing Magisk. **Connect the device to internet in the setup!** +- Enable developer options, and **confirm that the OEM unlocking option exists and grayed out!** The `VaultKeeper` service will unleash the bootloader after it confirms that the user has the OEM unlocking option enabled. This step is to simply make sure the service gets the correct info, and also double check that our device is in a correct state +- Your bootloader now accepts unofficial images in download mode. + +### Instructions +1. Download the firmware for your device. +2. Unzip the firmware and copy the **AP** tar file to your device. It is normally named as `AP_[device_model_sw_ver].tar.md5` +3. Install the latest Magisk Manager +4. In Magisk Manager: **Install → Install → Select and Patch a File** and select the AP tar file. +5. Magisk Manager will patch the whole firmware file and store the output to +`[Internal Storage]/Download/magisk_patched.tar` +6. Copy the tar file to your PC, and boot your device to download mode. +7. Flash `magisk_patched.tar` as AP in ODIN
**Important: Uncheck "Auto Reboot" in Options!!!!** +8. Magisk is now successfully flashed to your device! But there are still several steps before you can properly use the device. +9. We now want to boot into the stock recovery to factory reset our device.
+**Full data wipe is mandatory! Do not skip this step.**
+Press *Power + Volume Down* to exit download mode. As soon as the screen turns off, immediately press *Power + Bixby + Volume Up* to boot to recovery partition. Just as mentioned in the previous section, since we want to boot into stock recovery, **continue pressing the volume up button until you see the stock recovery screen**. +10. In the stock recovery menu, use volume buttons to navigate through menus, and the power button to select the option. Select *Wipe data/factory reset* to wipe the data of the device. +11. This time, we can finally boot to the system with Magisk. Select *Reboot system now*, and immediately press *Power + Bixby + Volume Up*. After seeing the bootloader warning screen, release all buttons so it can boot to the system. +12. The device will automatically reboot for the first time it boots. This is completely normal and done by design. +13. After the device is booted up, do the usual initial setup. **The following steps will need internet connection.** +14. You shall see Magisk Manager in your app drawer; if not, manually install the APK you downloaded in step 3 and continue to the next step. The app would be a stub and it shall automatically upgrade to the full Magisk Manager when you open it. +15. Magisk Manager will ask to do additional setups. Let it do its job and the app will automatically reboot your device. +16. Voila! Enjoy Magisk :) + +### Additional Info +- Magisk actually patches 3 partitions on your device: + - `vbmeta`: replace with empty vbmeta image to disable partition verification + - `boot`: remove the signature of the image to prevent soft bricks + - `recovery`: this is where Magisk is actually installed +- **Never, ever** try to restore either of the 3 images mentioned back to stock! You can easily brick your device by doing so, and the only way out is to do full ODIN restore following with factory reset. Just don't do it. +- If you want to upgrade your device, **never** flash the stock **AP** tar file with reasons mentioned above. **Always** pre-patch the firmware before flashing in ODIN. +- If you don't need to patch the full firmware, you can manually create a tar file with **at least** `vbmeta.img`, `boot.img`, and `recovery.img` to let Magisk Manager patch your images in the proper way. ## Huawei -Huawei devices using Kirin processors have a different partitioning method from most common devices. Magisk is usually installed to the `boot` partition of the device, however Huawei devices does not have this partition. Depending on what EMUI version your device is running the instructions are slightly different. Even if you have switched to a custom ROM, you shall still know which version of EMUI you are running before switching. +Huawei devices using Kirin processors have a different partitioning method from most common devices. Magisk is usually installed to the `boot` partition of the device, however Huawei devices does not have this partition. Depending on what EMUI version your device is running, the instructions will be slightly different. ### Obtain Stock Images -Huawei does not release official factory images, however most firmware zips can be downloaded from the [Huawei Firmware Database](http://pro-teammt.ru/firmware-database/). To extract the images from `UPDATE.APP` in the zip, you have to use [Huawei Update Extractor](https://forum.xda-developers.com/showthread.php?t=2433454) (Windows only!) +Huawei does not release official factory images, however most firmware zips can be downloaded from the [Huawei Firmware Database](http://pro-teammt.ru/firmware-database/). To extract images from `UPDATE.APP` in the zip, you have to use [Huawei Update Extractor](https://forum.xda-developers.com/showthread.php?t=2433454) (Windows only!) ### EMUI 8 -For EMUI 8 devices, your device have a partition named `ramdisk`, which will be where Magisk is going to be installed. +For EMUI 8 devices, your device have a partition named `ramdisk`, which is where Magisk is going to be installed. -- If you plan to use custom recoveries, simply follow the instructions for custom recovery above. -Note that to install TWRP, you will first download the TWRP recovery image, and use -`fastboot flash recovery_ramdisk /path/to/twrp.img` to install the custom recovery. -- If you plan not to use custom recoveries, you will have to extract `RAMDISK.img` from your firmware. Follow the instructions for boot image patching above, but use the `RAMDISK.img` file instead of a boot image. To install the patched image back to your device, here is the fastboot command: -`fastboot flash ramdisk /path/to/patched_boot.img`. +- If you plan to use custom recoveries, simply follow the instructions for custom recovery and you're all set. +- If you plan not to use custom recoveries, you will have to extract `RAMDISK.img` from your firmware. Follow the instructions for boot image patching above, but use the `RAMDISK.img` file instead of a boot image. +- To flash the patched image to your device, here is the fastboot command:
+`fastboot flash ramdisk /path/to/magisk_patched.img`
Be aware you are flashing to `ramdisk`, not `boot`! -### EMUI 9 -For EMUI 9 devices, the `ramdisk` partition no longer exists. As a workaround, Magisk will be installed to the `recovery_ramdisk` partition. **This means that you HAVE TO boot to recovery every time you reboot.** To boot to recovery, press **Power + Volume Up** when booting your device. +### EMUI 9 or Higher +For EMUI 9+ devices, the `ramdisk` partition no longer exists. As a workaround, Magisk will be installed to the `recovery_ramdisk` partition. **Please read the Magisk in Recovery section before following the instructions below!** -- If you plan to use custom recoveries, simply follow the instructions for custom recovery above. -Note that to install TWRP, you will first download the TWRP recovery image, and use -`fastboot flash recovery_ramdisk /path/to/twrp.img` to install the custom recovery. -**Magisk will overwrite the custom recovery.** -- If you plan not to use custom recoveries, you will have to extract `RECOVERY_RAMDIS.img` from your firmware. Follow the instructions for boot image patching above, but use the `RECOVERY_RAMDIS.img` file instead of a boot image. To install the patched image back to your device, here is the fastboot command: -`fastboot flash recovery_ramdisk /path/to/patched_boot.img`. -Be aware you are flashing to `recovery_ramdisk`, not `boot` nor `ramdisk`! -- You can still install custom recoveries to the `erecovery_ramdisk` partition. Boot to erecovery mode to boot into custom recovery in this case +*Note: As I tested on my Honor View 10, Huawei's kernel does not seem to be able to capture key button press events in early boot, so long pressing Volume Up does **NOT** boot to recovery on my device. Your experience may vary.* + +- If you plan to use custom recoveries, simply follow the instructions for custom recovery and you're all set.
+**Warning: Magisk will overwrite the custom recovery.** +- If you plan not to use custom recoveries, you will have to extract `RECOVERY_RAMDIS.img` from your firmware. Follow the instructions for boot image patching above, but use the `RECOVERY_RAMDIS.img` file instead of a boot image. +- To flash the patched image to your device, here is the fastboot command:
+`fastboot flash recovery_ramdisk /path/to/magisk_patched.img`
+Be aware you are flashing to `recovery_ramdisk`, not `boot`! diff --git a/native/jni/core/init.cpp b/native/jni/core/init.cpp index ed6cc5bcc..3f6adbcc6 100644 --- a/native/jni/core/init.cpp +++ b/native/jni/core/init.cpp @@ -609,10 +609,8 @@ void MagiskInit::setup_rootfs() { sprintf(path, "/sbin/%s", applet_names[i]); xsymlink("/sbin/magisk", path); } - for (int i = 0; init_applet[i]; ++i) { - sprintf(path, "/sbin/%s", init_applet[i]); - xsymlink("/sbin/magiskinit", path); - } + xsymlink("/sbin/magiskinit", "/sbin/magiskpolicy"); + xsymlink("/sbin/magiskinit", "/sbin/supolicy"); close(rootdir); close(sbin); diff --git a/shared/src/main/res/values-mk/strings.xml b/shared/src/main/res/values-mk/strings.xml new file mode 100644 index 000000000..26b898170 --- /dev/null +++ b/shared/src/main/res/values-mk/strings.xml @@ -0,0 +1,13 @@ + + + Magisk Manager + Manager + Magisk + Magisk Hide + + + + Не, благодарам + Да + ОК + diff --git a/shared/src/main/res/values-tr/strings.xml b/shared/src/main/res/values-tr/strings.xml index 0b90ae362..b12c91cfb 100644 --- a/shared/src/main/res/values-tr/strings.xml +++ b/shared/src/main/res/values-tr/strings.xml @@ -1,5 +1,5 @@ - Hayır teşekkürler + Hayır, teşekkürler Evet Tamam diff --git a/stub/src/main/res/values-mk/strings.xml b/stub/src/main/res/values-mk/strings.xml new file mode 100644 index 000000000..32664f06e --- /dev/null +++ b/stub/src/main/res/values-mk/strings.xml @@ -0,0 +1,4 @@ + + Надградете до целосната верзија на Magisk Manager за да го завршите поставувањето. Преземете и инсталирајте? + Ве молиме поврзете се на интернет бидејќи е потребна надградба на целосната верзија на Magisk Manager. +