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
6df7006b
Commit
6df7006b
authored
Apr 22, 2019
by
Viktor De Pasquale
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleaned up unnecessary classes
parent
aceb3ee8
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
0 additions
and
1481 deletions
+0
-1481
ApplicationAdapter.java
...m/topjohnwu/magisk/model/adapters/ApplicationAdapter.java
+0
-426
ModulesAdapter.java
...a/com/topjohnwu/magisk/model/adapters/ModulesAdapter.java
+0
-126
PolicyAdapter.java
...va/com/topjohnwu/magisk/model/adapters/PolicyAdapter.java
+0
-168
ReposAdapter.java
...ava/com/topjohnwu/magisk/model/adapters/ReposAdapter.java
+0
-246
SectionedAdapter.java
...com/topjohnwu/magisk/model/adapters/SectionedAdapter.java
+0
-96
SuLogAdapter.java
...ava/com/topjohnwu/magisk/model/adapters/SuLogAdapter.java
+0
-143
TabFragmentAdapter.java
...m/topjohnwu/magisk/model/adapters/TabFragmentAdapter.java
+0
-41
MagiskLogFragment.java
...n/java/com/topjohnwu/magisk/ui/log/MagiskLogFragment.java
+0
-156
SuLogFragment.java
.../main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java
+0
-79
No files found.
app/src/main/java/com/topjohnwu/magisk/model/adapters/ApplicationAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.content.Context
;
import
android.content.pm.ApplicationInfo
;
import
android.content.pm.ComponentInfo
;
import
android.content.pm.PackageInfo
;
import
android.content.pm.PackageManager
;
import
android.os.AsyncTask
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.CheckBox
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.buildware.widget.indeterm.IndeterminateCheckBox
;
import
com.topjohnwu.magisk.App
;
import
com.topjohnwu.magisk.Config
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Event
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.view.ArrowExpandable
;
import
com.topjohnwu.magisk.view.Expandable
;
import
com.topjohnwu.superuser.Shell
;
import
com.topjohnwu.superuser.internal.UiThreadHandler
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Set
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.WorkerThread
;
import
androidx.collection.ArraySet
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
import
java9.util.Comparators
;
import
java9.util.Lists
;
import
java9.util.Objects
;
import
java9.util.Sets
;
import
java9.util.stream.Collectors
;
import
java9.util.stream.Stream
;
import
java9.util.stream.StreamSupport
;
public
class
ApplicationAdapter
extends
SectionedAdapter
<
ApplicationAdapter
.
AppViewHolder
,
ApplicationAdapter
.
ProcessViewHolder
>
{
private
static
final
String
SAFETYNET_PROCESS
=
"com.google.android.gms.unstable"
;
private
static
final
String
GMS_PACKAGE
=
"com.google.android.gms"
;
private
static
boolean
old_hide
=
false
;
/* A list of apps that should not be shown as hide-able */
private
static
final
List
<
String
>
HIDE_BLACKLIST
=
Lists
.
of
(
App
.
self
.
getPackageName
(),
"android"
,
"com.android.chrome"
,
"com.chrome.beta"
,
"com.chrome.dev"
,
"com.chrome.canary"
,
"com.android.webview"
,
"com.google.android.webview"
);
private
static
final
List
<
String
>
DEFAULT_HIDELIST
=
Lists
.
of
(
SAFETYNET_PROCESS
);
private
static
int
BOTTOM_MARGIN
=
-
1
;
private
List
<
HideAppInfo
>
fullList
,
showList
;
private
List
<
HideTarget
>
hideList
;
private
PackageManager
pm
;
private
boolean
showSystem
;
public
ApplicationAdapter
(
Context
context
)
{
fullList
=
showList
=
Collections
.
emptyList
();
hideList
=
Collections
.
emptyList
();
pm
=
context
.
getPackageManager
();
showSystem
=
Config
.
get
(
Config
.
Key
.
SHOW_SYSTEM_APP
);
AsyncTask
.
SERIAL_EXECUTOR
.
execute
(
this
::
loadApps
);
}
private
static
ViewGroup
.
MarginLayoutParams
getMargins
(
RecyclerView
.
ViewHolder
vh
)
{
return
(
ViewGroup
.
MarginLayoutParams
)
vh
.
itemView
.
getLayoutParams
();
}
@Override
public
int
getSectionCount
()
{
return
showList
.
size
();
}
@Override
public
int
getItemCount
(
int
section
)
{
HideAppInfo
app
=
showList
.
get
(
section
);
return
app
.
expanded
?
app
.
processList
.
size
()
:
0
;
}
@Override
public
AppViewHolder
onCreateSectionViewHolder
(
ViewGroup
parent
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_hide_app
,
parent
,
false
);
AppViewHolder
vh
=
new
AppViewHolder
(
v
);
if
(
BOTTOM_MARGIN
<
0
)
BOTTOM_MARGIN
=
getMargins
(
vh
).
bottomMargin
;
return
vh
;
}
@Override
public
ProcessViewHolder
onCreateItemViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_hide_process
,
parent
,
false
);
return
new
ProcessViewHolder
(
v
);
}
@Override
public
void
onBindSectionViewHolder
(
AppViewHolder
holder
,
int
section
)
{
HideAppInfo
app
=
showList
.
get
(
section
);
holder
.
app_name
.
setText
(
app
.
name
);
holder
.
app_icon
.
setImageDrawable
(
app
.
info
.
loadIcon
(
pm
));
holder
.
package_name
.
setText
(
app
.
info
.
packageName
);
holder
.
checkBox
.
setOnStateChangedListener
(
null
);
holder
.
checkBox
.
setState
(
app
.
getState
());
holder
.
ex
.
setExpanded
(
app
.
expanded
);
int
index
=
getItemPosition
(
section
,
0
);
holder
.
checkBox
.
setOnStateChangedListener
((
IndeterminateCheckBox
box
,
@Nullable
Boolean
status
)
->
{
if
(
status
!=
null
)
{
setHide
(
status
,
app
);
if
(
app
.
expanded
)
notifyItemRangeChanged
(
index
,
app
.
processList
.
size
());
}
});
if
(
app
.
processList
.
size
()
>
1
)
{
holder
.
arrow
.
setVisibility
(
View
.
VISIBLE
);
holder
.
trigger
.
setOnClickListener
((
v
)
->
{
if
(
app
.
expanded
)
{
app
.
expanded
=
false
;
notifyItemRangeRemoved
(
index
,
app
.
processList
.
size
());
holder
.
ex
.
collapse
();
}
else
{
app
.
expanded
=
true
;
notifyItemRangeInserted
(
index
,
app
.
processList
.
size
());
holder
.
ex
.
expand
();
}
});
}
else
{
holder
.
arrow
.
setVisibility
(
View
.
GONE
);
holder
.
trigger
.
setOnClickListener
(
null
);
}
}
@Override
public
void
onBindItemViewHolder
(
ProcessViewHolder
holder
,
int
section
,
int
position
)
{
HideAppInfo
app
=
showList
.
get
(
section
);
HideProcessInfo
target
=
app
.
processList
.
get
(
position
);
holder
.
process
.
setText
(
target
.
name
);
holder
.
checkbox
.
setOnCheckedChangeListener
(
null
);
holder
.
checkbox
.
setChecked
(
target
.
hidden
);
holder
.
checkbox
.
setOnCheckedChangeListener
((
v
,
checked
)
->
{
setHide
(
checked
,
app
,
target
);
notifyItemChanged
(
getSectionPosition
(
section
));
});
getMargins
(
holder
).
bottomMargin
=
position
==
app
.
processList
.
size
()
-
1
?
BOTTOM_MARGIN
:
0
;
}
public
void
filter
(
String
constraint
)
{
AsyncTask
.
SERIAL_EXECUTOR
.
execute
(()
->
{
Stream
<
HideAppInfo
>
s
=
StreamSupport
.
stream
(
fullList
)
.
filter
(
this
::
systemFilter
)
.
filter
(
t
->
nameFilter
(
t
,
constraint
));
UiThreadHandler
.
run
(()
->
{
showList
=
s
.
collect
(
Collectors
.
toList
());
notifyDataSetChanged
();
});
});
}
public
void
setShowSystem
(
boolean
b
)
{
showSystem
=
b
;
}
public
void
refresh
()
{
AsyncTask
.
SERIAL_EXECUTOR
.
execute
(
this
::
loadApps
);
}
private
void
setHide
(
boolean
add
,
HideAppInfo
app
)
{
if
(
add
)
{
StreamSupport
.
stream
(
app
.
processList
).
forEach
(
p
->
setHide
(
true
,
app
,
p
));
}
else
{
if
(
StreamSupport
.
stream
(
app
.
processList
)
.
anyMatch
(
p
->
p
.
name
.
equals
(
SAFETYNET_PROCESS
)))
{
StreamSupport
.
stream
(
app
.
processList
).
forEach
(
p
->
setHide
(
false
,
app
,
p
));
}
else
{
// Quick removal
Shell
.
su
(
"magiskhide --rm "
+
app
.
info
.
packageName
).
submit
();
StreamSupport
.
stream
(
app
.
processList
).
forEach
(
p
->
p
.
hidden
=
false
);
}
}
}
private
void
setHide
(
boolean
add
,
HideAppInfo
app
,
HideProcessInfo
process
)
{
// Don't remove SafetyNet
if
(!
add
&&
DEFAULT_HIDELIST
.
contains
(
process
.
name
))
return
;
Shell
.
su
(
Utils
.
fmt
(
"magiskhide --%s %s %s"
,
add
?
"add"
:
"rm"
,
app
.
info
.
packageName
,
process
.
name
)).
submit
();
process
.
hidden
=
add
;
}
private
void
addProcesses
(
Set
<
String
>
set
,
ComponentInfo
[]
infos
)
{
if
(
infos
!=
null
)
for
(
ComponentInfo
info
:
infos
)
set
.
add
(
info
.
processName
);
}
private
PackageInfo
getPackageInfo
(
String
pkg
)
{
// Try super hard to get as much info as possible
try
{
return
pm
.
getPackageInfo
(
pkg
,
PackageManager
.
GET_ACTIVITIES
|
PackageManager
.
GET_SERVICES
|
PackageManager
.
GET_RECEIVERS
|
PackageManager
.
GET_PROVIDERS
);
}
catch
(
Exception
e1
)
{
try
{
PackageInfo
info
=
pm
.
getPackageInfo
(
pkg
,
PackageManager
.
GET_ACTIVITIES
);
info
.
services
=
pm
.
getPackageInfo
(
pkg
,
PackageManager
.
GET_SERVICES
).
services
;
info
.
receivers
=
pm
.
getPackageInfo
(
pkg
,
PackageManager
.
GET_RECEIVERS
).
receivers
;
info
.
providers
=
pm
.
getPackageInfo
(
pkg
,
PackageManager
.
GET_PROVIDERS
).
providers
;
return
info
;
}
catch
(
Exception
e2
)
{
return
null
;
}
}
}
@WorkerThread
private
void
loadApps
()
{
hideList
=
StreamSupport
.
stream
(
Shell
.
su
(
"magiskhide --ls"
).
exec
().
getOut
())
.
map
(
HideTarget:
:
new
)
.
collect
(
Collectors
.
toList
());
fullList
=
StreamSupport
.
stream
(
pm
.
getInstalledApplications
(
0
))
.
filter
(
info
->
!
HIDE_BLACKLIST
.
contains
(
info
.
packageName
)
&&
info
.
enabled
)
.
map
(
info
->
{
if
(
old_hide
)
{
return
new
HideAppInfo
(
info
,
Sets
.
of
(
info
.
packageName
));
}
else
{
Set
<
String
>
set
=
new
ArraySet
<>();
PackageInfo
pkg
=
getPackageInfo
(
info
.
packageName
);
if
(
pkg
!=
null
)
{
addProcesses
(
set
,
pkg
.
activities
);
addProcesses
(
set
,
pkg
.
services
);
addProcesses
(
set
,
pkg
.
receivers
);
addProcesses
(
set
,
pkg
.
providers
);
}
if
(
set
.
isEmpty
())
return
null
;
return
new
HideAppInfo
(
info
,
set
);
}
}).
filter
(
Objects:
:
nonNull
).
sorted
()
.
collect
(
Collectors
.
toList
());
Event
.
trigger
(
false
,
Event
.
MAGISK_HIDE_DONE
);
}
// True if not system app or user already hidden it
private
boolean
systemFilter
(
HideAppInfo
target
)
{
return
showSystem
||
target
.
haveHidden
()
||
(
target
.
info
.
flags
&
ApplicationInfo
.
FLAG_SYSTEM
)
==
0
;
}
private
boolean
contains
(
String
s
,
String
filter
)
{
return
s
.
toLowerCase
().
contains
(
filter
);
}
private
boolean
nameFilter
(
HideAppInfo
target
,
String
filter
)
{
if
(
filter
==
null
||
filter
.
isEmpty
())
return
true
;
filter
=
filter
.
toLowerCase
();
if
(
contains
(
target
.
name
,
filter
))
return
true
;
for
(
HideProcessInfo
p
:
target
.
processList
)
{
if
(
contains
(
p
.
name
,
filter
))
return
true
;
}
return
contains
(
target
.
info
.
packageName
,
filter
);
}
class
HideAppInfo
implements
Comparable
<
HideAppInfo
>
{
String
name
;
ApplicationInfo
info
;
List
<
HideProcessInfo
>
processList
;
boolean
expanded
;
IndeterminateCheckBox
.
OnStateChangedListener
listener
;
HideAppInfo
(
ApplicationInfo
appInfo
,
Set
<
String
>
set
)
{
info
=
appInfo
;
name
=
Utils
.
getAppLabel
(
info
,
pm
);
expanded
=
false
;
processList
=
StreamSupport
.
stream
(
set
)
.
map
(
process
->
new
HideProcessInfo
(
info
.
packageName
,
process
))
.
sorted
().
collect
(
Collectors
.
toList
());
listener
=
(
IndeterminateCheckBox
box
,
@Nullable
Boolean
status
)
->
{
if
(
status
!=
null
)
{
for
(
HideProcessInfo
p
:
processList
)
{
String
cmd
=
Utils
.
fmt
(
"magiskhide --%s %s %s"
,
status
?
"add"
:
"rm"
,
info
.
packageName
,
p
.
name
);
Shell
.
su
(
cmd
).
submit
();
p
.
hidden
=
status
;
}
}
};
}
@Override
public
int
compareTo
(
HideAppInfo
o
)
{
Comparator
<
HideAppInfo
>
c
;
c
=
Comparators
.
comparing
(
HideAppInfo:
:
haveHidden
);
c
=
Comparators
.
reversed
(
c
);
c
=
Comparators
.
thenComparing
(
c
,
t
->
t
.
name
,
String:
:
compareToIgnoreCase
);
c
=
Comparators
.
thenComparing
(
c
,
t
->
t
.
info
.
packageName
);
return
c
.
compare
(
this
,
o
);
}
Boolean
getState
()
{
boolean
all
=
true
;
boolean
hidden
=
false
;
for
(
HideProcessInfo
p
:
processList
)
{
if
(!
p
.
hidden
)
all
=
false
;
else
hidden
=
true
;
}
if
(
all
)
return
true
;
return
hidden
?
null
:
false
;
}
boolean
haveHidden
()
{
Boolean
c
=
getState
();
return
c
==
null
?
true
:
c
;
}
}
class
HideProcessInfo
implements
Comparable
<
HideProcessInfo
>
{
String
name
;
boolean
hidden
;
HideProcessInfo
(
String
pkg
,
String
process
)
{
this
.
name
=
process
;
for
(
HideTarget
t
:
hideList
)
{
if
(
t
.
pkg
.
equals
(
pkg
)
&&
t
.
process
.
equals
(
process
))
{
hidden
=
true
;
break
;
}
}
}
@Override
public
int
compareTo
(
HideProcessInfo
o
)
{
Comparator
<
HideProcessInfo
>
c
;
c
=
Comparators
.
comparing
((
HideProcessInfo
t
)
->
t
.
hidden
);
c
=
Comparators
.
reversed
(
c
);
c
=
Comparators
.
thenComparing
(
c
,
t
->
t
.
name
);
return
c
.
compare
(
this
,
o
);
}
}
class
HideTarget
{
String
pkg
;
String
process
;
HideTarget
(
String
line
)
{
String
[]
split
=
line
.
split
(
"\\|"
,
2
);
pkg
=
split
[
0
];
if
(
split
.
length
==
2
)
{
process
=
split
[
1
];
}
else
{
// Backwards compatibility
old_hide
=
true
;
process
=
pkg
;
}
}
}
class
AppViewHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
app_icon
)
ImageView
app_icon
;
@BindView
(
R
.
id
.
app_name
)
TextView
app_name
;
@BindView
(
R
.
id
.
package_name
)
TextView
package_name
;
@BindView
(
R
.
id
.
checkbox
)
IndeterminateCheckBox
checkBox
;
@BindView
(
R
.
id
.
trigger
)
View
trigger
;
@BindView
(
R
.
id
.
arrow
)
ImageView
arrow
;
Expandable
ex
;
AppViewHolder
(
@NonNull
View
itemView
)
{
super
(
itemView
);
new
ApplicationAdapter$AppViewHolder_ViewBinding
(
this
,
itemView
);
ex
=
new
ArrowExpandable
(
new
Expandable
()
{
@Override
protected
void
onExpand
()
{
getMargins
(
AppViewHolder
.
this
).
bottomMargin
=
0
;
}
@Override
protected
void
onCollapse
()
{
getMargins
(
AppViewHolder
.
this
).
bottomMargin
=
BOTTOM_MARGIN
;
}
},
arrow
);
}
}
class
ProcessViewHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
process
)
TextView
process
;
@BindView
(
R
.
id
.
checkbox
)
CheckBox
checkbox
;
ProcessViewHolder
(
@NonNull
View
itemView
)
{
super
(
itemView
);
new
ApplicationAdapter$ProcessViewHolder_ViewBinding
(
this
,
itemView
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/ModulesAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.content.Context
;
import
android.text.TextUtils
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.CheckBox
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.google.android.material.snackbar.Snackbar
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.entity.Module
;
import
com.topjohnwu.magisk.view.SnackbarMaker
;
import
com.topjohnwu.superuser.Shell
;
import
java.util.List
;
import
androidx.annotation.NonNull
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
public
class
ModulesAdapter
extends
RecyclerView
.
Adapter
<
ModulesAdapter
.
ViewHolder
>
{
private
final
List
<
Module
>
mList
;
public
ModulesAdapter
(
List
<
Module
>
list
)
{
mList
=
list
;
}
@NonNull
@Override
public
ViewHolder
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
view
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_module
,
parent
,
false
);
return
new
ViewHolder
(
view
);
}
@Override
public
void
onBindViewHolder
(
final
ViewHolder
holder
,
int
position
)
{
Context
context
=
holder
.
itemView
.
getContext
();
final
Module
module
=
mList
.
get
(
position
);
String
version
=
module
.
getVersion
();
String
author
=
module
.
getAuthor
();
String
description
=
module
.
getDescription
();
String
noInfo
=
context
.
getString
(
R
.
string
.
no_info_provided
);
holder
.
title
.
setText
(
module
.
getName
());
holder
.
versionName
.
setText
(
TextUtils
.
isEmpty
(
version
)
?
noInfo
:
version
);
holder
.
author
.
setText
(
TextUtils
.
isEmpty
(
author
)
?
noInfo
:
context
.
getString
(
R
.
string
.
author
,
author
));
holder
.
description
.
setText
(
TextUtils
.
isEmpty
(
description
)
?
noInfo
:
description
);
holder
.
checkBox
.
setOnCheckedChangeListener
(
null
);
holder
.
checkBox
.
setChecked
(
module
.
isEnabled
());
holder
.
checkBox
.
setOnCheckedChangeListener
((
v
,
isChecked
)
->
{
int
snack
;
if
(
isChecked
)
{
module
.
removeDisableFile
();
snack
=
R
.
string
.
disable_file_removed
;
}
else
{
module
.
createDisableFile
();
snack
=
R
.
string
.
disable_file_created
;
}
SnackbarMaker
.
make
(
holder
.
itemView
,
snack
,
Snackbar
.
LENGTH_SHORT
).
show
();
});
holder
.
delete
.
setOnClickListener
(
v
->
{
boolean
removed
=
module
.
willBeRemoved
();
int
snack
;
if
(
removed
)
{
module
.
deleteRemoveFile
();
snack
=
R
.
string
.
remove_file_deleted
;
}
else
{
module
.
createRemoveFile
();
snack
=
R
.
string
.
remove_file_created
;
}
SnackbarMaker
.
make
(
holder
.
itemView
,
snack
,
Snackbar
.
LENGTH_SHORT
).
show
();
updateDeleteButton
(
holder
,
module
);
});
if
(
module
.
isUpdated
())
{
holder
.
notice
.
setVisibility
(
View
.
VISIBLE
);
holder
.
notice
.
setText
(
R
.
string
.
update_file_created
);
holder
.
delete
.
setEnabled
(
false
);
}
else
{
updateDeleteButton
(
holder
,
module
);
}
}
private
void
updateDeleteButton
(
ViewHolder
holder
,
Module
module
)
{
holder
.
notice
.
setVisibility
(
module
.
willBeRemoved
()
?
View
.
VISIBLE
:
View
.
GONE
);
if
(
module
.
willBeRemoved
())
{
holder
.
delete
.
setImageResource
(
R
.
drawable
.
ic_undelete
);
}
else
{
holder
.
delete
.
setImageResource
(
R
.
drawable
.
ic_delete
);
}
}
@Override
public
int
getItemCount
()
{
return
mList
.
size
();
}
static
class
ViewHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
title
)
TextView
title
;
@BindView
(
R
.
id
.
version_name
)
TextView
versionName
;
@BindView
(
R
.
id
.
description
)
TextView
description
;
@BindView
(
R
.
id
.
notice
)
TextView
notice
;
@BindView
(
R
.
id
.
checkbox
)
CheckBox
checkBox
;
@BindView
(
R
.
id
.
author
)
TextView
author
;
@BindView
(
R
.
id
.
delete
)
ImageView
delete
;
ViewHolder
(
View
itemView
)
{
super
(
itemView
);
new
ModulesAdapter$ViewHolder_ViewBinding
(
this
,
itemView
);
if
(!
Shell
.
rootAccess
())
{
checkBox
.
setEnabled
(
false
);
delete
.
setEnabled
(
false
);
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/PolicyAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.app.Activity
;
import
android.content.DialogInterface
;
import
android.content.pm.PackageManager
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.google.android.material.snackbar.Snackbar
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.data.database.MagiskDB
;
import
com.topjohnwu.magisk.model.entity.Policy
;
import
com.topjohnwu.magisk.utils.FingerprintHelper
;
import
com.topjohnwu.magisk.view.ArrowExpandable
;
import
com.topjohnwu.magisk.view.Expandable
;
import
com.topjohnwu.magisk.view.ExpandableViewHolder
;
import
com.topjohnwu.magisk.view.SnackbarMaker
;
import
com.topjohnwu.magisk.view.dialogs.CustomAlertDialog
;
import
com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
;
import
java.util.List
;
import
androidx.annotation.NonNull
;
import
androidx.appcompat.widget.SwitchCompat
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
public
class
PolicyAdapter
extends
RecyclerView
.
Adapter
<
PolicyAdapter
.
ViewHolder
>
{
private
final
List
<
Policy
>
policyList
;
private
final
MagiskDB
dbHelper
;
private
final
PackageManager
pm
;
private
final
boolean
[]
expandList
;
public
PolicyAdapter
(
List
<
Policy
>
list
,
MagiskDB
db
,
PackageManager
pm
)
{
policyList
=
list
;
expandList
=
new
boolean
[
policyList
.
size
()];
dbHelper
=
db
;
this
.
pm
=
pm
;
}
@NonNull
@Override
public
ViewHolder
onCreateViewHolder
(
@NonNull
ViewGroup
parent
,
int
viewType
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_policy
,
parent
,
false
);
return
new
ViewHolder
(
v
);
}
@Override
public
void
onBindViewHolder
(
@NonNull
ViewHolder
holder
,
int
position
)
{
Policy
policy
=
policyList
.
get
(
position
);
holder
.
settings
.
setExpanded
(
expandList
[
position
]);
holder
.
trigger
.
setOnClickListener
(
view
->
{
if
(
holder
.
settings
.
isExpanded
())
{
holder
.
settings
.
collapse
();
expandList
[
position
]
=
false
;
}
else
{
holder
.
settings
.
expand
();
expandList
[
position
]
=
true
;
}
});
holder
.
appName
.
setText
(
policy
.
appName
);
holder
.
packageName
.
setText
(
policy
.
packageName
);
holder
.
appIcon
.
setImageDrawable
(
policy
.
info
.
loadIcon
(
pm
));
holder
.
notificationSwitch
.
setOnCheckedChangeListener
(
null
);
holder
.
loggingSwitch
.
setOnCheckedChangeListener
(
null
);
holder
.
masterSwitch
.
setChecked
(
policy
.
policy
==
Policy
.
ALLOW
);
holder
.
notificationSwitch
.
setChecked
(
policy
.
notification
);
holder
.
loggingSwitch
.
setChecked
(
policy
.
logging
);
holder
.
masterSwitch
.
setOnClickListener
(
v
->
{
boolean
isChecked
=
holder
.
masterSwitch
.
isChecked
();
Runnable
r
=
()
->
{
if
(
isChecked
?
policy
.
policy
==
Policy
.
DENY
:
policy
.
policy
==
Policy
.
ALLOW
)
{
policy
.
policy
=
isChecked
?
Policy
.
ALLOW
:
Policy
.
DENY
;
String
message
=
v
.
getContext
().
getString
(
isChecked
?
R
.
string
.
su_snack_grant
:
R
.
string
.
su_snack_deny
,
policy
.
appName
);
SnackbarMaker
.
make
(
holder
.
itemView
,
message
,
Snackbar
.
LENGTH_SHORT
).
show
();
dbHelper
.
updatePolicy
(
policy
);
}
};
if
(
FingerprintHelper
.
useFingerprint
())
{
holder
.
masterSwitch
.
setChecked
(!
isChecked
);
new
FingerprintAuthDialog
((
Activity
)
v
.
getContext
(),
()
->
{
holder
.
masterSwitch
.
setChecked
(
isChecked
);
r
.
run
();
}).
show
();
}
else
{
r
.
run
();
}
});
holder
.
notificationSwitch
.
setOnCheckedChangeListener
((
v
,
isChecked
)
->
{
if
(
isChecked
!=
policy
.
notification
)
{
policy
.
notification
=
isChecked
;
String
message
=
v
.
getContext
().
getString
(
isChecked
?
R
.
string
.
su_snack_notif_on
:
R
.
string
.
su_snack_notif_off
,
policy
.
appName
);
SnackbarMaker
.
make
(
holder
.
itemView
,
message
,
Snackbar
.
LENGTH_SHORT
).
show
();
dbHelper
.
updatePolicy
(
policy
);
}
});
holder
.
loggingSwitch
.
setOnCheckedChangeListener
((
v
,
isChecked
)
->
{
if
(
isChecked
!=
policy
.
logging
)
{
policy
.
logging
=
isChecked
;
String
message
=
v
.
getContext
().
getString
(
isChecked
?
R
.
string
.
su_snack_log_on
:
R
.
string
.
su_snack_log_off
,
policy
.
appName
);
SnackbarMaker
.
make
(
holder
.
itemView
,
message
,
Snackbar
.
LENGTH_SHORT
).
show
();
dbHelper
.
updatePolicy
(
policy
);
}
});
holder
.
delete
.
setOnClickListener
(
v
->
{
DialogInterface
.
OnClickListener
l
=
(
dialog
,
which
)
->
{
policyList
.
remove
(
position
);
notifyItemRemoved
(
position
);
notifyItemRangeChanged
(
position
,
policyList
.
size
());
SnackbarMaker
.
make
(
holder
.
itemView
,
v
.
getContext
().
getString
(
R
.
string
.
su_snack_revoke
,
policy
.
appName
),
Snackbar
.
LENGTH_SHORT
).
show
();
dbHelper
.
deletePolicy
(
policy
);
};
if
(
FingerprintHelper
.
useFingerprint
())
{
new
FingerprintAuthDialog
((
Activity
)
v
.
getContext
(),
()
->
l
.
onClick
(
null
,
0
)).
show
();
}
else
{
new
CustomAlertDialog
(
v
.
getContext
())
.
setTitle
(
R
.
string
.
su_revoke_title
)
.
setMessage
(
v
.
getContext
().
getString
(
R
.
string
.
su_revoke_msg
,
policy
.
appName
))
.
setPositiveButton
(
R
.
string
.
yes
,
l
)
.
setNegativeButton
(
R
.
string
.
no_thanks
,
null
)
.
setCancelable
(
true
)
.
show
();
}
});
}
@Override
public
int
getItemCount
()
{
return
policyList
.
size
();
}
static
class
ViewHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
app_name
)
TextView
appName
;
@BindView
(
R
.
id
.
package_name
)
TextView
packageName
;
@BindView
(
R
.
id
.
app_icon
)
ImageView
appIcon
;
@BindView
(
R
.
id
.
master_switch
)
SwitchCompat
masterSwitch
;
@BindView
(
R
.
id
.
notification_switch
)
SwitchCompat
notificationSwitch
;
@BindView
(
R
.
id
.
logging_switch
)
SwitchCompat
loggingSwitch
;
@BindView
(
R
.
id
.
expand_layout
)
ViewGroup
expandLayout
;
@BindView
(
R
.
id
.
arrow
)
ImageView
arrow
;
@BindView
(
R
.
id
.
trigger
)
View
trigger
;
@BindView
(
R
.
id
.
delete
)
ImageView
delete
;
@BindView
(
R
.
id
.
more_info
)
ImageView
moreInfo
;
Expandable
settings
;
public
ViewHolder
(
View
itemView
)
{
super
(
itemView
);
new
PolicyAdapter$ViewHolder_ViewBinding
(
this
,
itemView
);
settings
=
new
ArrowExpandable
(
new
ExpandableViewHolder
(
expandLayout
),
arrow
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/ReposAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.database.Cursor
;
import
android.os.Build
;
import
android.text.TextUtils
;
import
android.util.Pair
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.ImageView
;
import
android.widget.SearchView
;
import
android.widget.TextView
;
import
com.topjohnwu.magisk.App
;
import
com.topjohnwu.magisk.ClassMap
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.data.database.RepoDatabaseHelper
;
import
com.topjohnwu.magisk.model.download.DownloadModuleService
;
import
com.topjohnwu.magisk.model.entity.Module
;
import
com.topjohnwu.magisk.model.entity.Repo
;
import
com.topjohnwu.magisk.ui.base.IBaseLeanback
;
import
com.topjohnwu.magisk.ui.base.MagiskActivity
;
import
com.topjohnwu.magisk.utils.Event
;
import
com.topjohnwu.magisk.view.MarkDownWindow
;
import
com.topjohnwu.magisk.view.dialogs.CustomAlertDialog
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
import
java9.util.stream.StreamSupport
;
public
class
ReposAdapter
extends
SectionedAdapter
<
ReposAdapter
.
SectionHolder
,
ReposAdapter
.
RepoHolder
>
implements
Event
.
AutoListener
,
SearchView
.
OnQueryTextListener
{
private
static
final
int
UPDATES
=
0
;
private
static
final
int
INSTALLED
=
1
;
private
static
final
int
OTHERS
=
2
;
private
Map
<
String
,
Module
>
moduleMap
;
private
final
RepoDatabaseHelper
repoDB
;
private
final
List
<
Pair
<
Integer
,
List
<
Repo
>>>
repoPairs
;
private
List
<
Repo
>
fullList
;
private
SearchView
mSearch
;
public
ReposAdapter
()
{
repoDB
=
App
.
self
.
getRepoDB
();
moduleMap
=
Collections
.
emptyMap
();
fullList
=
Collections
.
emptyList
();
repoPairs
=
new
ArrayList
<>();
}
@Override
public
int
getSectionCount
()
{
return
repoPairs
.
size
();
}
@Override
public
int
getItemCount
(
int
section
)
{
return
repoPairs
.
get
(
section
).
second
.
size
();
}
@Override
public
SectionHolder
onCreateSectionViewHolder
(
ViewGroup
parent
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
section
,
parent
,
false
);
return
new
SectionHolder
(
v
);
}
@Override
public
RepoHolder
onCreateItemViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_repo
,
parent
,
false
);
return
new
RepoHolder
(
v
);
}
@Override
public
void
onBindSectionViewHolder
(
SectionHolder
holder
,
int
section
)
{
switch
(
repoPairs
.
get
(
section
).
first
)
{
case
UPDATES:
holder
.
sectionText
.
setText
(
R
.
string
.
update_available
);
break
;
case
INSTALLED:
holder
.
sectionText
.
setText
(
R
.
string
.
installed
);
break
;
case
OTHERS:
holder
.
sectionText
.
setText
(
R
.
string
.
not_installed
);
break
;
}
}
@Override
public
void
onBindItemViewHolder
(
RepoHolder
holder
,
int
section
,
int
position
)
{
Repo
repo
=
repoPairs
.
get
(
section
).
second
.
get
(
position
);
Context
context
=
holder
.
itemView
.
getContext
();
String
name
=
repo
.
getName
();
String
version
=
repo
.
getVersion
();
String
author
=
repo
.
getAuthor
();
String
description
=
repo
.
getDescription
();
String
noInfo
=
context
.
getString
(
R
.
string
.
no_info_provided
);
holder
.
title
.
setText
(
TextUtils
.
isEmpty
(
name
)
?
noInfo
:
name
);
holder
.
versionName
.
setText
(
TextUtils
.
isEmpty
(
version
)
?
noInfo
:
version
);
holder
.
author
.
setText
(
TextUtils
.
isEmpty
(
author
)
?
noInfo
:
context
.
getString
(
R
.
string
.
author
,
author
));
holder
.
description
.
setText
(
TextUtils
.
isEmpty
(
description
)
?
noInfo
:
description
);
holder
.
updateTime
.
setText
(
context
.
getString
(
R
.
string
.
updated_on
,
repo
.
getLastUpdateString
()));
holder
.
infoLayout
.
setOnClickListener
(
v
->
MarkDownWindow
.
show
(
context
,
null
,
repo
.
getDetailUrl
()));
holder
.
downloadImage
.
setOnClickListener
(
v
->
{
new
CustomAlertDialog
(
context
)
.
setTitle
(
context
.
getString
(
R
.
string
.
repo_install_title
,
repo
.
getName
()))
.
setMessage
(
context
.
getString
(
R
.
string
.
repo_install_msg
,
repo
.
getDownloadFilename
()))
.
setCancelable
(
true
)
.
setPositiveButton
(
R
.
string
.
install
,
(
d
,
i
)
->
startDownload
((
MagiskActivity
)
context
,
repo
,
true
))
.
setNeutralButton
(
R
.
string
.
download
,
(
d
,
i
)
->
startDownload
((
MagiskActivity
)
context
,
repo
,
false
))
.
setNegativeButton
(
R
.
string
.
no_thanks
,
null
)
.
show
();
});
}
private
<
Ctxt
extends
Context
&
IBaseLeanback
>
void
startDownload
(
Ctxt
activity
,
Repo
repo
,
Boolean
install
)
{
activity
.
runWithExternalRW
(()
->
{
Intent
intent
=
new
Intent
(
activity
,
ClassMap
.
get
(
DownloadModuleService
.
class
))
.
putExtra
(
"repo"
,
repo
).
putExtra
(
"install"
,
install
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
activity
.
startForegroundService
(
intent
);
}
else
{
activity
.
startService
(
intent
);
}
});
}
private
void
updateLists
()
{
if
(
mSearch
!=
null
)
onQueryTextChange
(
mSearch
.
getQuery
().
toString
());
else
onQueryTextChange
(
""
);
}
private
static
boolean
noCaseContain
(
String
a
,
String
b
)
{
return
a
.
toLowerCase
().
contains
(
b
.
toLowerCase
());
}
public
void
setSearchView
(
SearchView
view
)
{
mSearch
=
view
;
mSearch
.
setOnQueryTextListener
(
this
);
}
public
void
notifyDBChanged
(
boolean
refresh
)
{
try
(
Cursor
c
=
repoDB
.
getRepoCursor
())
{
fullList
=
new
ArrayList
<>(
c
.
getCount
());
while
(
c
.
moveToNext
())
fullList
.
add
(
new
Repo
(
c
));
}
if
(
refresh
)
updateLists
();
}
@Override
public
void
onEvent
(
int
event
)
{
moduleMap
=
Event
.
getResult
(
event
);
updateLists
();
}
@Override
public
int
[]
getListeningEvents
()
{
return
new
int
[]
{
Event
.
MODULE_LOAD_DONE
};
}
@Override
public
boolean
onQueryTextSubmit
(
String
query
)
{
return
false
;
}
@Override
public
boolean
onQueryTextChange
(
String
s
)
{
List
<
Repo
>
updates
=
new
ArrayList
<>();
List
<
Repo
>
installed
=
new
ArrayList
<>();
List
<
Repo
>
others
=
new
ArrayList
<>();
StreamSupport
.
stream
(
fullList
)
.
filter
(
repo
->
noCaseContain
(
repo
.
getName
(),
s
)
||
noCaseContain
(
repo
.
getAuthor
(),
s
)
||
noCaseContain
(
repo
.
getDescription
(),
s
))
.
forEach
(
repo
->
{
Module
module
=
moduleMap
.
get
(
repo
.
getId
());
if
(
module
!=
null
)
{
if
(
repo
.
getVersionCode
()
>
module
.
getVersionCode
())
{
// Updates
updates
.
add
(
repo
);
}
else
{
installed
.
add
(
repo
);
}
}
else
{
others
.
add
(
repo
);
}
});
repoPairs
.
clear
();
if
(!
updates
.
isEmpty
())
repoPairs
.
add
(
new
Pair
<>(
UPDATES
,
updates
));
if
(!
installed
.
isEmpty
())
repoPairs
.
add
(
new
Pair
<>(
INSTALLED
,
installed
));
if
(!
others
.
isEmpty
())
repoPairs
.
add
(
new
Pair
<>(
OTHERS
,
others
));
notifyDataSetChanged
();
return
false
;
}
static
class
SectionHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
section_text
)
TextView
sectionText
;
SectionHolder
(
View
itemView
)
{
super
(
itemView
);
new
ReposAdapter$SectionHolder_ViewBinding
(
this
,
itemView
);
}
}
static
class
RepoHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
title
)
TextView
title
;
@BindView
(
R
.
id
.
version_name
)
TextView
versionName
;
@BindView
(
R
.
id
.
description
)
TextView
description
;
@BindView
(
R
.
id
.
author
)
TextView
author
;
@BindView
(
R
.
id
.
info_layout
)
View
infoLayout
;
@BindView
(
R
.
id
.
download
)
ImageView
downloadImage
;
@BindView
(
R
.
id
.
update_time
)
TextView
updateTime
;
RepoHolder
(
View
itemView
)
{
super
(
itemView
);
new
ReposAdapter$RepoHolder_ViewBinding
(
this
,
itemView
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/SectionedAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.view.ViewGroup
;
import
androidx.annotation.NonNull
;
import
androidx.recyclerview.widget.RecyclerView
;
public
abstract
class
SectionedAdapter
<
S
extends
RecyclerView
.
ViewHolder
,
C
extends
RecyclerView
.
ViewHolder
>
extends
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>
{
private
static
final
int
SECTION_TYPE
=
Integer
.
MIN_VALUE
;
@NonNull
@Override
final
public
RecyclerView
.
ViewHolder
onCreateViewHolder
(
@NonNull
ViewGroup
parent
,
int
viewType
)
{
if
(
viewType
==
SECTION_TYPE
)
return
onCreateSectionViewHolder
(
parent
);
return
onCreateItemViewHolder
(
parent
,
viewType
);
}
@Override
@SuppressWarnings
(
"unchecked"
)
final
public
void
onBindViewHolder
(
@NonNull
RecyclerView
.
ViewHolder
holder
,
int
position
)
{
PositionInfo
info
=
getPositionInfo
(
position
);
if
(
info
.
position
==
-
1
)
onBindSectionViewHolder
((
S
)
holder
,
info
.
section
);
else
onBindItemViewHolder
((
C
)
holder
,
info
.
section
,
info
.
position
);
}
@Override
final
public
int
getItemCount
()
{
int
size
,
sec
;
size
=
sec
=
getSectionCount
();
for
(
int
i
=
0
;
i
<
sec
;
++
i
){
size
+=
getItemCount
(
i
);
}
return
size
;
}
@Override
final
public
int
getItemViewType
(
int
position
)
{
PositionInfo
info
=
getPositionInfo
(
position
);
if
(
info
.
position
==
-
1
)
return
SECTION_TYPE
;
else
return
getItemViewType
(
info
.
section
,
info
.
position
);
}
public
int
getItemViewType
(
int
section
,
int
position
)
{
return
0
;
}
protected
int
getSectionPosition
(
int
section
)
{
return
getItemPosition
(
section
,
-
1
);
}
protected
int
getItemPosition
(
int
section
,
int
position
)
{
int
realPosition
=
0
;
// Previous sections
for
(
int
i
=
0
;
i
<
section
;
++
i
)
{
realPosition
+=
getItemCount
(
i
)
+
1
;
}
// Current section
realPosition
+=
position
+
1
;
return
realPosition
;
}
private
PositionInfo
getPositionInfo
(
int
position
)
{
int
section
=
0
;
while
(
true
)
{
if
(
position
==
0
)
return
new
PositionInfo
(
section
,
-
1
);
position
-=
1
;
if
(
position
<
getItemCount
(
section
))
return
new
PositionInfo
(
section
,
position
);
position
-=
getItemCount
(
section
++);
}
}
private
static
class
PositionInfo
{
int
section
;
int
position
;
PositionInfo
(
int
section
,
int
position
)
{
this
.
section
=
section
;
this
.
position
=
position
;
}
}
public
abstract
int
getSectionCount
();
public
abstract
int
getItemCount
(
int
section
);
public
abstract
S
onCreateSectionViewHolder
(
ViewGroup
parent
);
public
abstract
C
onCreateItemViewHolder
(
ViewGroup
parent
,
int
viewType
);
public
abstract
void
onBindSectionViewHolder
(
S
holder
,
int
section
);
public
abstract
void
onBindItemViewHolder
(
C
holder
,
int
section
,
int
position
);
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/SuLogAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
android.content.Context
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.animation.Animation
;
import
android.view.animation.RotateAnimation
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.data.database.MagiskDB
;
import
com.topjohnwu.magisk.model.entity.SuLogEntry
;
import
com.topjohnwu.magisk.view.ExpandableViewHolder
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
public
class
SuLogAdapter
extends
SectionedAdapter
<
SuLogAdapter
.
SectionHolder
,
SuLogAdapter
.
LogViewHolder
>
{
private
List
<
List
<
SuLogEntry
>>
logEntries
;
private
Set
<
Integer
>
itemExpanded
,
sectionExpanded
;
private
MagiskDB
suDB
;
public
SuLogAdapter
(
MagiskDB
db
)
{
suDB
=
db
;
logEntries
=
Collections
.
emptyList
();
sectionExpanded
=
new
HashSet
<>();
itemExpanded
=
new
HashSet
<>();
}
@Override
public
int
getSectionCount
()
{
return
logEntries
.
size
();
}
@Override
public
int
getItemCount
(
int
section
)
{
return
sectionExpanded
.
contains
(
section
)
?
logEntries
.
get
(
section
).
size
()
:
0
;
}
@Override
public
SectionHolder
onCreateSectionViewHolder
(
ViewGroup
parent
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_sulog_group
,
parent
,
false
);
return
new
SectionHolder
(
v
);
}
@Override
public
LogViewHolder
onCreateItemViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
v
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
list_item_sulog
,
parent
,
false
);
return
new
LogViewHolder
(
v
);
}
@Override
public
void
onBindSectionViewHolder
(
SectionHolder
holder
,
int
section
)
{
SuLogEntry
entry
=
logEntries
.
get
(
section
).
get
(
0
);
holder
.
arrow
.
setRotation
(
sectionExpanded
.
contains
(
section
)
?
180
:
0
);
holder
.
itemView
.
setOnClickListener
(
v
->
{
RotateAnimation
rotate
;
if
(
sectionExpanded
.
contains
(
section
))
{
holder
.
arrow
.
setRotation
(
0
);
rotate
=
new
RotateAnimation
(
180
,
0
,
Animation
.
RELATIVE_TO_SELF
,
0.5f
,
Animation
.
RELATIVE_TO_SELF
,
0.5f
);
sectionExpanded
.
remove
(
section
);
notifyItemRangeRemoved
(
getItemPosition
(
section
,
0
),
logEntries
.
get
(
section
).
size
());
}
else
{
rotate
=
new
RotateAnimation
(
0
,
180
,
Animation
.
RELATIVE_TO_SELF
,
0.5f
,
Animation
.
RELATIVE_TO_SELF
,
0.5f
);
sectionExpanded
.
add
(
section
);
notifyItemRangeInserted
(
getItemPosition
(
section
,
0
),
logEntries
.
get
(
section
).
size
());
}
rotate
.
setDuration
(
300
);
rotate
.
setFillAfter
(
true
);
holder
.
arrow
.
setAnimation
(
rotate
);
});
holder
.
date
.
setText
(
entry
.
getDateString
());
}
@Override
public
void
onBindItemViewHolder
(
LogViewHolder
holder
,
int
section
,
int
position
)
{
SuLogEntry
entry
=
logEntries
.
get
(
section
).
get
(
position
);
int
realIdx
=
getItemPosition
(
section
,
position
);
holder
.
expandable
.
setExpanded
(
itemExpanded
.
contains
(
realIdx
));
holder
.
itemView
.
setOnClickListener
(
view
->
{
if
(
holder
.
expandable
.
isExpanded
())
{
holder
.
expandable
.
collapse
();
itemExpanded
.
remove
(
realIdx
);
}
else
{
holder
.
expandable
.
expand
();
itemExpanded
.
add
(
realIdx
);
}
});
Context
context
=
holder
.
itemView
.
getContext
();
holder
.
appName
.
setText
(
entry
.
appName
);
holder
.
action
.
setText
(
entry
.
action
?
R
.
string
.
grant
:
R
.
string
.
deny
);
holder
.
pid
.
setText
(
context
.
getString
(
R
.
string
.
pid
,
entry
.
fromPid
));
holder
.
uid
.
setText
(
context
.
getString
(
R
.
string
.
target_uid
,
entry
.
toUid
));
holder
.
command
.
setText
(
context
.
getString
(
R
.
string
.
command
,
entry
.
command
));
holder
.
time
.
setText
(
entry
.
getTimeString
());
}
public
void
notifyDBChanged
()
{
logEntries
=
suDB
.
getLogs
();
itemExpanded
.
clear
();
sectionExpanded
.
clear
();
sectionExpanded
.
add
(
0
);
notifyDataSetChanged
();
}
static
class
SectionHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
date
)
TextView
date
;
@BindView
(
R
.
id
.
arrow
)
ImageView
arrow
;
SectionHolder
(
View
itemView
)
{
super
(
itemView
);
new
SuLogAdapter$SectionHolder_ViewBinding
(
this
,
itemView
);
}
}
static
class
LogViewHolder
extends
RecyclerView
.
ViewHolder
{
@BindView
(
R
.
id
.
app_name
)
TextView
appName
;
@BindView
(
R
.
id
.
action
)
TextView
action
;
@BindView
(
R
.
id
.
time
)
TextView
time
;
@BindView
(
R
.
id
.
pid
)
TextView
pid
;
@BindView
(
R
.
id
.
uid
)
TextView
uid
;
@BindView
(
R
.
id
.
cmd
)
TextView
command
;
@BindView
(
R
.
id
.
expand_layout
)
ViewGroup
expandLayout
;
ExpandableViewHolder
expandable
;
LogViewHolder
(
View
itemView
)
{
super
(
itemView
);
new
SuLogAdapter$LogViewHolder_ViewBinding
(
this
,
itemView
);
expandable
=
new
ExpandableViewHolder
(
expandLayout
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/model/adapters/TabFragmentAdapter.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
model
.
adapters
;
import
java.util.ArrayList
;
import
java.util.List
;
import
androidx.fragment.app.Fragment
;
import
androidx.fragment.app.FragmentManager
;
import
androidx.fragment.app.FragmentPagerAdapter
;
public
class
TabFragmentAdapter
extends
FragmentPagerAdapter
{
private
List
<
Fragment
>
fragmentList
;
private
List
<
String
>
titleList
;
public
TabFragmentAdapter
(
FragmentManager
fm
)
{
super
(
fm
);
fragmentList
=
new
ArrayList
<>();
titleList
=
new
ArrayList
<>();
}
@Override
public
Fragment
getItem
(
int
position
)
{
return
fragmentList
.
get
(
position
);
}
@Override
public
int
getCount
()
{
return
fragmentList
.
size
();
}
@Override
public
CharSequence
getPageTitle
(
int
position
)
{
return
titleList
.
get
(
position
);
}
public
void
addTab
(
Fragment
fragment
,
String
title
)
{
fragmentList
.
add
(
fragment
);
titleList
.
add
(
title
);
}
}
app/src/main/java/com/topjohnwu/magisk/ui/log/MagiskLogFragment.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
ui
.
log
;
import
android.os.Bundle
;
import
android.view.LayoutInflater
;
import
android.view.Menu
;
import
android.view.MenuInflater
;
import
android.view.MenuItem
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
com.google.android.material.snackbar.Snackbar
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.adapters.StringListAdapter
;
import
com.topjohnwu.magisk.ui.base.BaseFragment
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.view.SnackbarMaker
;
import
com.topjohnwu.superuser.Shell
;
import
com.topjohnwu.superuser.internal.NOPList
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.Calendar
;
import
java.util.List
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
public
class
MagiskLogFragment
extends
BaseFragment
{
@BindView
(
R
.
id
.
recyclerView
)
RecyclerView
rv
;
@Nullable
@Override
public
View
onCreateView
(
LayoutInflater
inflater
,
ViewGroup
container
,
Bundle
savedInstanceState
)
{
View
view
=
inflater
.
inflate
(
R
.
layout
.
fragment_magisk_log
,
container
,
false
);
unbinder
=
new
MagiskLogFragment_ViewBinding
(
this
,
view
);
setHasOptionsMenu
(
true
);
return
view
;
}
@Override
public
void
onStart
()
{
super
.
onStart
();
getActivity
().
setTitle
(
R
.
string
.
log
);
}
@Override
public
void
onResume
()
{
super
.
onResume
();
readLogs
();
}
@Override
public
void
onCreateOptionsMenu
(
Menu
menu
,
MenuInflater
inflater
)
{
inflater
.
inflate
(
R
.
menu
.
menu_log
,
menu
);
}
@Override
public
boolean
onOptionsItemSelected
(
MenuItem
item
)
{
switch
(
item
.
getItemId
())
{
case
R
.
id
.
menu_refresh
:
readLogs
();
return
true
;
case
R
.
id
.
menu_save
:
runWithExternalRW
(
this
::
saveLogs
);
return
true
;
case
R
.
id
.
menu_clear
:
clearLogs
();
rv
.
setAdapter
(
new
MagiskLogAdapter
(
NOPList
.
getInstance
()));
return
true
;
default
:
return
true
;
}
}
private
void
readLogs
()
{
Shell
.
su
(
"tail -n 5000 "
+
Const
.
MAGISK_LOG
).
submit
(
result
->
{
rv
.
setAdapter
(
new
MagiskLogAdapter
(
result
.
getOut
()));
});
}
private
void
saveLogs
()
{
Calendar
now
=
Calendar
.
getInstance
();
String
filename
=
Utils
.
fmt
(
"magisk_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
{
logFile
.
createNewFile
();
}
catch
(
IOException
e
)
{
return
;
}
Shell
.
su
(
"cat "
+
Const
.
MAGISK_LOG
+
" > "
+
logFile
)
.
submit
(
result
->
SnackbarMaker
.
make
(
rv
,
logFile
.
getPath
(),
Snackbar
.
LENGTH_SHORT
).
show
());
}
private
void
clearLogs
()
{
Shell
.
su
(
"echo -n > "
+
Const
.
MAGISK_LOG
).
submit
();
SnackbarMaker
.
make
(
rv
,
R
.
string
.
logs_cleared
,
Snackbar
.
LENGTH_SHORT
).
show
();
}
private
class
MagiskLogAdapter
extends
StringListAdapter
<
MagiskLogAdapter
.
ViewHolder
>
{
MagiskLogAdapter
(
List
<
String
>
list
)
{
super
(
list
);
if
(
mList
.
isEmpty
())
mList
.
add
(
requireContext
().
getString
(
R
.
string
.
log_is_empty
));
}
@Override
protected
int
itemLayoutRes
()
{
return
R
.
layout
.
list_item_console
;
}
@NonNull
@Override
public
ViewHolder
createViewHolder
(
@NonNull
View
v
)
{
return
new
ViewHolder
(
v
);
}
@Override
protected
void
onUpdateTextWidth
(
ViewHolder
holder
)
{
super
.
onUpdateTextWidth
(
holder
);
// Find the longest string and update accordingly
int
max
=
0
;
String
maxStr
=
""
;
for
(
String
s
:
mList
)
{
int
len
=
s
.
length
();
if
(
len
>
max
)
{
max
=
len
;
maxStr
=
s
;
}
}
holder
.
txt
.
setText
(
maxStr
);
super
.
onUpdateTextWidth
(
holder
);
}
public
class
ViewHolder
extends
StringListAdapter
.
ViewHolder
{
public
ViewHolder
(
@NonNull
View
itemView
)
{
super
(
itemView
);
}
@Override
protected
int
textViewResId
()
{
return
R
.
id
.
txt
;
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/log/SuLogFragment.java
deleted
100644 → 0
View file @
aceb3ee8
package
com
.
topjohnwu
.
magisk
.
ui
.
log
;
import
android.os.Bundle
;
import
android.view.LayoutInflater
;
import
android.view.Menu
;
import
android.view.MenuInflater
;
import
android.view.MenuItem
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.TextView
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.model.adapters.SuLogAdapter
;
import
com.topjohnwu.magisk.ui.base.BaseFragment
;
import
androidx.annotation.Nullable
;
import
androidx.recyclerview.widget.RecyclerView
;
import
butterknife.BindView
;
public
class
SuLogFragment
extends
BaseFragment
{
@BindView
(
R
.
id
.
empty_rv
)
TextView
emptyRv
;
@BindView
(
R
.
id
.
recyclerView
)
RecyclerView
recyclerView
;
private
SuLogAdapter
adapter
;
@Override
public
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setHasOptionsMenu
(
true
);
}
@Override
public
void
onCreateOptionsMenu
(
Menu
menu
,
MenuInflater
inflater
)
{
inflater
.
inflate
(
R
.
menu
.
menu_log
,
menu
);
menu
.
findItem
(
R
.
id
.
menu_save
).
setVisible
(
false
);
}
@Override
public
View
onCreateView
(
LayoutInflater
inflater
,
ViewGroup
container
,
Bundle
savedInstanceState
)
{
// Inflate the layout for this fragment
View
v
=
inflater
.
inflate
(
R
.
layout
.
fragment_su_log
,
container
,
false
);
unbinder
=
new
SuLogFragment_ViewBinding
(
this
,
v
);
adapter
=
new
SuLogAdapter
(
app
.
getDB
());
recyclerView
.
setAdapter
(
adapter
);
updateList
();
return
v
;
}
private
void
updateList
()
{
adapter
.
notifyDBChanged
();
if
(
adapter
.
getSectionCount
()
==
0
)
{
emptyRv
.
setVisibility
(
View
.
VISIBLE
);
recyclerView
.
setVisibility
(
View
.
GONE
);
}
else
{
emptyRv
.
setVisibility
(
View
.
GONE
);
recyclerView
.
setVisibility
(
View
.
VISIBLE
);
}
}
@Override
public
boolean
onOptionsItemSelected
(
MenuItem
item
)
{
switch
(
item
.
getItemId
())
{
case
R
.
id
.
menu_refresh
:
updateList
();
return
true
;
case
R
.
id
.
menu_clear
:
app
.
getDB
().
clearLogs
();
updateList
();
return
true
;
default
:
return
true
;
}
}
}
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