Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
14ff22fb
Commit
14ff22fb
authored
Apr 24, 2019
by
Viktor De Pasquale
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated flash screen with new arch
parent
07eb7dda
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
450 additions
and
353 deletions
+450
-353
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+1
-1
Const.java
app/src/main/java/com/topjohnwu/magisk/Const.java
+3
-0
ViewModelsModule.kt
...src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
+3
-0
ViewEvents.kt
...main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
+9
-1
FlashResultListener.kt
...a/com/topjohnwu/magisk/model/flash/FlashResultListener.kt
+7
-0
Flashing.kt
...rc/main/java/com/topjohnwu/magisk/model/flash/Flashing.kt
+4
-4
Patching.kt
...rc/main/java/com/topjohnwu/magisk/model/flash/Patching.kt
+9
-9
MagiskActivity.kt
.../main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt
+13
-10
MagiskFragment.kt
.../main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt
+2
-0
MagiskViewModel.kt
...main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt
+4
-0
FlashActivity.java
...ain/java/com/topjohnwu/magisk/ui/flash/FlashActivity.java
+0
-274
FlashActivity.kt
.../main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt
+24
-0
FlashViewModel.kt
...main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
+104
-0
DataBindingAdapters.kt
...in/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt
+30
-0
XList.kt
app/src/main/java/com/topjohnwu/magisk/utils/XList.kt
+43
-0
XString.kt
app/src/main/java/com/topjohnwu/magisk/utils/XString.kt
+11
-0
XTime.kt
app/src/main/java/com/topjohnwu/magisk/utils/XTime.kt
+18
-0
ic_back.xml
app/src/main/res/drawable/ic_back.xml
+10
-0
ic_restart.xml
app/src/main/res/drawable/ic_restart.xml
+10
-0
activity_flash.xml
app/src/main/res/layout/activity_flash.xml
+142
-53
strings.xml
app/src/main/res/values/strings.xml
+3
-1
No files found.
app/src/main/AndroidManifest.xml
View file @
14ff22fb
...
...
@@ -35,7 +35,7 @@
android:name=
"a.f"
android:configChanges=
"keyboardHidden|orientation|screenSize"
android:screenOrientation=
"nosensor"
android:theme=
"@style/
AppTheme.NoDrawer
"
/>
android:theme=
"@style/
MagiskTheme.Flashing
"
/>
<!-- Superuser -->
...
...
app/src/main/java/com/topjohnwu/magisk/Const.java
View file @
14ff22fb
...
...
@@ -35,6 +35,9 @@ public class Const {
public
static
final
int
USER_ID
=
Process
.
myUid
()
/
100000
;
// Generic
public
static
final
String
MAGISK_INSTALL_LOG_FILENAME
=
"magisk_install_log_%s.log"
;
public
static
final
class
MAGISK_VER
{
public
static
final
int
MIN_SUPPORT
=
18000
;
}
...
...
app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
View file @
14ff22fb
package
com.topjohnwu.magisk.di
import
android.net.Uri
import
com.topjohnwu.magisk.ui.MainViewModel
import
com.topjohnwu.magisk.ui.flash.FlashViewModel
import
com.topjohnwu.magisk.ui.hide.HideViewModel
import
com.topjohnwu.magisk.ui.home.HomeViewModel
import
com.topjohnwu.magisk.ui.log.LogViewModel
...
...
@@ -17,4 +19,5 @@ val viewModelModules = module {
viewModel
{
HideViewModel
(
get
(),
get
())
}
viewModel
{
ModuleViewModel
(
get
(),
get
())
}
viewModel
{
LogViewModel
(
get
(),
get
())
}
viewModel
{
(
action
:
String
,
uri
:
Uri
?)
->
FlashViewModel
(
action
,
uri
,
get
())
}
}
app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
View file @
14ff22fb
...
...
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.model.events
import
android.app.Activity
import
com.skoumal.teanity.viewevents.ViewEvent
import
com.topjohnwu.magisk.model.entity.Repo
import
io.reactivex.subjects.PublishSubject
data class
OpenLinkEvent
(
val
url
:
String
)
:
ViewEvent
()
...
...
@@ -25,4 +26,11 @@ class OpenFilePickerEvent : ViewEvent()
class
OpenChangelogEvent
(
val
item
:
Repo
)
:
ViewEvent
()
class
InstallModuleEvent
(
val
item
:
Repo
)
:
ViewEvent
()
class
PageChangedEvent
:
ViewEvent
()
\ No newline at end of file
class
PageChangedEvent
:
ViewEvent
()
class
PermissionEvent
(
val
permissions
:
List
<
String
>,
val
callback
:
PublishSubject
<
Boolean
>
)
:
ViewEvent
()
class
BackPressEvent
:
ViewEvent
()
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/model/flash/FlashResultListener.kt
0 → 100644
View file @
14ff22fb
package
com.topjohnwu.magisk.model.flash
interface
FlashResultListener
{
fun
onResult
(
isSuccess
:
Boolean
)
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/model/flash/Flashing.kt
View file @
14ff22fb
...
...
@@ -13,7 +13,7 @@ sealed class Flashing(
uri
:
Uri
,
private
val
console
:
MutableList
<
String
>,
log
:
MutableList
<
String
>,
private
val
resultListener
:
(
Result
<
Boolean
>)
->
Unit
private
val
resultListener
:
FlashResultListener
)
:
FlashZip
(
uri
,
console
,
log
)
{
override
fun
onResult
(
success
:
Boolean
)
{
...
...
@@ -21,14 +21,14 @@ sealed class Flashing(
console
.
add
(
"! Installation failed"
)
}
resultListener
(
Result
.
success
(
success
)
)
resultListener
.
onResult
(
success
)
}
class
Install
(
uri
:
Uri
,
console
:
MutableList
<
String
>,
log
:
MutableList
<
String
>,
resultListener
:
(
Result
<
Boolean
>)
->
Unit
=
{}
resultListener
:
FlashResultListener
)
:
Flashing
(
uri
,
console
,
log
,
resultListener
)
{
override
fun
onResult
(
success
:
Boolean
)
{
...
...
@@ -44,7 +44,7 @@ sealed class Flashing(
uri
:
Uri
,
console
:
MutableList
<
String
>,
log
:
MutableList
<
String
>,
resultListener
:
(
Result
<
Boolean
>)
->
Unit
=
{}
resultListener
:
FlashResultListener
)
:
Flashing
(
uri
,
console
,
log
,
resultListener
)
{
private
val
context
:
Context
by
inject
()
...
...
app/src/main/java/com/topjohnwu/magisk/model/flash/Patching.kt
View file @
14ff22fb
...
...
@@ -6,8 +6,8 @@ import com.topjohnwu.superuser.Shell
sealed
class
Patching
(
private
val
console
:
MutableList
<
String
>,
logs
:
List
<
String
>,
private
val
resultListener
:
(
Result
<
Boolean
>)
->
Unit
logs
:
Mutable
List
<
String
>,
private
val
resultListener
:
FlashResultListener
)
:
MagiskInstaller
(
console
,
logs
)
{
override
fun
onResult
(
success
:
Boolean
)
{
...
...
@@ -17,14 +17,14 @@ sealed class Patching(
Shell
.
sh
(
"rm -rf $installDir"
).
submit
()
console
.
add
(
"! Installation failed"
)
}
resultListener
(
Result
.
success
(
success
)
)
resultListener
.
onResult
(
success
)
}
class
File
(
private
val
uri
:
Uri
,
console
:
MutableList
<
String
>,
logs
:
List
<
String
>,
resultListener
:
(
Result
<
Boolean
>)
->
Unit
=
{}
logs
:
Mutable
List
<
String
>,
resultListener
:
FlashResultListener
)
:
Patching
(
console
,
logs
,
resultListener
)
{
override
fun
operations
()
=
extractZip
()
&&
handleFile
(
uri
)
&&
patchBoot
()
&&
storeBoot
()
...
...
@@ -32,8 +32,8 @@ sealed class Patching(
class
SecondSlot
(
console
:
MutableList
<
String
>,
logs
:
List
<
String
>,
resultListener
:
(
Result
<
Boolean
>)
->
Unit
=
{}
logs
:
Mutable
List
<
String
>,
resultListener
:
FlashResultListener
)
:
Patching
(
console
,
logs
,
resultListener
)
{
override
fun
operations
()
=
findSecondaryImage
()
&&
extractZip
()
&&
patchBoot
()
&&
flashBoot
()
&&
postOTA
()
...
...
@@ -41,8 +41,8 @@ sealed class Patching(
class
Direct
(
console
:
MutableList
<
String
>,
logs
:
List
<
String
>,
resultListener
:
(
Result
<
Boolean
>)
->
Unit
=
{}
logs
:
Mutable
List
<
String
>,
resultListener
:
FlashResultListener
)
:
Patching
(
console
,
logs
,
resultListener
)
{
override
fun
operations
()
=
findImage
()
&&
extractZip
()
&&
patchBoot
()
&&
flashBoot
()
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt
View file @
14ff22fb
...
...
@@ -16,6 +16,7 @@ import com.ncapdevi.fragnav.FragNavController
import
com.ncapdevi.fragnav.FragNavTransactionOptions
import
com.skoumal.teanity.viewevents.ViewEvent
import
com.topjohnwu.magisk.Config
import
com.topjohnwu.magisk.model.events.BackPressEvent
import
com.topjohnwu.magisk.model.events.PermissionEvent
import
com.topjohnwu.magisk.model.events.ViewActionEvent
import
com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
...
...
@@ -36,7 +37,8 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
protected
open
val
defaultPosition
:
Int
=
0
protected
val
navigationController
by
lazy
{
protected
val
navigationController
get
()
=
if
(
navHostId
==
0
)
null
else
_navigationController
private
val
_navigationController
by
lazy
{
if
(
navHostId
==
0
)
throw
IllegalStateException
(
"Did you forget to override \"navHostId\"?"
)
FragNavController
(
supportFragmentManager
,
navHostId
)
}
...
...
@@ -54,7 +56,7 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
navigationController
.
apply
{
navigationController
?
.
apply
{
rootFragmentListener
=
this
@MagiskActivity
initialize
(
defaultPosition
,
savedInstanceState
)
}
...
...
@@ -62,13 +64,14 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
override
fun
onSaveInstanceState
(
outState
:
Bundle
)
{
super
.
onSaveInstanceState
(
outState
)
navigationController
.
onSaveInstanceState
(
outState
)
navigationController
?
.
onSaveInstanceState
(
outState
)
}
@CallSuper
override
fun
onEventDispatched
(
event
:
ViewEvent
)
{
super
.
onEventDispatched
(
event
)
when
(
event
)
{
is
BackPressEvent
->
onBackPressed
()
is
MagiskNavigationEvent
->
navigateTo
(
event
)
is
ViewActionEvent
->
event
.
action
(
this
)
is
PermissionEvent
->
withPermissions
(*
event
.
permissions
.
toTypedArray
())
{
...
...
@@ -86,15 +89,15 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
override
fun
navigateTo
(
event
:
MagiskNavigationEvent
)
{
val
directions
=
event
.
navDirections
navigationController
.
defaultTransactionOptions
=
FragNavTransactionOptions
.
newBuilder
()
navigationController
?
.
defaultTransactionOptions
=
FragNavTransactionOptions
.
newBuilder
()
.
customAnimations
(
event
.
animOptions
)
.
build
()
navigationController
.
currentStack
navigationController
?
.
currentStack
?.
indexOfFirst
{
it
.
javaClass
==
event
.
navOptions
.
popUpTo
}
?.
let
{
if
(
it
==
-
1
)
null
else
it
}
// invalidate if class is not found
?.
let
{
if
(
event
.
navOptions
.
inclusive
)
it
+
1
else
it
}
?.
let
{
navigationController
.
popFragments
(
it
)
}
?.
let
{
navigationController
?
.
popFragments
(
it
)
}
when
(
directions
.
isActivity
)
{
true
->
navigateToActivity
(
event
)
...
...
@@ -127,21 +130,21 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
when
(
val
index
=
baseFragments
.
indexOfFirst
{
it
.
java
.
name
==
destination
.
name
})
{
-
1
->
destination
.
newInstance
()
.
apply
{
arguments
=
event
.
navDirections
.
args
}
.
let
{
navigationController
.
pushFragment
(
it
)
}
.
let
{
navigationController
?
.
pushFragment
(
it
)
}
// When it's desired that fragments of same class are put on top of one another edit this
else
->
navigationController
.
switchTab
(
index
)
else
->
navigationController
?
.
switchTab
(
index
)
}
}
override
fun
onBackPressed
()
{
val
fragment
=
navigationController
.
currentFrag
as
?
MagiskFragment
<*,
*>
val
fragment
=
navigationController
?
.
currentFrag
as
?
MagiskFragment
<*,
*>
if
(
fragment
?.
onBackPressed
()
==
true
)
{
return
}
try
{
navigationController
.
popFragment
()
navigationController
?.
popFragment
()
?:
throw
UnsupportedOperationException
()
}
catch
(
e
:
UnsupportedOperationException
)
{
super
.
onBackPressed
()
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskFragment.kt
View file @
14ff22fb
...
...
@@ -5,6 +5,7 @@ import androidx.databinding.ViewDataBinding
import
androidx.fragment.app.Fragment
import
com.skoumal.teanity.view.TeanityFragment
import
com.skoumal.teanity.viewevents.ViewEvent
import
com.topjohnwu.magisk.model.events.BackPressEvent
import
com.topjohnwu.magisk.model.events.PermissionEvent
import
com.topjohnwu.magisk.model.events.ViewActionEvent
import
com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
...
...
@@ -27,6 +28,7 @@ abstract class MagiskFragment<ViewModel : MagiskViewModel, Binding : ViewDataBin
override
fun
onEventDispatched
(
event
:
ViewEvent
)
{
super
.
onEventDispatched
(
event
)
when
(
event
)
{
is
BackPressEvent
->
magiskActivity
.
onBackPressed
()
is
MagiskNavigationEvent
->
navigateTo
(
event
)
is
ViewActionEvent
->
event
.
action
(
requireActivity
())
is
PermissionEvent
->
magiskActivity
.
withPermissions
(*
event
.
permissions
.
toTypedArray
())
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskViewModel.kt
View file @
14ff22fb
...
...
@@ -2,6 +2,7 @@ package com.topjohnwu.magisk.ui.base
import
android.app.Activity
import
com.skoumal.teanity.viewmodel.LoadingViewModel
import
com.topjohnwu.magisk.model.events.BackPressEvent
import
com.topjohnwu.magisk.model.events.PermissionEvent
import
com.topjohnwu.magisk.model.events.ViewActionEvent
import
com.topjohnwu.magisk.utils.Event
...
...
@@ -23,4 +24,7 @@ abstract class MagiskViewModel : LoadingViewModel(), Event.AutoListener {
val
subject
=
PublishSubject
.
create
<
Boolean
>()
return
subject
.
doOnSubscribe
{
PermissionEvent
(
permissions
.
toList
(),
subject
).
publish
()
}
}
fun
back
()
=
BackPressEvent
().
publish
()
}
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.java
deleted
100644 → 0
View file @
07eb7dda
package
com
.
topjohnwu
.
magisk
.
ui
.
flash
;
import
android.content.Intent
;
import
android.net.Uri
;
import
android.os.Bundle
;
import
android.view.View
;
import
android.widget.Button
;
import
android.widget.LinearLayout
;
import
android.widget.Toast
;
import
androidx.annotation.NonNull
;
import
androidx.appcompat.app.ActionBar
;
import
androidx.appcompat.widget.Toolbar
;
import
androidx.recyclerview.widget.RecyclerView
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.adapters.StringListAdapter
;
import
com.topjohnwu.magisk.tasks.FlashZip
;
import
com.topjohnwu.magisk.tasks.MagiskInstaller
;
import
com.topjohnwu.magisk.ui.base.BaseActivity
;
import
com.topjohnwu.magisk.utils.RootUtils
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.superuser.CallbackList
;
import
com.topjohnwu.superuser.Shell
;
import
com.topjohnwu.superuser.internal.UiThreadHandler
;
import
java.io.File
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Locale
;
import
butterknife.BindColor
;
import
butterknife.BindView
;
import
butterknife.OnClick
;
public
class
FlashActivity
extends
BaseActivity
{
@BindView
(
R
.
id
.
toolbar
)
Toolbar
toolbar
;
@BindView
(
R
.
id
.
button_panel
)
LinearLayout
buttonPanel
;
@BindView
(
R
.
id
.
reboot
)
Button
reboot
;
@BindView
(
R
.
id
.
recyclerView
)
RecyclerView
rv
;
@BindColor
(
android
.
R
.
color
.
white
)
int
white
;
private
List
<
String
>
console
,
logs
;
@OnClick
(
R
.
id
.
reboot
)
void
reboot
()
{
RootUtils
.
reboot
();
}
@OnClick
(
R
.
id
.
save_logs
)
void
saveLogs
()
{
runWithExternalRW
(()
->
{
Calendar
now
=
Calendar
.
getInstance
();
String
filename
=
String
.
format
(
Locale
.
US
,
"magisk_install_log_%04d%02d%02d_%02d%02d%02d.log"
,
now
.
get
(
Calendar
.
YEAR
),
now
.
get
(
Calendar
.
MONTH
)
+
1
,
now
.
get
(
Calendar
.
DAY_OF_MONTH
),
now
.
get
(
Calendar
.
HOUR_OF_DAY
),
now
.
get
(
Calendar
.
MINUTE
),
now
.
get
(
Calendar
.
SECOND
));
File
logFile
=
new
File
(
Const
.
EXTERNAL_PATH
,
filename
);
try
(
FileWriter
writer
=
new
FileWriter
(
logFile
))
{
for
(
String
s
:
logs
)
{
writer
.
write
(
s
);
writer
.
write
(
'\n'
);
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
;
}
Utils
.
toast
(
logFile
.
getPath
(),
Toast
.
LENGTH_LONG
);
});
}
@OnClick
(
R
.
id
.
close
)
public
void
close
()
{
finish
();
}
@Override
public
void
onBackPressed
()
{
// Prevent user accidentally press back button
}
@Override
public
int
getDarkTheme
()
{
return
R
.
style
.
AppTheme_NoDrawer_Dark
;
}
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_flash
);
new
FlashActivity_ViewBinding
(
this
);
setSupportActionBar
(
toolbar
);
ActionBar
ab
=
getSupportActionBar
();
if
(
ab
!=
null
)
{
ab
.
setTitle
(
R
.
string
.
flashing
);
}
setFloating
();
setFinishOnTouchOutside
(
false
);
if
(!
Shell
.
rootAccess
())
reboot
.
setVisibility
(
View
.
GONE
);
logs
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
console
=
new
ConsoleList
();
rv
.
setAdapter
(
new
ConsoleAdapter
());
Intent
intent
=
getIntent
();
Uri
uri
=
intent
.
getData
();
switch
(
intent
.
getStringExtra
(
Const
.
Key
.
FLASH_ACTION
))
{
case
Const
.
Value
.
FLASH_ZIP
:
new
FlashModule
(
uri
).
exec
();
break
;
case
Const
.
Value
.
UNINSTALL
:
new
Uninstall
(
uri
).
exec
();
break
;
case
Const
.
Value
.
FLASH_MAGISK
:
new
DirectInstall
().
exec
();
break
;
case
Const
.
Value
.
FLASH_INACTIVE_SLOT
:
new
SecondSlot
().
exec
();
break
;
case
Const
.
Value
.
PATCH_FILE
:
new
PatchFile
(
uri
).
exec
();
break
;
}
}
private
class
ConsoleAdapter
extends
StringListAdapter
<
ConsoleAdapter
.
ViewHolder
>
{
ConsoleAdapter
()
{
super
(
console
,
true
);
}
@Override
protected
int
itemLayoutRes
()
{
return
R
.
layout
.
list_item_console
;
}
@NonNull
@Override
public
ViewHolder
createViewHolder
(
@NonNull
View
v
)
{
return
new
ViewHolder
(
v
);
}
class
ViewHolder
extends
StringListAdapter
.
ViewHolder
{
public
ViewHolder
(
@NonNull
View
itemView
)
{
super
(
itemView
);
txt
.
setTextColor
(
white
);
}
@Override
protected
int
textViewResId
()
{
return
R
.
id
.
txt
;
}
}
}
private
class
ConsoleList
extends
CallbackList
<
String
>
{
ConsoleList
()
{
super
(
new
ArrayList
<>());
}
private
void
updateUI
()
{
rv
.
getAdapter
().
notifyItemChanged
(
size
()
-
1
);
rv
.
postDelayed
(()
->
rv
.
smoothScrollToPosition
(
size
()
-
1
),
10
);
}
@Override
public
void
onAddElement
(
String
s
)
{
logs
.
add
(
s
);
updateUI
();
}
@Override
public
String
set
(
int
i
,
String
s
)
{
String
ret
=
super
.
set
(
i
,
s
);
UiThreadHandler
.
run
(
this
::
updateUI
);
return
ret
;
}
}
private
class
FlashModule
extends
FlashZip
{
FlashModule
(
Uri
uri
)
{
super
(
uri
,
console
,
logs
);
}
@Override
protected
void
onResult
(
boolean
success
)
{
if
(
success
)
{
Utils
.
loadModules
();
}
else
{
console
.
add
(
"! Installation failed"
);
reboot
.
setVisibility
(
View
.
GONE
);
}
buttonPanel
.
setVisibility
(
View
.
VISIBLE
);
}
}
private
class
Uninstall
extends
FlashModule
{
Uninstall
(
Uri
uri
)
{
super
(
uri
);
}
@Override
protected
void
onResult
(
boolean
success
)
{
if
(
success
)
UiThreadHandler
.
handler
.
postDelayed
(
Shell
.
su
(
"pm uninstall "
+
getPackageName
())::
exec
,
3000
);
else
super
.
onResult
(
false
);
}
}
private
abstract
class
BaseInstaller
extends
MagiskInstaller
{
BaseInstaller
()
{
super
(
console
,
logs
);
}
@Override
protected
void
onResult
(
boolean
success
)
{
if
(
success
)
{
console
.
add
(
"- All done!"
);
}
else
{
Shell
.
sh
(
"rm -rf "
+
installDir
).
submit
();
console
.
add
(
"! Installation failed"
);
reboot
.
setVisibility
(
View
.
GONE
);
}
buttonPanel
.
setVisibility
(
View
.
VISIBLE
);
}
}
private
class
DirectInstall
extends
BaseInstaller
{
@Override
protected
boolean
operations
()
{
return
findImage
()
&&
extractZip
()
&&
patchBoot
()
&&
flashBoot
();
}
}
private
class
SecondSlot
extends
BaseInstaller
{
@Override
protected
boolean
operations
()
{
return
findSecondaryImage
()
&&
extractZip
()
&&
patchBoot
()
&&
flashBoot
()
&&
postOTA
();
}
}
private
class
PatchFile
extends
BaseInstaller
{
private
Uri
uri
;
PatchFile
(
Uri
u
)
{
uri
=
u
;
}
@Override
protected
boolean
operations
()
{
return
extractZip
()
&&
handleFile
(
uri
)
&&
patchBoot
()
&&
storeBoot
();
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt
0 → 100644
View file @
14ff22fb
package
com.topjohnwu.magisk.ui.flash
import
com.topjohnwu.magisk.Const
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.databinding.ActivityFlashBinding
import
com.topjohnwu.magisk.ui.base.MagiskActivity
import
org.koin.androidx.viewmodel.ext.android.viewModel
import
org.koin.core.parameter.parametersOf
open
class
FlashActivity
:
MagiskActivity
<
FlashViewModel
,
ActivityFlashBinding
>()
{
override
val
layoutRes
:
Int
=
R
.
layout
.
activity_flash
override
val
viewModel
:
FlashViewModel
by
viewModel
{
val
uri
=
intent
.
data
val
action
=
intent
.
getStringExtra
(
Const
.
Key
.
FLASH_ACTION
)
?:
let
{
finish
();
""
}
parametersOf
(
action
,
uri
)
}
override
fun
onBackPressed
()
{
if
(
viewModel
.
loading
)
return
super
.
onBackPressed
()
}
}
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
0 → 100644
View file @
14ff22fb
package
com.topjohnwu.magisk.ui.flash
import
android.Manifest.permission.READ_EXTERNAL_STORAGE
import
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import
android.content.res.Resources
import
android.net.Uri
import
android.os.Handler
import
androidx.core.os.postDelayed
import
androidx.databinding.ObservableArrayList
import
com.skoumal.teanity.databinding.ComparableRvItem
import
com.skoumal.teanity.extensions.subscribeK
import
com.skoumal.teanity.util.DiffObservableList
import
com.skoumal.teanity.util.KObservableField
import
com.skoumal.teanity.viewevents.SnackbarEvent
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.Const
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem
import
com.topjohnwu.magisk.model.flash.FlashResultListener
import
com.topjohnwu.magisk.model.flash.Flashing
import
com.topjohnwu.magisk.model.flash.Patching
import
com.topjohnwu.magisk.ui.base.MagiskViewModel
import
com.topjohnwu.magisk.utils.*
import
com.topjohnwu.superuser.Shell
import
me.tatarka.bindingcollectionadapter2.ItemBinding
import
java.io.File
class
FlashViewModel
(
action
:
String
,
uri
:
Uri
?,
private
val
resources
:
Resources
)
:
MagiskViewModel
(),
FlashResultListener
{
val
canShowReboot
=
Shell
.
rootAccess
()
val
showRestartTitle
=
KObservableField
(
false
)
val
behaviorText
=
KObservableField
(
resources
.
getString
(
R
.
string
.
flashing
))
val
items
=
DiffObservableList
(
ComparableRvItem
.
callback
)
val
itemBinding
=
ItemBinding
.
of
<
ComparableRvItem
<*>>
{
itemBinding
,
_
,
item
->
item
.
bind
(
itemBinding
)
itemBinding
.
bindExtra
(
BR
.
viewModel
,
this
@FlashViewModel
)
}
private
val
rawItems
=
ObservableArrayList
<
String
>()
init
{
rawItems
.
sendUpdatesTo
(
items
)
{
it
.
map
{
ConsoleRvItem
(
it
)
}
}
state
=
State
.
LOADING
val
uri
=
uri
?:
Uri
.
EMPTY
when
(
action
)
{
Const
.
Value
.
FLASH_ZIP
->
Flashing
.
Install
(
uri
,
rawItems
,
rawItems
,
this
)
.
exec
()
Const
.
Value
.
UNINSTALL
->
Flashing
.
Uninstall
(
uri
,
rawItems
,
rawItems
,
this
)
.
exec
()
Const
.
Value
.
FLASH_MAGISK
->
Patching
.
Direct
(
rawItems
,
rawItems
,
this
)
.
exec
()
Const
.
Value
.
FLASH_INACTIVE_SLOT
->
Patching
.
SecondSlot
(
rawItems
,
rawItems
,
this
)
.
exec
()
Const
.
Value
.
PATCH_FILE
->
Patching
.
File
(
uri
,
rawItems
,
rawItems
,
this
)
.
exec
()
}
}
override
fun
onResult
(
isSuccess
:
Boolean
)
{
state
=
if
(
isSuccess
)
State
.
LOADED
else
State
.
LOADING_FAILED
behaviorText
.
value
=
when
{
isSuccess
->
resources
.
getString
(
R
.
string
.
done
)
else
->
resources
.
getString
(
R
.
string
.
failure
)
}
if
(
isSuccess
)
{
Handler
().
postDelayed
(
500
)
{
showRestartTitle
.
value
=
true
}
}
}
fun
savePressed
()
=
withPermissions
(
READ_EXTERNAL_STORAGE
,
WRITE_EXTERNAL_STORAGE
)
.
map
{
now
}
.
map
{
it
.
toTime
(
timeFormatFull
)
}
.
map
{
Const
.
MAGISK_INSTALL_LOG_FILENAME
.
format
(
it
)
}
.
map
{
File
(
Const
.
EXTERNAL_PATH
,
it
)
}
.
map
{
file
->
val
log
=
items
.
filterIsInstance
<
ConsoleRvItem
>()
.
joinToString
(
"\n"
)
{
it
.
item
}
file
.
writeText
(
log
)
file
.
path
}
.
subscribeK
{
SnackbarEvent
(
it
).
publish
()
}
.
add
()
fun
restartPressed
()
=
RootUtils
.
reboot
()
fun
backPressed
()
=
back
()
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt
View file @
14ff22fb
package
com.topjohnwu.magisk.utils
import
android.view.View
import
android.widget.TextView
import
androidx.annotation.ColorInt
import
androidx.annotation.DrawableRes
import
androidx.appcompat.widget.AppCompatImageView
...
...
@@ -9,10 +10,15 @@ import androidx.databinding.BindingAdapter
import
androidx.databinding.InverseBindingAdapter
import
androidx.databinding.InverseBindingListener
import
androidx.drawerlayout.widget.DrawerLayout
import
androidx.interpolator.view.animation.FastOutSlowInInterpolator
import
androidx.viewpager.widget.ViewPager
import
com.google.android.material.navigation.NavigationView
import
com.skoumal.teanity.extensions.subscribeK
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.model.entity.state.IndeterminateState
import
io.reactivex.Observable
import
io.reactivex.disposables.Disposable
import
java.util.concurrent.TimeUnit
@BindingAdapter
(
"onNavigationClick"
)
...
...
@@ -80,4 +86,28 @@ fun setPositionChangedListener(view: ViewPager, listener: InverseBindingListener
positionOffsetPixels
:
Int
)
=
listener
.
onChange
()
})
}
@BindingAdapter
(
"invisibleScale"
)
fun
setInvisibleWithScale
(
view
:
View
,
isInvisible
:
Boolean
)
{
view
.
animate
()
.
scaleX
(
if
(
isInvisible
)
0f
else
1f
)
.
scaleY
(
if
(
isInvisible
)
0f
else
1f
)
.
setInterpolator
(
FastOutSlowInInterpolator
())
.
start
()
}
@BindingAdapter
(
"movieBehavior"
,
"movieBehaviorText"
)
fun
setMovieBehavior
(
view
:
TextView
,
isMovieBehavior
:
Boolean
,
text
:
String
)
{
(
view
.
tag
as
?
Disposable
)
?.
dispose
()
if
(
isMovieBehavior
)
{
val
observer
=
Observable
.
interval
(
150
,
TimeUnit
.
MILLISECONDS
)
.
subscribeK
{
view
.
text
=
text
.
replaceRandomWithSpecial
()
}
view
.
tag
=
observer
}
else
{
view
.
text
=
text
}
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/utils/XList.kt
View file @
14ff22fb
package
com.topjohnwu.magisk.utils
import
androidx.databinding.ObservableList
import
com.skoumal.teanity.extensions.subscribeK
import
com.skoumal.teanity.util.DiffObservableList
import
io.reactivex.disposables.Disposable
fun
<
T
>
MutableList
<
T
>.
update
(
newList
:
List
<
T
>)
{
clear
()
addAll
(
newList
)
}
fun
<
T1
,
T2
>
ObservableList
<
T1
>.
sendUpdatesTo
(
target
:
DiffObservableList
<
T2
>,
mapper
:
(
List
<
T1
>)
->
List
<
T2
>
)
{
addOnListChangedCallback
(
object
:
ObservableList
.
OnListChangedCallback
<
ObservableList
<
T1
>>()
{
override
fun
onChanged
(
sender
:
ObservableList
<
T1
>?)
{
updateAsync
(
sender
?:
return
)
}
override
fun
onItemRangeRemoved
(
sender
:
ObservableList
<
T1
>?,
p0
:
Int
,
p1
:
Int
)
{
updateAsync
(
sender
?:
return
)
}
override
fun
onItemRangeMoved
(
sender
:
ObservableList
<
T1
>?,
p0
:
Int
,
p1
:
Int
,
p2
:
Int
)
{
updateAsync
(
sender
?:
return
)
}
override
fun
onItemRangeInserted
(
sender
:
ObservableList
<
T1
>?,
p0
:
Int
,
p1
:
Int
)
{
updateAsync
(
sender
?:
return
)
}
override
fun
onItemRangeChanged
(
sender
:
ObservableList
<
T1
>?,
p0
:
Int
,
p1
:
Int
)
{
updateAsync
(
sender
?:
return
)
}
private
var
updater
:
Disposable
?
=
null
private
fun
updateAsync
(
sender
:
List
<
T1
>)
{
updater
?.
dispose
()
updater
=
sender
.
toSingle
()
.
map
{
mapper
(
it
)
}
.
map
{
it
to
target
.
calculateDiff
(
it
)
}
.
subscribeK
{
target
.
update
(
it
.
first
,
it
.
second
)
}
}
})
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/utils/XString.kt
0 → 100644
View file @
14ff22fb
package
com.topjohnwu.magisk.utils
val
specialChars
=
arrayOf
(
'!'
,
'@'
,
'#'
,
'$'
,
'%'
,
'&'
,
'?'
)
fun
String
.
replaceRandomWithSpecial
():
String
{
var
random
:
Char
do
{
random
=
random
()
}
while
(
random
==
'.'
)
return
replace
(
random
,
specialChars
.
random
())
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/utils/XTime.kt
0 → 100644
View file @
14ff22fb
package
com.topjohnwu.magisk.utils
import
java.text.ParseException
import
java.text.SimpleDateFormat
import
java.util.*
val
now
get
()
=
System
.
currentTimeMillis
()
fun
Long
.
toTime
(
format
:
SimpleDateFormat
)
=
format
.
format
(
this
).
orEmpty
()
fun
String
.
toTime
(
format
:
SimpleDateFormat
)
=
try
{
format
.
parse
(
this
)
?.
time
?:
-
1
}
catch
(
e
:
ParseException
)
{
-
1L
}
private
val
locale
get
()
=
Locale
.
getDefault
()
val
timeFormatFull
by
lazy
{
SimpleDateFormat
(
"YYYY/MM/DD_HH:mm:ss"
,
locale
)
}
val
timeFormatStandard
by
lazy
{
SimpleDateFormat
(
"YYYY-MM-DD'T'HH:mm:ss'Z'"
,
locale
)
}
\ No newline at end of file
app/src/main/res/drawable/ic_back.xml
0 → 100644
View file @
14ff22fb
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
>
<path
android:fillColor=
"@color/colorText"
android:pathData=
"M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"
/>
</vector>
\ No newline at end of file
app/src/main/res/drawable/ic_restart.xml
0 → 100644
View file @
14ff22fb
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
>
<path
android:fillColor=
"#000"
android:pathData=
"M12,4C14.1,4 16.1,4.8 17.6,6.3C20.7,9.4 20.7,14.5 17.6,17.6C15.8,19.5 13.3,20.2 10.9,19.9L11.4,17.9C13.1,18.1 14.9,17.5 16.2,16.2C18.5,13.9 18.5,10.1 16.2,7.7C15.1,6.6 13.5,6 12,6V10.6L7,5.6L12,0.6V4M6.3,17.6C3.7,15 3.3,11 5.1,7.9L6.6,9.4C5.5,11.6 5.9,14.4 7.8,16.2C8.3,16.7 8.9,17.1 9.6,17.4L9,19.4C8,19 7.1,18.4 6.3,17.6Z"
/>
</vector>
\ No newline at end of file
app/src/main/res/layout/activity_flash.xml
View file @
14ff22fb
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@color/flashing_background_color"
android:orientation=
"vertical"
>
<layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
>
<
include
layout=
"@layout/toolbar"
/
>
<
data
>
<HorizontalScrollView
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
<variable
name=
"viewModel"
type=
"com.topjohnwu.magisk.ui.flash.FlashViewModel"
/>
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"1"
>
android:layout_height=
"match_parent"
>
<com.google.android.material.appbar.AppBarLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:theme=
"@style/AppBarLayoutTheme.Flashing"
>
<androidx.appcompat.widget.Toolbar
android:layout_width=
"match_parent"
android:layout_height=
"?attr/actionBarSize"
app:contentInsetLeft=
"0dp"
app:contentInsetStart=
"0dp"
app:popupTheme=
"@style/ToolbarPopupTheme.Flashing"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:animateLayoutChanges=
"true"
>
<FrameLayout
invisibleScale=
"@{viewModel.loading}"
android:layout_width=
"0dp"
android:layout_height=
"match_parent"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:onClick=
"@{() -> viewModel.backPressed()}"
app:layout_constraintDimensionRatio=
"1:1"
app:layout_constraintLeft_toLeftOf=
"parent"
>
<androidx.appcompat.widget.AppCompatImageView
style=
"@style/Widget.Icon"
android:layout_gravity=
"center"
android:background=
"@android:color/transparent"
app:srcCompat=
"@drawable/ic_back"
app:tint=
"@android:color/white"
/>
</FrameLayout>
<androidx.appcompat.widget.AppCompatTextView
style=
"@style/Widget.Text.Emphasize"
movieBehavior=
"@{viewModel.loading}"
movieBehaviorText=
"@{viewModel.behaviorText}"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:fontFamily=
"monospace"
android:textColor=
"@android:color/white"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"Flashing..."
/>
<FrameLayout
invisibleScale=
"@{viewModel.loading}"
android:layout_width=
"0dp"
android:layout_height=
"match_parent"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:onClick=
"@{() -> viewModel.savePressed()}"
app:layout_constraintDimensionRatio=
"1:1"
app:layout_constraintRight_toRightOf=
"parent"
>
<androidx.appcompat.widget.AppCompatImageView
style=
"@style/Widget.Icon"
android:layout_gravity=
"center"
android:background=
"@android:color/transparent"
app:srcCompat=
"@drawable/ic_save"
app:tint=
"@android:color/white"
/>
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id=
"@+id/recyclerView"
android:layout_width=
"wrap_content"
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:paddingStart=
"8dp"
android:paddingEnd=
"8dp"
app:layoutManager=
"androidx.recyclerview.widget.LinearLayoutManager"
/>
app:layout_behavior=
"@string/appbar_scrolling_view_behavior"
>
</HorizontalScrollView>
<androidx.recyclerview.widget.RecyclerView
itemBinding=
"@{viewModel.itemBinding}"
items=
"@{viewModel.items}"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
app:layoutManager=
"androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem=
"@layout/item_console"
/>
<LinearLayout
android:id=
"@+id/button_panel"
style=
"?android:buttonStyle"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"10dp"
android:orientation=
"horizontal"
android:visibility=
"gone"
>
<Button
android:id=
"@+id/close"
style=
"?android:borderlessButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"50dp"
android:layout_weight=
"1"
android:text=
"@string/close"
/>
<Button
android:id=
"@+id/save_logs"
style=
"?android:borderlessButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"50dp"
android:layout_weight=
"1"
android:text=
"@string/menuSaveLog"
/>
<Button
android:id=
"@+id/reboot"
style=
"?android:borderlessButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"50dp"
android:layout_weight=
"1"
android:text=
"@string/reboot"
/>
</LinearLayout>
</LinearLayout>
<com.google.android.material.card.MaterialCardView
invisibleScale=
"@{!viewModel.loaded || !viewModel.canShowReboot}"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_margin=
"@dimen/margin_generic"
app:cardBackgroundColor=
"@color/colorSecondary"
app:cardCornerRadius=
"26dp"
app:cardPreventCornerOverlap=
"true"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:animateLayoutChanges=
"true"
android:background=
"?attr/selectableItemBackground"
android:gravity=
"center"
android:onClick=
"@{() -> viewModel.restartPressed()}"
android:padding=
"@dimen/margin_generic_half"
>
<androidx.appcompat.widget.AppCompatImageView
style=
"@style/Widget.Icon"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:background=
"@android:color/transparent"
app:srcCompat=
"@drawable/ic_restart"
app:tint=
"@color/colorTextTinted"
/>
<androidx.appcompat.widget.AppCompatTextView
style=
"@style/Widget.Text.Emphasize.Tinted"
gone=
"@{!viewModel.showRestartTitle}"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"@dimen/margin_generic_half"
android:paddingRight=
"@dimen/margin_generic_half"
android:text=
"@string/reboot"
/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
14ff22fb
...
...
@@ -99,7 +99,9 @@
<string
name=
"dtbo_patched_title"
>
DTBO was patched!
</string>
<string
name=
"dtbo_patched_reboot"
>
Magisk Manager has patched dtbo.img. Please reboot.
</string>
<string
name=
"flashing"
>
Flashing
</string>
<string
name=
"flashing"
>
Flashing…
</string>
<string
name=
"done"
>
Done!
</string>
<string
name=
"failure"
>
Failed
</string>
<string
name=
"hide_manager_title"
>
Hiding Magisk Manager…
</string>
<string
name=
"hide_manager_fail_toast"
>
Hide Magisk Manager failed.
</string>
<string
name=
"open_link_failed_toast"
>
No application found to open the link.
</string>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment