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
6dbd8baa
Commit
6dbd8baa
authored
Nov 07, 2021
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleanup DownloadService
parent
e660fabc
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
126 additions
and
210 deletions
+126
-210
Const.kt
app/src/main/java/com/topjohnwu/magisk/core/Const.kt
+0
-2
DownloadService.kt
...ava/com/topjohnwu/magisk/core/download/DownloadService.kt
+48
-99
ManagerHandler.kt
...java/com/topjohnwu/magisk/core/download/ManagerHandler.kt
+14
-24
ModuleProcessor.kt
...ava/com/topjohnwu/magisk/core/download/ModuleProcessor.kt
+0
-43
Subject.kt
...c/main/java/com/topjohnwu/magisk/core/download/Subject.kt
+33
-13
ProgressInputStream.kt
...va/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt
+6
-1
ModuleInstallDialog.kt
...com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt
+2
-2
XJava.kt
app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt
+8
-10
FlashFragment.kt
.../main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
+2
-4
FlashViewModel.kt
...main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
+1
-4
HomeFragment.kt
...rc/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
+4
-0
Notifications.kt
app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
+8
-3
main.xml
app/src/main/res/navigation/main.xml
+0
-5
No files found.
app/src/main/java/com/topjohnwu/magisk/core/Const.kt
View file @
6dbd8baa
...
@@ -39,8 +39,6 @@ object Const {
...
@@ -39,8 +39,6 @@ object Const {
}
}
object
ID
{
object
ID
{
// notifications
const
val
APK_UPDATE_NOTIFICATION_ID
=
5
const
val
JOB_SERVICE_ID
=
7
const
val
JOB_SERVICE_ID
=
7
const
val
UPDATE_NOTIFICATION_CHANNEL
=
"update"
const
val
UPDATE_NOTIFICATION_CHANNEL
=
"update"
const
val
PROGRESS_NOTIFICATION_CHANNEL
=
"progress"
const
val
PROGRESS_NOTIFICATION_CHANNEL
=
"progress"
...
...
app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt
View file @
6dbd8baa
...
@@ -3,66 +3,47 @@ package com.topjohnwu.magisk.core.download
...
@@ -3,66 +3,47 @@ package com.topjohnwu.magisk.core.download
import
android.annotation.SuppressLint
import
android.annotation.SuppressLint
import
android.app.Notification
import
android.app.Notification
import
android.app.PendingIntent
import
android.app.PendingIntent
import
android.app.PendingIntent.*
import
android.content.Context
import
android.content.Context
import
android.content.Intent
import
android.content.Intent
import
android.os.Build
import
android.os.Build
import
android.os.IBinder
import
android.os.IBinder
import
androidx.core.net.toFile
import
androidx.lifecycle.LifecycleOwner
import
androidx.lifecycle.LifecycleOwner
import
androidx.lifecycle.MutableLiveData
import
androidx.lifecycle.MutableLiveData
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.arch.BaseUIActivity
import
com.topjohnwu.magisk.core.ForegroundTracker
import
com.topjohnwu.magisk.core.ForegroundTracker
import
com.topjohnwu.magisk.core.base.BaseService
import
com.topjohnwu.magisk.core.base.BaseService
import
com.topjohnwu.magisk.core.download.Action.Flash
import
com.topjohnwu.magisk.core.download.Subject.Manager
import
com.topjohnwu.magisk.core.download.Subject.Module
import
com.topjohnwu.magisk.core.intent
import
com.topjohnwu.magisk.core.intent
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import
com.topjohnwu.magisk.core.utils.ProgressInputStream
import
com.topjohnwu.magisk.core.utils.ProgressInputStream
import
com.topjohnwu.magisk.di.ServiceLocator
import
com.topjohnwu.magisk.di.ServiceLocator
import
com.topjohnwu.magisk.
ui.flash.FlashFragment
import
com.topjohnwu.magisk.
ktx.copyAndClose
import
com.topjohnwu.magisk.
utils.APKInstall
import
com.topjohnwu.magisk.
ktx.synchronized
import
com.topjohnwu.magisk.view.Notifications
import
com.topjohnwu.magisk.view.Notifications
import
com.topjohnwu.superuser.internal.UiThreadHandler
import
com.topjohnwu.magisk.view.Notifications.mgr
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.*
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.cancel
import
kotlinx.coroutines.launch
import
okhttp3.ResponseBody
import
okhttp3.ResponseBody
import
timber.log.Timber
import
timber.log.Timber
import
java.io.IOException
import
java.io.IOException
import
java.io.InputStream
import
java.io.InputStream
import
java.util.*
import
java.util.*
import
kotlin.collections.HashMap
import
kotlin.collections.HashMap
import
kotlin.random.Random.Default.nextInt
class
DownloadService
:
BaseService
()
{
class
DownloadService
:
BaseService
()
{
private
val
context
get
()
=
this
private
val
hasNotifications
get
()
=
notifications
.
isNotEmpty
()
private
val
hasNotifications
get
()
=
notifications
.
isNotEmpty
()
private
val
notifications
=
Collections
.
synchronizedMap
(
HashMap
<
Int
,
Notification
.
Builder
>()
)
private
val
notifications
=
HashMap
<
Int
,
Notification
.
Builder
>().
synchronized
(
)
private
val
coroutineScope
=
CoroutineScope
(
Dispatchers
.
IO
)
private
val
job
=
Job
(
)
val
service
get
()
=
ServiceLocator
.
networkService
val
service
get
()
=
ServiceLocator
.
networkService
private
val
mgr
get
()
=
Notifications
.
mgr
// -- Service overrides
// -- Service overrides
override
fun
onBind
(
intent
:
Intent
?):
IBinder
?
=
null
override
fun
onBind
(
intent
:
Intent
?):
IBinder
?
=
null
override
fun
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
):
Int
{
override
fun
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
):
Int
{
intent
.
getParcelableExtra
<
Subject
>(
SUBJECT_KEY
)
?.
let
{
subject
->
intent
.
getParcelableExtra
<
Subject
>(
SUBJECT_KEY
)
?.
let
{
doDownload
(
it
)
}
update
(
subject
.
notifyID
())
return
START_NOT_STICKY
coroutineScope
.
launch
{
try
{
subject
.
startDownload
()
}
catch
(
e
:
IOException
)
{
Timber
.
e
(
e
)
notifyFail
(
subject
)
}
}
}
return
START_REDELIVER_INTENT
}
}
override
fun
onTaskRemoved
(
rootIntent
:
Intent
?)
{
override
fun
onTaskRemoved
(
rootIntent
:
Intent
?)
{
...
@@ -73,29 +54,40 @@ class DownloadService : BaseService() {
...
@@ -73,29 +54,40 @@ class DownloadService : BaseService() {
override
fun
onDestroy
()
{
override
fun
onDestroy
()
{
super
.
onDestroy
()
super
.
onDestroy
()
coroutineScope
.
cancel
()
job
.
cancel
()
}
}
// -- Download logic
// -- Download logic
private
suspend
fun
Subject
.
startDownload
()
{
private
fun
doDownload
(
subject
:
Subject
)
{
val
stream
=
service
.
fetchFile
(
url
).
toProgressStream
(
this
)
update
(
subject
.
notifyId
)
when
(
this
)
{
val
coroutineScope
=
CoroutineScope
(
job
+
Dispatchers
.
IO
)
is
Module
->
// Download and process on-the-fly
coroutineScope
.
launch
{
stream
.
toModule
(
file
,
service
.
fetchInstaller
().
byteStream
())
try
{
is
Manager
->
handleAPK
(
this
,
stream
)
val
stream
=
service
.
fetchFile
(
subject
.
url
).
toProgressStream
(
subject
)
when
(
subject
)
{
is
Subject
.
Manager
->
handleAPK
(
subject
,
stream
)
else
->
stream
.
copyAndClose
(
subject
.
file
.
outputStream
())
}
if
(
ForegroundTracker
.
hasForeground
)
{
remove
(
subject
.
notifyId
)
subject
.
pendingIntent
(
this
@DownloadService
).
send
()
}
else
{
notifyFinish
(
subject
)
}
}
val
newId
=
notifyFinish
(
this
)
if
(
ForegroundTracker
.
hasForeground
)
onFinish
(
this
,
newId
)
if
(!
hasNotifications
)
if
(!
hasNotifications
)
stopSelf
()
stopSelf
()
}
catch
(
e
:
IOException
)
{
Timber
.
e
(
e
)
notifyFail
(
subject
)
}
}
}
}
private
fun
ResponseBody
.
toProgressStream
(
subject
:
Subject
):
InputStream
{
private
fun
ResponseBody
.
toProgressStream
(
subject
:
Subject
):
InputStream
{
val
max
=
contentLength
()
val
max
=
contentLength
()
val
total
=
max
.
toFloat
()
/
1048576
val
total
=
max
.
toFloat
()
/
1048576
val
id
=
subject
.
notifyI
D
()
val
id
=
subject
.
notifyI
d
update
(
id
)
{
it
.
setContentTitle
(
subject
.
title
)
}
update
(
id
)
{
it
.
setContentTitle
(
subject
.
title
)
}
...
@@ -115,18 +107,18 @@ class DownloadService : BaseService() {
...
@@ -115,18 +107,18 @@ class DownloadService : BaseService() {
}
}
}
}
// --- Notification
s
// --- Notification
management
private
fun
notifyFail
(
subject
:
Subject
)
=
finalNotify
(
subject
.
notifyI
D
()
)
{
private
fun
notifyFail
(
subject
:
Subject
)
=
finalNotify
(
subject
.
notifyI
d
)
{
broadcast
(-
2f
,
subject
)
broadcast
(-
2f
,
subject
)
it
.
setContentText
(
getString
(
R
.
string
.
download_file_error
))
it
.
setContentText
(
getString
(
R
.
string
.
download_file_error
))
.
setSmallIcon
(
android
.
R
.
drawable
.
stat_notify_error
)
.
setSmallIcon
(
android
.
R
.
drawable
.
stat_notify_error
)
.
setOngoing
(
false
)
.
setOngoing
(
false
)
}
}
private
fun
notifyFinish
(
subject
:
Subject
)
=
finalNotify
(
subject
.
notifyI
D
()
)
{
private
fun
notifyFinish
(
subject
:
Subject
)
=
finalNotify
(
subject
.
notifyI
d
)
{
broadcast
(
1f
,
subject
)
broadcast
(
1f
,
subject
)
it
.
set
Intent
(
subject
)
it
.
set
ContentIntent
(
subject
.
pendingIntent
(
this
)
)
.
setContentTitle
(
subject
.
title
)
.
setContentTitle
(
subject
.
title
)
.
setContentText
(
getString
(
R
.
string
.
download_complete
))
.
setContentText
(
getString
(
R
.
string
.
download_complete
))
.
setSmallIcon
(
android
.
R
.
drawable
.
stat_sys_download_done
)
.
setSmallIcon
(
android
.
R
.
drawable
.
stat_sys_download_done
)
...
@@ -135,17 +127,14 @@ class DownloadService : BaseService() {
...
@@ -135,17 +127,14 @@ class DownloadService : BaseService() {
.
setAutoCancel
(
true
)
.
setAutoCancel
(
true
)
}
}
private
fun
finalNotify
(
private
fun
finalNotify
(
id
:
Int
,
editor
:
(
Notification
.
Builder
)
->
Unit
):
Int
{
id
:
Int
,
val
notification
=
remove
(
id
)
?.
also
(
editor
)
?:
return
-
1
editor
:
(
Notification
.
Builder
)
->
Notification
.
Builder
val
newId
=
Notifications
.
nextId
()
)
:
Int
{
val
notification
=
remove
(
id
)
?.
run
(
editor
)
?:
return
-
1
val
newId
=
nextInt
()
mgr
.
notify
(
newId
,
notification
.
build
())
mgr
.
notify
(
newId
,
notification
.
build
())
return
newId
return
newId
}
}
fun
create
()
=
Notifications
.
progress
(
this
,
""
)
private
fun
create
()
=
Notifications
.
progress
(
this
,
""
)
fun
update
(
id
:
Int
,
editor
:
(
Notification
.
Builder
)
->
Unit
=
{})
{
fun
update
(
id
:
Int
,
editor
:
(
Notification
.
Builder
)
->
Unit
=
{})
{
val
wasEmpty
=
!
hasNotifications
val
wasEmpty
=
!
hasNotifications
...
@@ -171,49 +160,9 @@ class DownloadService : BaseService() {
...
@@ -171,49 +160,9 @@ class DownloadService : BaseService() {
}
}
}
}
private
fun
Notification
.
Builder
.
setIntent
(
subject
:
Subject
)
=
when
(
subject
)
{
is
Module
->
setIntent
(
subject
)
is
Manager
->
setIntent
(
subject
)
}
private
fun
Notification
.
Builder
.
setIntent
(
subject
:
Module
)
=
when
(
subject
.
action
)
{
Flash
->
setContentIntent
(
FlashFragment
.
installIntent
(
context
,
subject
.
file
))
else
->
setContentIntent
(
Intent
())
}
private
fun
Notification
.
Builder
.
setIntent
(
subject
:
Manager
)
=
setContentIntent
(
APKInstall
.
installIntent
(
context
,
subject
.
file
.
toFile
()))
@SuppressLint
(
"InlinedApi"
)
private
fun
Notification
.
Builder
.
setContentIntent
(
intent
:
Intent
)
=
setContentIntent
(
PendingIntent
.
getActivity
(
context
,
nextInt
(),
intent
,
PendingIntent
.
FLAG_IMMUTABLE
or
PendingIntent
.
FLAG_ONE_SHOT
))
// -- Post download processing
private
fun
onFinish
(
subject
:
Subject
,
id
:
Int
)
=
when
(
subject
)
{
is
Module
->
subject
.
onFinish
(
id
)
is
Manager
->
subject
.
onFinish
(
id
)
}
private
fun
Module
.
onFinish
(
id
:
Int
)
=
when
(
action
)
{
Flash
->
{
UiThreadHandler
.
run
{
(
ForegroundTracker
.
foreground
as
?
BaseUIActivity
<*,
*>)
?.
navigation
?.
navigate
(
FlashFragment
.
install
(
file
,
id
))
}
}
else
->
Unit
}
private
fun
Manager
.
onFinish
(
id
:
Int
)
{
remove
(
id
)
APKInstall
.
install
(
context
,
file
.
toFile
())
}
companion
object
{
companion
object
{
private
const
val
SUBJECT_KEY
=
"download_subject"
private
const
val
SUBJECT_KEY
=
"download_subject"
private
const
val
REQUEST_CODE
=
1
private
val
progressBroadcast
=
MutableLiveData
<
Pair
<
Float
,
Subject
>?>()
private
val
progressBroadcast
=
MutableLiveData
<
Pair
<
Float
,
Subject
>?>()
...
@@ -233,13 +182,13 @@ class DownloadService : BaseService() {
...
@@ -233,13 +182,13 @@ class DownloadService : BaseService() {
context
.
intent
<
DownloadService
>().
putExtra
(
SUBJECT_KEY
,
subject
)
context
.
intent
<
DownloadService
>().
putExtra
(
SUBJECT_KEY
,
subject
)
@SuppressLint
(
"InlinedApi"
)
@SuppressLint
(
"InlinedApi"
)
fun
pendingIntent
(
context
:
Context
,
subject
:
Subject
):
PendingIntent
{
fun
getPendingIntent
(
context
:
Context
,
subject
:
Subject
):
PendingIntent
{
val
flag
=
FLAG_IMMUTABLE
or
FLAG_UPDATE_CURRENT
or
FLAG_ONE_SHOT
val
intent
=
intent
(
context
,
subject
)
return
if
(
Build
.
VERSION
.
SDK_INT
>=
26
)
{
return
if
(
Build
.
VERSION
.
SDK_INT
>=
26
)
{
PendingIntent
.
getForegroundService
(
context
,
nextInt
(),
intent
(
context
,
subject
),
getForegroundService
(
context
,
REQUEST_CODE
,
intent
,
flag
)
PendingIntent
.
FLAG_IMMUTABLE
or
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
else
{
}
else
{
PendingIntent
.
getService
(
context
,
nextInt
(),
intent
(
context
,
subject
),
getService
(
context
,
REQUEST_CODE
,
intent
,
flag
)
PendingIntent
.
FLAG_IMMUTABLE
or
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
}
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt
View file @
6dbd8baa
package
com.topjohnwu.magisk.core.download
package
com.topjohnwu.magisk.core.download
import
android.content.Context
import
androidx.core.net.toFile
import
androidx.core.net.toFile
import
com.topjohnwu.magisk.DynAPK
import
com.topjohnwu.magisk.DynAPK
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
...
@@ -8,29 +7,14 @@ import com.topjohnwu.magisk.core.Info
...
@@ -8,29 +7,14 @@ import com.topjohnwu.magisk.core.Info
import
com.topjohnwu.magisk.core.isRunningAsStub
import
com.topjohnwu.magisk.core.isRunningAsStub
import
com.topjohnwu.magisk.core.tasks.HideAPK
import
com.topjohnwu.magisk.core.tasks.HideAPK
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import
com.topjohnwu.magisk.ktx.copyAndClose
import
com.topjohnwu.magisk.ktx.relaunchApp
import
com.topjohnwu.magisk.ktx.relaunchApp
import
com.topjohnwu.magisk.ktx.withStreams
import
com.topjohnwu.magisk.ktx.writeTo
import
com.topjohnwu.magisk.ktx.writeTo
import
java.io.File
import
java.io.File
import
java.io.InputStream
import
java.io.InputStream
import
java.io.OutputStream
import
java.io.OutputStream
private
fun
Context
.
patch
(
apk
:
File
)
{
private
class
TeeOutputStream
(
val
patched
=
File
(
apk
.
parent
,
"patched.apk"
)
HideAPK
.
patch
(
this
,
apk
,
patched
,
packageName
,
applicationInfo
.
nonLocalizedLabel
)
apk
.
delete
()
patched
.
renameTo
(
apk
)
}
private
fun
DownloadService
.
notifyHide
(
id
:
Int
)
{
update
(
id
)
{
it
.
setProgress
(
0
,
0
,
true
)
.
setContentTitle
(
getString
(
R
.
string
.
hide_app_title
))
.
setContentText
(
""
)
}
}
private
class
DupOutputStream
(
private
val
o1
:
OutputStream
,
private
val
o1
:
OutputStream
,
private
val
o2
:
OutputStream
private
val
o2
:
OutputStream
)
:
OutputStream
()
{
)
:
OutputStream
()
{
...
@@ -50,20 +34,26 @@ private class DupOutputStream(
...
@@ -50,20 +34,26 @@ private class DupOutputStream(
suspend
fun
DownloadService
.
handleAPK
(
subject
:
Subject
.
Manager
,
stream
:
InputStream
)
{
suspend
fun
DownloadService
.
handleAPK
(
subject
:
Subject
.
Manager
,
stream
:
InputStream
)
{
fun
write
(
output
:
OutputStream
)
{
fun
write
(
output
:
OutputStream
)
{
val
ext
=
subject
.
externalFile
.
outputStream
()
val
external
=
subject
.
externalFile
.
outputStream
()
val
o
=
DupOutputStream
(
ext
,
output
)
stream
.
copyAndClose
(
TeeOutputStream
(
external
,
output
))
withStreams
(
stream
,
o
)
{
src
,
out
->
src
.
copyTo
(
out
)
}
}
}
if
(
isRunningAsStub
)
{
if
(
isRunningAsStub
)
{
val
apk
=
subject
.
file
.
toFile
()
val
apk
=
subject
.
file
.
toFile
()
val
id
=
subject
.
notifyI
D
()
val
id
=
subject
.
notifyI
d
write
(
DynAPK
.
update
(
this
).
outputStream
())
write
(
DynAPK
.
update
(
this
).
outputStream
())
if
(
Info
.
stub
!!
.
version
<
subject
.
stub
.
versionCode
)
{
if
(
Info
.
stub
!!
.
version
<
subject
.
stub
.
versionCode
)
{
// Also upgrade stub
// Also upgrade stub
notifyHide
(
id
)
update
(
id
)
{
it
.
setProgress
(
0
,
0
,
true
)
.
setContentTitle
(
getString
(
R
.
string
.
hide_app_title
))
.
setContentText
(
""
)
}
service
.
fetchFile
(
subject
.
stub
.
link
).
byteStream
().
writeTo
(
apk
)
service
.
fetchFile
(
subject
.
stub
.
link
).
byteStream
().
writeTo
(
apk
)
patch
(
apk
)
val
patched
=
File
(
apk
.
parent
,
"patched.apk"
)
HideAPK
.
patch
(
this
,
apk
,
patched
,
packageName
,
applicationInfo
.
nonLocalizedLabel
)
apk
.
delete
()
patched
.
renameTo
(
apk
)
}
else
{
}
else
{
// Simply relaunch the app
// Simply relaunch the app
stopSelf
()
stopSelf
()
...
...
app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt
deleted
100644 → 0
View file @
e660fabc
package
com.topjohnwu.magisk.core.download
import
android.net.Uri
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import
com.topjohnwu.magisk.ktx.forEach
import
com.topjohnwu.magisk.ktx.withStreams
import
java.io.InputStream
import
java.util.zip.ZipEntry
import
java.util.zip.ZipInputStream
import
java.util.zip.ZipOutputStream
fun
InputStream
.
toModule
(
file
:
Uri
,
installer
:
InputStream
)
{
val
input
=
ZipInputStream
(
buffered
())
val
output
=
ZipOutputStream
(
file
.
outputStream
().
buffered
())
withStreams
(
input
,
output
)
{
zin
,
zout
->
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/"
))
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/com/"
))
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/com/google/"
))
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/com/google/android/"
))
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/com/google/android/update-binary"
))
installer
.
copyTo
(
zout
)
zout
.
putNextEntry
(
ZipEntry
(
"META-INF/com/google/android/updater-script"
))
zout
.
write
(
"#MAGISK\n"
.
toByteArray
(
charset
(
"UTF-8"
)))
var
off
=
-
1
zin
.
forEach
{
entry
->
if
(
off
<
0
)
{
off
=
entry
.
name
.
indexOf
(
'/'
)
+
1
}
val
path
=
entry
.
name
.
substring
(
off
)
if
(
path
.
isNotEmpty
()
&&
!
path
.
startsWith
(
"META-INF"
))
{
zout
.
putNextEntry
(
ZipEntry
(
path
))
if
(!
entry
.
isDirectory
)
{
zin
.
copyTo
(
zout
)
}
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
View file @
6dbd8baa
package
com.topjohnwu.magisk.core.download
package
com.topjohnwu.magisk.core.download
import
android.annotation.SuppressLint
import
android.app.PendingIntent
import
android.content.Context
import
android.content.Intent
import
android.net.Uri
import
android.net.Uri
import
android.os.Parcelable
import
android.os.Parcelable
import
androidx.core.net.toFile
import
androidx.core.net.toUri
import
androidx.core.net.toUri
import
com.topjohnwu.magisk.core.Info
import
com.topjohnwu.magisk.core.Info
import
com.topjohnwu.magisk.core.model.MagiskJson
import
com.topjohnwu.magisk.core.model.MagiskJson
...
@@ -10,22 +15,33 @@ import com.topjohnwu.magisk.core.model.module.OnlineModule
...
@@ -10,22 +15,33 @@ import com.topjohnwu.magisk.core.model.module.OnlineModule
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils
import
com.topjohnwu.magisk.core.utils.MediaStoreUtils
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.ktx.cachedFile
import
com.topjohnwu.magisk.ktx.cachedFile
import
com.topjohnwu.magisk.ui.flash.FlashFragment
import
com.topjohnwu.magisk.utils.APKInstall
import
com.topjohnwu.magisk.view.Notifications
import
kotlinx.parcelize.IgnoredOnParcel
import
kotlinx.parcelize.IgnoredOnParcel
import
kotlinx.parcelize.Parcelize
import
kotlinx.parcelize.Parcelize
private
fun
cachedFile
(
name
:
String
)
=
AppContext
.
cachedFile
(
name
).
apply
{
delete
()
}.
toUri
()
private
fun
cachedFile
(
name
:
String
)
=
AppContext
.
cachedFile
(
name
).
apply
{
delete
()
}.
toUri
()
enum
class
Action
{
Flash
,
Download
}
sealed
class
Subject
:
Parcelable
{
sealed
class
Subject
:
Parcelable
{
abstract
val
url
:
String
abstract
val
url
:
String
abstract
val
file
:
Uri
abstract
val
file
:
Uri
abstract
val
action
:
Action
abstract
val
title
:
String
abstract
val
title
:
String
abstract
val
notifyId
:
Int
abstract
fun
pendingIntent
(
context
:
Context
):
PendingIntent
@Parcelize
@Parcelize
class
Module
(
class
Module
(
val
module
:
OnlineModule
,
val
module
:
OnlineModule
,
override
val
action
:
Action
val
action
:
Action
,
override
val
notifyId
:
Int
=
Notifications
.
nextId
()
)
:
Subject
()
{
)
:
Subject
()
{
override
val
url
:
String
get
()
=
module
.
zip_url
override
val
url
:
String
get
()
=
module
.
zip_url
override
val
title
:
String
get
()
=
module
.
downloadFilename
override
val
title
:
String
get
()
=
module
.
downloadFilename
...
@@ -34,14 +50,19 @@ sealed class Subject : Parcelable {
...
@@ -34,14 +50,19 @@ sealed class Subject : Parcelable {
override
val
file
by
lazy
{
override
val
file
by
lazy
{
MediaStoreUtils
.
getFile
(
title
).
uri
MediaStoreUtils
.
getFile
(
title
).
uri
}
}
override
fun
pendingIntent
(
context
:
Context
)
=
when
(
action
)
{
Action
.
Flash
->
FlashFragment
.
installIntent
(
context
,
file
)
else
->
Intent
().
toPending
(
context
)
}
}
}
@Parcelize
@Parcelize
class
Manager
(
class
Manager
(
private
val
json
:
MagiskJson
=
Info
.
remote
.
magisk
,
private
val
json
:
MagiskJson
=
Info
.
remote
.
magisk
,
val
stub
:
StubJson
=
Info
.
remote
.
stub
val
stub
:
StubJson
=
Info
.
remote
.
stub
,
override
val
notifyId
:
Int
=
Notifications
.
nextId
()
)
:
Subject
()
{
)
:
Subject
()
{
override
val
action
get
()
=
Action
.
Download
override
val
title
:
String
get
()
=
"Magisk-${json.version}(${json.versionCode})"
override
val
title
:
String
get
()
=
"Magisk-${json.version}(${json.versionCode})"
override
val
url
:
String
get
()
=
json
.
link
override
val
url
:
String
get
()
=
json
.
link
...
@@ -51,15 +72,14 @@ sealed class Subject : Parcelable {
...
@@ -51,15 +72,14 @@ sealed class Subject : Parcelable {
}
}
val
externalFile
get
()
=
MediaStoreUtils
.
getFile
(
"$title.apk"
).
uri
val
externalFile
get
()
=
MediaStoreUtils
.
getFile
(
"$title.apk"
).
uri
}
fun
notifyID
()
=
hashCode
()
override
fun
pendingIntent
(
context
:
Context
)
=
}
APKInstall
.
installIntent
(
context
,
file
.
toFile
()).
toPending
(
context
)
}
sealed
class
Action
:
Parcelable
{
@Parcelize
object
Flash
:
Action
()
@Parcelize
@SuppressLint
(
"InlinedApi"
)
object
Download
:
Action
()
protected
fun
Intent
.
toPending
(
context
:
Context
):
PendingIntent
{
return
PendingIntent
.
getActivity
(
context
,
notifyId
,
this
,
PendingIntent
.
FLAG_IMMUTABLE
or
PendingIntent
.
FLAG_ONE_SHOT
)
}
}
}
app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt
View file @
6dbd8baa
...
@@ -5,7 +5,7 @@ import java.io.InputStream
...
@@ -5,7 +5,7 @@ import java.io.InputStream
class
ProgressInputStream
(
class
ProgressInputStream
(
base
:
InputStream
,
base
:
InputStream
,
val
progressEmitter
:
(
Long
)
->
Unit
=
{}
val
progressEmitter
:
(
Long
)
->
Unit
)
:
FilterInputStream
(
base
)
{
)
:
FilterInputStream
(
base
)
{
private
var
bytesRead
=
0L
private
var
bytesRead
=
0L
...
@@ -40,4 +40,9 @@ class ProgressInputStream(
...
@@ -40,4 +40,9 @@ class ProgressInputStream(
}
}
return
sz
return
sz
}
}
override
fun
close
()
{
super
.
close
()
progressEmitter
(
bytesRead
)
}
}
}
app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt
View file @
6dbd8baa
...
@@ -14,8 +14,8 @@ class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() {
...
@@ -14,8 +14,8 @@ class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() {
with
(
dialog
)
{
with
(
dialog
)
{
fun
download
(
install
:
Boolean
)
{
fun
download
(
install
:
Boolean
)
{
val
config
=
if
(
install
)
Action
.
Flash
else
Action
.
Download
val
action
=
if
(
install
)
Action
.
Flash
else
Action
.
Download
val
subject
=
Subject
.
Module
(
item
,
config
)
val
subject
=
Subject
.
Module
(
item
,
action
)
DownloadService
.
start
(
context
,
subject
)
DownloadService
.
start
(
context
,
subject
)
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt
View file @
6dbd8baa
...
@@ -19,9 +19,6 @@ inline fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
...
@@ -19,9 +19,6 @@ inline fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
}
}
}
}
fun
InputStream
.
writeTo
(
file
:
File
)
=
withStreams
(
this
,
file
.
outputStream
())
{
reader
,
writer
->
reader
.
copyTo
(
writer
)
}
inline
fun
<
In
:
InputStream
,
Out
:
OutputStream
>
withStreams
(
inline
fun
<
In
:
InputStream
,
Out
:
OutputStream
>
withStreams
(
inStream
:
In
,
inStream
:
In
,
outStream
:
Out
,
outStream
:
Out
,
...
@@ -34,18 +31,19 @@ inline fun <In : InputStream, Out : OutputStream> withStreams(
...
@@ -34,18 +31,19 @@ inline fun <In : InputStream, Out : OutputStream> withStreams(
}
}
}
}
fun
<
T
>
MutableList
<
T
>.
update
(
newList
:
List
<
T
>)
{
fun
InputStream
.
copyAndClose
(
out
:
OutputStream
)
=
withStreams
(
this
,
out
)
{
i
,
o
->
i
.
copyTo
(
o
)
}
clear
()
addAll
(
newList
)
fun
InputStream
.
writeTo
(
file
:
File
)
=
copyAndClose
(
file
.
outputStream
())
}
operator
fun
<
E
>
SparseArrayCompat
<
E
>.
set
(
key
:
Int
,
value
:
E
)
{
operator
fun
<
E
>
SparseArrayCompat
<
E
>.
set
(
key
:
Int
,
value
:
E
)
{
put
(
key
,
value
)
put
(
key
,
value
)
}
}
fun
<
T
>
MutableList
<
T
>.
synchronized
()
=
Collections
.
synchronizedList
(
this
)
fun
<
T
>
MutableList
<
T
>.
synchronized
():
MutableList
<
T
>
=
Collections
.
synchronizedList
(
this
)
fun
<
T
>
MutableSet
<
T
>.
synchronized
()
=
Collections
.
synchronizedSet
(
this
)
fun
<
K
,
V
>
MutableMap
<
K
,
V
>.
synchronized
()
=
Collections
.
synchronizedMap
(
this
)
fun
<
T
>
MutableSet
<
T
>.
synchronized
():
MutableSet
<
T
>
=
Collections
.
synchronizedSet
(
this
)
fun
<
K
,
V
>
MutableMap
<
K
,
V
>.
synchronized
():
MutableMap
<
K
,
V
>
=
Collections
.
synchronizedMap
(
this
)
fun
SimpleDateFormat
.
parseOrNull
(
date
:
String
)
=
fun
SimpleDateFormat
.
parseOrNull
(
date
:
String
)
=
runCatching
{
parse
(
date
)
}.
onFailure
{
Timber
.
e
(
it
)
}.
getOrNull
()
runCatching
{
parse
(
date
)
}.
onFailure
{
Timber
.
e
(
it
)
}.
getOrNull
()
...
...
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
View file @
6dbd8baa
...
@@ -111,16 +111,14 @@ class FlashFragment : BaseUIFragment<FlashViewModel, FragmentFlashMd2Binding>()
...
@@ -111,16 +111,14 @@ class FlashFragment : BaseUIFragment<FlashViewModel, FragmentFlashMd2Binding>()
/* Installing is understood as flashing modules / zips */
/* Installing is understood as flashing modules / zips */
fun
installIntent
(
context
:
Context
,
file
:
Uri
,
id
:
Int
=
-
1
)
=
FlashFragmentArgs
(
fun
installIntent
(
context
:
Context
,
file
:
Uri
)
=
FlashFragmentArgs
(
action
=
Const
.
Value
.
FLASH_ZIP
,
action
=
Const
.
Value
.
FLASH_ZIP
,
additionalData
=
file
,
additionalData
=
file
,
dismissId
=
id
).
let
{
createIntent
(
context
,
it
)
}
).
let
{
createIntent
(
context
,
it
)
}
fun
install
(
file
:
Uri
,
id
:
Int
)
=
MainDirections
.
actionFlashFragment
(
fun
install
(
file
:
Uri
)
=
MainDirections
.
actionFlashFragment
(
action
=
Const
.
Value
.
FLASH_ZIP
,
action
=
Const
.
Value
.
FLASH_ZIP
,
additionalData
=
file
,
additionalData
=
file
,
dismissId
=
id
)
)
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
View file @
6dbd8baa
...
@@ -20,7 +20,6 @@ import com.topjohnwu.magisk.databinding.itemBindingOf
...
@@ -20,7 +20,6 @@ import com.topjohnwu.magisk.databinding.itemBindingOf
import
com.topjohnwu.magisk.databinding.set
import
com.topjohnwu.magisk.databinding.set
import
com.topjohnwu.magisk.events.SnackbarEvent
import
com.topjohnwu.magisk.events.SnackbarEvent
import
com.topjohnwu.magisk.ktx.*
import
com.topjohnwu.magisk.ktx.*
import
com.topjohnwu.magisk.view.Notifications
import
com.topjohnwu.superuser.CallbackList
import
com.topjohnwu.superuser.CallbackList
import
com.topjohnwu.superuser.Shell
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
...
@@ -50,9 +49,7 @@ class FlashViewModel : BaseViewModel() {
...
@@ -50,9 +49,7 @@ class FlashViewModel : BaseViewModel() {
}
}
fun
startFlashing
()
{
fun
startFlashing
()
{
val
(
action
,
uri
,
id
)
=
args
val
(
action
,
uri
)
=
args
if
(
id
!=
-
1
)
Notifications
.
mgr
.
cancel
(
id
)
viewModelScope
.
launch
{
viewModelScope
.
launch
{
val
result
=
when
(
action
)
{
val
result
=
when
(
action
)
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
View file @
6dbd8baa
...
@@ -70,4 +70,8 @@ class HomeFragment : BaseUIFragment<HomeViewModel, FragmentHomeMd2Binding>() {
...
@@ -70,4 +70,8 @@ class HomeFragment : BaseUIFragment<HomeViewModel, FragmentHomeMd2Binding>() {
return
true
return
true
}
}
override
fun
onResume
()
{
super
.
onResume
()
viewModel
.
stateManagerProgress
=
0
}
}
}
app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
View file @
6dbd8baa
...
@@ -8,19 +8,22 @@ import android.os.Build.VERSION.SDK_INT
...
@@ -8,19 +8,22 @@ import android.os.Build.VERSION.SDK_INT
import
androidx.core.content.getSystemService
import
androidx.core.content.getSystemService
import
androidx.core.graphics.drawable.toIcon
import
androidx.core.graphics.drawable.toIcon
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.core.Const
import
com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
import
com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
import
com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL
import
com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL
import
com.topjohnwu.magisk.core.download.DownloadService
import
com.topjohnwu.magisk.core.download.DownloadService
import
com.topjohnwu.magisk.core.download.Subject
import
com.topjohnwu.magisk.core.download.Subject
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.ktx.getBitmap
import
com.topjohnwu.magisk.ktx.getBitmap
import
java.util.concurrent.atomic.AtomicInteger
@Suppress
(
"DEPRECATION"
)
@Suppress
(
"DEPRECATION"
)
object
Notifications
{
object
Notifications
{
val
mgr
by
lazy
{
AppContext
.
getSystemService
<
NotificationManager
>()
!!
}
val
mgr
by
lazy
{
AppContext
.
getSystemService
<
NotificationManager
>()
!!
}
private
const
val
APK_UPDATE_NOTIFICATION_ID
=
5
private
val
nextId
=
AtomicInteger
(
APK_UPDATE_NOTIFICATION_ID
)
fun
setup
(
context
:
Context
)
{
fun
setup
(
context
:
Context
)
{
if
(
SDK_INT
>=
26
)
{
if
(
SDK_INT
>=
26
)
{
var
channel
=
NotificationChannel
(
UPDATE_NOTIFICATION_CHANNEL
,
var
channel
=
NotificationChannel
(
UPDATE_NOTIFICATION_CHANNEL
,
...
@@ -46,7 +49,7 @@ object Notifications {
...
@@ -46,7 +49,7 @@ object Notifications {
}
}
fun
managerUpdate
(
context
:
Context
)
{
fun
managerUpdate
(
context
:
Context
)
{
val
intent
=
DownloadService
.
p
endingIntent
(
context
,
Subject
.
Manager
())
val
intent
=
DownloadService
.
getP
endingIntent
(
context
,
Subject
.
Manager
())
val
builder
=
updateBuilder
(
context
)
val
builder
=
updateBuilder
(
context
)
.
setContentTitle
(
context
.
getString
(
R
.
string
.
magisk_update_title
))
.
setContentTitle
(
context
.
getString
(
R
.
string
.
magisk_update_title
))
...
@@ -54,7 +57,7 @@ object Notifications {
...
@@ -54,7 +57,7 @@ object Notifications {
.
setAutoCancel
(
true
)
.
setAutoCancel
(
true
)
.
setContentIntent
(
intent
)
.
setContentIntent
(
intent
)
mgr
.
notify
(
Const
.
ID
.
APK_UPDATE_NOTIFICATION_ID
,
builder
.
build
())
mgr
.
notify
(
APK_UPDATE_NOTIFICATION_ID
,
builder
.
build
())
}
}
fun
progress
(
context
:
Context
,
title
:
CharSequence
):
Notification
.
Builder
{
fun
progress
(
context
:
Context
,
title
:
CharSequence
):
Notification
.
Builder
{
...
@@ -69,4 +72,6 @@ object Notifications {
...
@@ -69,4 +72,6 @@ object Notifications {
.
setOngoing
(
true
)
.
setOngoing
(
true
)
return
builder
return
builder
}
}
fun
nextId
()
=
nextId
.
incrementAndGet
()
}
}
app/src/main/res/navigation/main.xml
View file @
6dbd8baa
...
@@ -51,11 +51,6 @@
...
@@ -51,11 +51,6 @@
app:argType=
"android.net.Uri"
app:argType=
"android.net.Uri"
app:nullable=
"true"
/>
app:nullable=
"true"
/>
<argument
android:name=
"dismiss_id"
android:defaultValue=
"-1"
app:argType=
"integer"
/>
</fragment>
</fragment>
<fragment
<fragment
...
...
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