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
5b2dce6c
Commit
5b2dce6c
authored
Sep 24, 2016
by
d8ahazard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Oh, it's so buttery...
Running out of stuff to fix.
👯
parent
bee9be53
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
214 additions
and
164 deletions
+214
-164
build.gradle
app/build.gradle
+3
-3
AutoRootFragment.java
app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
+1
-1
RootFragment.java
app/src/main/java/com/topjohnwu/magisk/RootFragment.java
+24
-20
WelcomeActivity.java
app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
+64
-3
AutoStartReceiver.java
...ava/com/topjohnwu/magisk/receivers/AutoStartReceiver.java
+1
-1
PrivateBroadcastReceiver.java
.../topjohnwu/magisk/receivers/PrivateBroadcastReceiver.java
+2
-2
MonitorService.java
...in/java/com/topjohnwu/magisk/services/MonitorService.java
+4
-4
TileServiceCompat.java
...java/com/topjohnwu/magisk/services/TileServiceCompat.java
+1
-1
TileServiceNewApi.java
...java/com/topjohnwu/magisk/services/TileServiceNewApi.java
+50
-42
PrefHelper.java
app/src/main/java/com/topjohnwu/magisk/utils/PrefHelper.java
+5
-0
Utils.java
app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
+53
-30
root_fragment.xml
app/src/main/res/layout/root_fragment.xml
+2
-2
settings_fragment.xml
app/src/main/res/layout/settings_fragment.xml
+0
-54
drawer.xml
app/src/main/res/menu/drawer.xml
+1
-1
strings.xml
app/src/main/res/values/strings.xml
+3
-0
No files found.
app/build.gradle
View file @
5b2dce6c
...
@@ -32,9 +32,9 @@ repositories {
...
@@ -32,9 +32,9 @@ repositories {
dependencies
{
dependencies
{
compile
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
compile
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
compile
'com.android.support:recyclerview-v7:24.2.
1
'
compile
'com.android.support:recyclerview-v7:24.2.
0
'
compile
'com.android.support:cardview-v7:24.2.
1
'
compile
'com.android.support:cardview-v7:24.2.
0
'
compile
'com.android.support:design:24.2.
1
'
compile
'com.android.support:design:24.2.
0
'
compile
'com.github.d8ahazard:BroadcastTileSupportUpdate:master'
compile
'com.github.d8ahazard:BroadcastTileSupportUpdate:master'
compile
'com.jakewharton:butterknife:8.4.0'
compile
'com.jakewharton:butterknife:8.4.0'
compile
'com.github.michalis-vitos:aFileChooser:master'
compile
'com.github.michalis-vitos:aFileChooser:master'
...
...
app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
View file @
5b2dce6c
...
@@ -62,7 +62,7 @@ public class AutoRootFragment extends ListFragment {
...
@@ -62,7 +62,7 @@ public class AutoRootFragment extends ListFragment {
super
.
onResume
();
super
.
onResume
();
initializeElements
();
initializeElements
();
super
.
onResume
();
super
.
onResume
();
getActivity
().
setTitle
(
"Auto-toggle"
);
getActivity
().
setTitle
(
R
.
string
.
auto_toggle_apps
);
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/RootFragment.java
View file @
5b2dce6c
...
@@ -23,6 +23,7 @@ import android.widget.Toast;
...
@@ -23,6 +23,7 @@ import android.widget.Toast;
import
com.topjohnwu.magisk.receivers.Receiver
;
import
com.topjohnwu.magisk.receivers.Receiver
;
import
com.topjohnwu.magisk.services.MonitorService
;
import
com.topjohnwu.magisk.services.MonitorService
;
import
com.topjohnwu.magisk.utils.Logger
;
import
com.topjohnwu.magisk.utils.PrefHelper
;
import
com.topjohnwu.magisk.utils.PrefHelper
;
import
com.topjohnwu.magisk.utils.Shell
;
import
com.topjohnwu.magisk.utils.Shell
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.utils.Utils
;
...
@@ -88,6 +89,7 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -88,6 +89,7 @@ public class RootFragment extends Fragment implements Receiver {
private
boolean
autoRootStatus
;
private
boolean
autoRootStatus
;
private
View
view
;
private
View
view
;
private
SharedPreferences
.
OnSharedPreferenceChangeListener
listener
;
@Nullable
@Nullable
@Override
@Override
...
@@ -107,8 +109,8 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -107,8 +109,8 @@ public class RootFragment extends Fragment implements Receiver {
new
updateUI
().
execute
();
new
updateUI
().
execute
();
rootToggle
.
setOnClickListener
(
toggle
->
{
rootToggle
.
setOnClickListener
(
toggle
->
{
Utils
.
toggleRoot
(((
CompoundButton
)
toggle
).
isChecked
());
Utils
.
toggleRoot
(((
CompoundButton
)
toggle
).
isChecked
()
,
getActivity
()
);
new
updateUI
().
execute
();
});
});
autoRootToggle
.
setOnClickListener
(
toggle
->
{
autoRootToggle
.
setOnClickListener
(
toggle
->
{
...
@@ -121,29 +123,34 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -121,29 +123,34 @@ public class RootFragment extends Fragment implements Receiver {
}
}
}
}
);
);
listener
=
(
prefs1
,
key
)
->
{
if
((
key
.
contains
(
"autoRootEnable"
))
|
(
key
.
equals
(
"root"
)))
{
Logger
.
dh
(
"RootFragmnet, keychange detected for "
+
key
);
new
updateUI
().
execute
();
}
};
prefs
.
registerOnSharedPreferenceChangeListener
(
listener
);
selinuxToggle
.
setOnClickListener
(
toggle
->
{
selinuxToggle
.
setOnClickListener
(
toggle
->
{
Shell
.
su
(((
CompoundButton
)
toggle
).
isChecked
()
?
"setenforce 1"
:
"setenforce 0"
);
Shell
.
su
(((
CompoundButton
)
toggle
).
isChecked
()
?
"setenforce 1"
:
"setenforce 0"
);
new
updateUI
().
execute
();
new
updateUI
().
execute
();
});
});
// LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mYourBroadcastReceiver,
// new IntentFilter("com.magisk.UPDATEUI"));
return
view
;
return
view
;
}
}
// private final BroadcastReceiver mYourBroadcastReceiver = new RootFragmentReceiver(Re) {
@Override
// @Override
public
void
onDestroy
()
{
// public void onReceive(Context context, Intent intent) {
super
.
onDestroy
();
//
prefs
.
unregisterOnSharedPreferenceChangeListener
(
listener
);
// Log.d("Magisk", "RootFragment: UpdateRF called and fired");
}
// new updateUI().execute();
// }
//
//
// };
@Override
@Override
public
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
public
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
...
@@ -158,9 +165,6 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -158,9 +165,6 @@ public class RootFragment extends Fragment implements Receiver {
Snackbar
.
make
(
view
,
getActivity
().
getString
(
R
.
string
.
auto_toggle
)
+
" disabled, permissions required."
,
Snackbar
.
LENGTH_LONG
).
show
();
Snackbar
.
make
(
view
,
getActivity
().
getString
(
R
.
string
.
auto_toggle
)
+
" disabled, permissions required."
,
Snackbar
.
LENGTH_LONG
).
show
();
}
}
}
else
if
(
requestCode
==
420
)
{
Log
.
d
(
"Magisk"
,
"Got result code OK for UI update."
);
new
updateUI
().
execute
();
}
}
}
}
...
@@ -182,7 +186,7 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -182,7 +186,7 @@ public class RootFragment extends Fragment implements Receiver {
rootToggle
.
setEnabled
(
true
);
rootToggle
.
setEnabled
(
true
);
}
}
new
updateUI
().
execute
();
}
}
...
@@ -190,7 +194,6 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -190,7 +194,6 @@ public class RootFragment extends Fragment implements Receiver {
public
void
onResume
()
{
public
void
onResume
()
{
super
.
onResume
();
super
.
onResume
();
getActivity
().
setTitle
(
"Root"
);
getActivity
().
setTitle
(
"Root"
);
new
updateUI
().
execute
();
new
updateUI
().
execute
();
}
}
...
@@ -209,6 +212,7 @@ public class RootFragment extends Fragment implements Receiver {
...
@@ -209,6 +212,7 @@ public class RootFragment extends Fragment implements Receiver {
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
getActivity
()))
{
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
getActivity
()))
{
Utils
.
SetupQuickSettingsTile
(
getActivity
());
Utils
.
SetupQuickSettingsTile
(
getActivity
());
}
}
autoRootStatus
=
Utils
.
autoToggleEnabled
(
getActivity
());
return
null
;
return
null
;
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
View file @
5b2dce6c
...
@@ -39,6 +39,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
...
@@ -39,6 +39,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
private
final
Handler
mDrawerHandler
=
new
Handler
();
private
final
Handler
mDrawerHandler
=
new
Handler
();
private
String
currentTitle
;
private
String
currentTitle
;
private
String
tag
;
@BindView
(
R
.
id
.
toolbar
)
@BindView
(
R
.
id
.
toolbar
)
Toolbar
toolbar
;
Toolbar
toolbar
;
...
@@ -73,6 +74,66 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
...
@@ -73,6 +74,66 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
requestPermissions
(
new
String
[]{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
0
);
requestPermissions
(
new
String
[]{
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
},
0
);
}
}
this
.
getFragmentManager
().
addOnBackStackChangedListener
(
()
->
{
FragmentManager
fragmentManager
=
getFragmentManager
();
Fragment
hm
=
getFragmentManager
().
findFragmentByTag
(
"root"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
root
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"autoroot"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
autoroot
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"magisk"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
magisk
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"modules"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
modules
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"downloads"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
downloads
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"log"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
log
);
}
}
hm
=
getFragmentManager
().
findFragmentByTag
(
"settings"
);
if
(
hm
!=
null
)
{
if
(
hm
.
isVisible
())
{
navigationView
.
setCheckedItem
(
R
.
id
.
settings
);
}
}
});
...
@@ -170,7 +231,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
...
@@ -170,7 +231,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
public
void
navigate
(
final
int
itemId
)
{
public
void
navigate
(
final
int
itemId
)
{
Fragment
navFragment
=
null
;
Fragment
navFragment
=
null
;
String
tag
=
""
;
tag
=
""
;
switch
(
itemId
)
{
switch
(
itemId
)
{
case
R
.
id
.
magisk
:
case
R
.
id
.
magisk
:
setTitle
(
R
.
string
.
magisk
);
setTitle
(
R
.
string
.
magisk
);
...
@@ -183,8 +244,8 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
...
@@ -183,8 +244,8 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
navFragment
=
new
RootFragment
();
navFragment
=
new
RootFragment
();
break
;
break
;
case
R
.
id
.
autoroot
:
case
R
.
id
.
autoroot
:
setTitle
(
R
.
string
.
auto_toggle
);
setTitle
(
R
.
string
.
auto_toggle
_apps
);
tag
=
"
ic_
autoroot"
;
tag
=
"autoroot"
;
navFragment
=
new
AutoRootFragment
();
navFragment
=
new
AutoRootFragment
();
break
;
break
;
case
R
.
id
.
modules
:
case
R
.
id
.
modules
:
...
...
app/src/main/java/com/topjohnwu/magisk/receivers/AutoStartReceiver.java
View file @
5b2dce6c
...
@@ -16,7 +16,7 @@ public class AutoStartReceiver extends BroadcastReceiver {
...
@@ -16,7 +16,7 @@ public class AutoStartReceiver extends BroadcastReceiver {
Intent
myIntent
=
new
Intent
(
context
,
MonitorService
.
class
);
Intent
myIntent
=
new
Intent
(
context
,
MonitorService
.
class
);
context
.
startService
(
myIntent
);
context
.
startService
(
myIntent
);
if
(
PrefHelper
.
CheckBool
(
"keep_root_off"
,
context
))
{
if
(
PrefHelper
.
CheckBool
(
"keep_root_off"
,
context
))
{
Utils
.
toggleRoot
(
false
);
Utils
.
toggleRoot
(
false
,
context
);
}
}
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
Utils
.
SetupQuickSettingsTile
(
context
);
Utils
.
SetupQuickSettingsTile
(
context
);
...
...
app/src/main/java/com/topjohnwu/magisk/receivers/PrivateBroadcastReceiver.java
View file @
5b2dce6c
...
@@ -25,11 +25,11 @@ public final class PrivateBroadcastReceiver extends BroadcastReceiver {
...
@@ -25,11 +25,11 @@ public final class PrivateBroadcastReceiver extends BroadcastReceiver {
}
}
if
(
ACTION_ENABLEROOT
.
equals
(
action
))
{
if
(
ACTION_ENABLEROOT
.
equals
(
action
))
{
Utils
.
toggleAutoRoot
(
false
,
context
);
Utils
.
toggleAutoRoot
(
false
,
context
);
Utils
.
toggleRoot
(
true
);
Utils
.
toggleRoot
(
true
,
context
);
}
}
if
(
ACTION_DISABLEROOT
.
equals
(
action
))
{
if
(
ACTION_DISABLEROOT
.
equals
(
action
))
{
Utils
.
toggleAutoRoot
(
false
,
context
);
Utils
.
toggleAutoRoot
(
false
,
context
);
Utils
.
toggleRoot
(
false
);
Utils
.
toggleRoot
(
false
,
context
);
}
}
Utils
.
SetupQuickSettingsTile
(
context
);
Utils
.
SetupQuickSettingsTile
(
context
);
...
...
app/src/main/java/com/topjohnwu/magisk/services/MonitorService.java
View file @
5b2dce6c
...
@@ -111,9 +111,9 @@ public class MonitorService extends AccessibilityService {
...
@@ -111,9 +111,9 @@ public class MonitorService extends AccessibilityService {
String
rootString
=
rootToggle
?
"on"
:
"off"
;
String
rootString
=
rootToggle
?
"on"
:
"off"
;
if
(
Utils
.
rootEnabled
()
!=
rootToggle
)
{
if
(
Utils
.
rootEnabled
()
!=
rootToggle
)
{
Logger
.
dh
(
"MonitorService: toggling root "
+
rootString
);
Logger
.
dh
(
"MonitorService: toggling root "
+
rootString
);
Utils
.
toggleRoot
(
rootToggle
);
Utils
.
toggleRoot
(
rootToggle
,
getApplicationContext
()
);
if
(
Utils
.
rootEnabled
()
!=
rootToggle
)
{
if
(
Utils
.
rootEnabled
()
!=
rootToggle
)
{
Utils
.
toggleRoot
(
rootToggle
);
Utils
.
toggleRoot
(
rootToggle
,
getApplicationContext
()
);
Logger
.
dh
(
"MonitorService: FORCING to "
+
rootString
);
Logger
.
dh
(
"MonitorService: FORCING to "
+
rootString
);
}
}
...
@@ -122,9 +122,9 @@ public class MonitorService extends AccessibilityService {
...
@@ -122,9 +122,9 @@ public class MonitorService extends AccessibilityService {
private
void
ForceEnableRoot
()
{
private
void
ForceEnableRoot
()
{
Log
.
d
(
"Magisk"
,
"MonitorService: ForceEnable called."
);
Log
.
d
(
"Magisk"
,
"MonitorService: ForceEnable called."
);
Utils
.
toggleRoot
(
true
);
Utils
.
toggleRoot
(
true
,
getApplicationContext
()
);
if
(!
Utils
.
rootEnabled
())
{
if
(!
Utils
.
rootEnabled
())
{
Utils
.
toggleRoot
(
true
);
Utils
.
toggleRoot
(
true
,
getApplicationContext
()
);
}
}
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/services/TileServiceCompat.java
View file @
5b2dce6c
...
@@ -75,7 +75,7 @@ public class TileServiceCompat extends Service {
...
@@ -75,7 +75,7 @@ public class TileServiceCompat extends Service {
private
void
onSimpleClick
()
{
private
void
onSimpleClick
()
{
updateRoots
();
updateRoots
();
updateTile
();
updateTile
();
Utils
.
toggleRoot
(!
root
);
Utils
.
toggleRoot
(!
root
,
getApplicationContext
()
);
}
}
private
void
onLongClick
()
{
private
void
onLongClick
()
{
...
...
app/src/main/java/com/topjohnwu/magisk/services/TileServiceNewApi.java
View file @
5b2dce6c
package
com
.
topjohnwu
.
magisk
.
services
;
package
com
.
topjohnwu
.
magisk
.
services
;
import
android.annotation.SuppressLint
;
import
android.annotation.SuppressLint
;
import
android.content.
SharedPreferences
;
import
android.content.
Intent
;
import
android.graphics.drawable.Icon
;
import
android.graphics.drawable.Icon
;
import
android.preference.PreferenceManager
;
import
android.service.quicksettings.Tile
;
import
android.service.quicksettings.Tile
;
import
android.util.Log
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Logger
;
import
com.topjohnwu.magisk.utils.Logger
;
import
com.topjohnwu.magisk.utils.Utils
;
import
com.topjohnwu.magisk.utils.Utils
;
@SuppressLint
(
"NewApi"
)
@SuppressLint
(
"NewApi"
)
public
class
TileServiceNewApi
extends
android
.
service
.
quicksettings
.
TileService
implements
public
class
TileServiceNewApi
extends
android
.
service
.
quicksettings
.
TileService
{
SharedPreferences
.
OnSharedPreferenceChangeListener
{
private
int
mRootsState
;
private
int
STATE_CURRENT
;
public
TileServiceNewApi
()
{
public
TileServiceNewApi
()
{
}
}
@Override
public
int
onStartCommand
(
Intent
intent
,
int
flags
,
int
startId
)
{
Logger
.
dh
(
"QST (New): Service start"
);
return
super
.
onStartCommand
(
intent
,
flags
,
startId
);
}
@Override
@Override
public
void
onTileAdded
()
{
public
void
onTileAdded
()
{
super
.
onTileAdded
();
super
.
onTileAdded
();
Logger
.
dh
(
"QST (New): Tile added"
);
setupState
();
setupState
();
this
.
getQsTile
().
updateTile
();
this
.
getQsTile
().
updateTile
();
}
}
@Override
@Override
public
void
onClick
()
{
public
void
onClick
()
{
switchState
();
mRootsState
=
Utils
.
CheckRootsState
(
getApplicationContext
());
this
.
getQsTile
().
updateTile
();
switchState
(
mRootsState
);
Logger
.
dh
(
"QST (New): Tile clicked"
);
}
@Override
public
void
onStartListening
()
{
super
.
onStartListening
();
setupState
();
Logger
.
dh
(
"QST (New): Tile is listening"
);
}
@Override
public
void
onStopListening
()
{
super
.
onStopListening
();
Logger
.
dh
(
"QST (New): Tile stopped listening"
);
}
}
private
void
setupState
()
{
private
void
setupState
()
{
SharedPreferences
preferences
=
PreferenceManager
.
getDefaultSharedPreferences
(
getApplicationContext
());
mRootsState
=
Utils
.
CheckRootsState
(
getApplicationContext
());
preferences
.
registerOnSharedPreferenceChangeListener
(
this
);
Logger
.
dh
(
"QST (New): SetupState"
);
Logger
.
dh
(
"TileService(New): SetupState"
);
Icon
iconRoot
=
Icon
.
createWithResource
(
getApplicationContext
(),
R
.
drawable
.
root
);
Icon
iconRoot
=
Icon
.
createWithResource
(
getApplicationContext
(),
R
.
drawable
.
root
);
Icon
iconAuto
=
Icon
.
createWithResource
(
getApplicationContext
(),
R
.
drawable
.
ic_autoroot
);
Icon
iconAuto
=
Icon
.
createWithResource
(
getApplicationContext
(),
R
.
drawable
.
ic_autoroot
);
Tile
tile
=
this
.
getQsTile
();
Tile
tile
=
getQsTile
();
boolean
autoRootStatus
=
Utils
.
autoToggleEnabled
(
getApplicationContext
());
Logger
.
dh
(
"QST: State is "
+
mRootsState
);
boolean
rootStatus
=
Utils
.
rootEnabled
();
switch
(
mRootsState
)
{
int
rootsStatus
=
Utils
.
CheckRootsState
(
getApplicationContext
());
case
2
:
Log
.
d
(
"Magisk"
,
"QST: Auto and root are "
+
autoRootStatus
+
" and "
+
rootStatus
+
Utils
.
CheckRootsState
(
getApplicationContext
()));
tile
.
setLabel
(
getApplicationContext
().
getString
(
R
.
string
.
auto_toggle
));
if
(
rootsStatus
==
2
)
{
tile
.
setIcon
(
iconAuto
);
tile
.
setLabel
(
getApplicationContext
().
getString
(
R
.
string
.
auto_toggle
));
tile
.
setState
(
Tile
.
STATE_ACTIVE
);
tile
.
setIcon
(
iconAuto
);
break
;
tile
.
setState
(
Tile
.
STATE_ACTIVE
);
}
else
if
(
rootsStatus
==
1
)
{
tile
.
setLabel
(
"Root enabled"
);
tile
.
setIcon
(
iconRoot
);
tile
.
setState
(
Tile
.
STATE_ACTIVE
);
}
else
{
tile
.
setLabel
(
"Root disabled"
);
tile
.
setIcon
(
iconRoot
);
tile
.
setState
(
Tile
.
STATE_INACTIVE
);
case
1
:
tile
.
setLabel
(
"Root enabled"
);
tile
.
setIcon
(
iconRoot
);
tile
.
setState
(
Tile
.
STATE_ACTIVE
);
break
;
default
:
tile
.
setLabel
(
"Root disabled"
);
tile
.
setIcon
(
iconRoot
);
tile
.
setState
(
Tile
.
STATE_INACTIVE
);
break
;
}
}
tile
.
updateTile
();
tile
.
updateTile
();
}
}
public
void
onSharedPreferenceChanged
(
SharedPreferences
sharedPreferences
,
String
key
)
private
void
switchState
(
int
rootsState
)
{
{
Logger
.
dh
(
"TileService: Key Change registered for "
+
key
);
if
(
key
.
equals
(
"autoRootEnable"
))
{
}
}
private
void
switchState
()
{
switch
(
rootsState
)
{
switch
(
Utils
.
CheckRootsState
(
getApplicationContext
()))
{
case
2
:
case
2
:
Utils
.
toggleRoot
(
true
);
Utils
.
toggleRoot
(
true
,
getApplicationContext
()
);
Utils
.
toggleAutoRoot
(
false
,
getApplicationContext
());
Utils
.
toggleAutoRoot
(
false
,
getApplicationContext
());
break
;
break
;
case
1
:
case
1
:
Utils
.
toggleRoot
(
false
);
Utils
.
toggleRoot
(
false
,
getApplicationContext
()
);
break
;
break
;
case
0
:
case
0
:
Utils
.
toggleAutoRoot
(
true
,
getApplicationContext
());
Utils
.
toggleAutoRoot
(
true
,
getApplicationContext
());
break
;
break
;
}
}
this
.
onStartListening
();
setupState
();
setupState
();
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/utils/PrefHelper.java
View file @
5b2dce6c
...
@@ -15,6 +15,11 @@ public class PrefHelper {
...
@@ -15,6 +15,11 @@ public class PrefHelper {
return
PreferenceManager
.
getDefaultSharedPreferences
(
context
).
getBoolean
(
key
,
false
);
return
PreferenceManager
.
getDefaultSharedPreferences
(
context
).
getBoolean
(
key
,
false
);
}
}
public
static
void
SetBool
(
String
key
,
Boolean
value
,
Context
context
)
{
PreferenceManager
.
getDefaultSharedPreferences
(
context
).
edit
().
putBoolean
(
key
,
value
).
commit
();
}
}
}
app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
View file @
5b2dce6c
...
@@ -16,6 +16,7 @@ import android.os.Build;
...
@@ -16,6 +16,7 @@ import android.os.Build;
import
android.os.Environment
;
import
android.os.Environment
;
import
android.preference.PreferenceManager
;
import
android.preference.PreferenceManager
;
import
android.provider.Settings
;
import
android.provider.Settings
;
import
android.service.quicksettings.TileService
;
import
android.support.design.widget.Snackbar
;
import
android.support.design.widget.Snackbar
;
import
android.support.v4.app.ActivityCompat
;
import
android.support.v4.app.ActivityCompat
;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
...
@@ -30,8 +31,8 @@ import com.topjohnwu.magisk.RootFragment;
...
@@ -30,8 +31,8 @@ import com.topjohnwu.magisk.RootFragment;
import
com.topjohnwu.magisk.module.BaseModule
;
import
com.topjohnwu.magisk.module.BaseModule
;
import
com.topjohnwu.magisk.receivers.PrivateBroadcastReceiver
;
import
com.topjohnwu.magisk.receivers.PrivateBroadcastReceiver
;
import
com.topjohnwu.magisk.services.MonitorService
;
import
com.topjohnwu.magisk.services.MonitorService
;
import
com.topjohnwu.magisk.services.TileServiceNewApi
;
import
com.topjohnwu.magisk.services.TileServiceCompat
;
import
com.topjohnwu.magisk.services.TileServiceCompat
;
import
com.topjohnwu.magisk.services.TileServiceNewApi
;
import
java.io.File
;
import
java.io.File
;
import
java.io.UnsupportedEncodingException
;
import
java.io.UnsupportedEncodingException
;
...
@@ -71,10 +72,10 @@ public class Utils {
...
@@ -71,10 +72,10 @@ public class Utils {
if
(!
Shell
.
rootAccess
())
{
if
(!
Shell
.
rootAccess
())
{
Snackbar
.
make
(((
Activity
)
context
).
findViewById
(
android
.
R
.
id
.
content
),
R
.
string
.
no_root_access
,
Snackbar
.
LENGTH_LONG
).
show
();
Snackbar
.
make
(((
Activity
)
context
).
findViewById
(
android
.
R
.
id
.
content
),
R
.
string
.
no_root_access
,
Snackbar
.
LENGTH_LONG
).
show
();
}
}
if
(
PrefHelper
.
CheckBool
(
"keep_root_off"
,
context
))
{
if
(
PrefHelper
.
CheckBool
(
"keep_root_off"
,
context
))
{
Utils
.
toggleRoot
(
false
);
Utils
.
toggleRoot
(
false
,
context
);
}
}
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
Utils
.
SetupQuickSettingsTile
(
context
);
Utils
.
SetupQuickSettingsTile
(
context
);
}
}
}
}
...
@@ -114,39 +115,58 @@ public class Utils {
...
@@ -114,39 +115,58 @@ public class Utils {
}
}
public
static
boolean
removeFile
(
String
path
)
{
public
static
boolean
removeFile
(
String
path
)
{
boolean
check
;
String
command
=
"rm -f "
+
path
+
" 2>/dev/null; if [ -f "
+
path
+
" ]; then echo false; else echo true; fi"
;
String
command
=
"rm -f "
+
path
+
" 2>/dev/null; if [ -f "
+
path
+
" ]; then echo false; else echo true; fi"
;
if
(!
Shell
.
rootAccess
())
{
if
(!
Shell
.
rootAccess
())
{
return
false
;
return
false
;
}
else
{
}
else
{
return
Boolean
.
parseBoolean
(
Shell
.
su
(
command
).
get
(
0
));
try
{
check
=
Boolean
.
parseBoolean
(
Shell
.
su
(
command
).
get
(
0
));
return
check
;
}
catch
(
NullPointerException
e
)
{
Log
.
d
(
"Magisk:"
,
"SU error executing removeFile "
+
e
);
return
false
;
}
}
}
}
}
public
static
void
toggleRoot
(
Boolean
b
)
{
public
static
void
toggleRoot
(
Boolean
b
,
Context
context
)
{
if
(
Utils
.
magiskVersion
!=
-
1
)
{
if
(
Utils
.
magiskVersion
!=
-
1
)
{
if
(
b
)
{
if
(
b
)
{
Shell
.
su
(
"ln -s $(getprop magisk.supath) /magisk/.core/bin"
,
"setprop magisk.root 1"
);
Shell
.
su
(
"ln -s $(getprop magisk.supath) /magisk/.core/bin"
,
"setprop magisk.root 1"
);
}
else
{
}
else
{
Shell
.
su
(
"rm -rf /magisk/.core/bin"
,
"setprop magisk.root 0"
);
Shell
.
su
(
"rm -rf /magisk/.core/bin"
,
"setprop magisk.root 0"
);
}
}
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
SetupQuickSettingsTile
(
context
);
}
PrefHelper
.
SetBool
(
"root"
,
b
,
context
);
}
}
}
}
public
static
void
toggleAutoRoot
(
Boolean
b
,
Context
context
)
{
public
static
void
toggleAutoRoot
(
Boolean
b
,
Context
context
)
{
if
(
Utils
.
magiskVersion
!=
-
1
)
{
if
(
Utils
.
magiskVersion
!=
-
1
)
{
PreferenceManager
.
getDefaultSharedPreferences
(
context
).
edit
().
putBoolean
(
"autoRootEnable"
,
b
).
apply
();
if
(!
Utils
.
hasServicePermission
(
context
))
{
Intent
myServiceIntent
=
new
Intent
(
context
,
MonitorService
.
class
);
Intent
intent
=
new
Intent
(
android
.
provider
.
Settings
.
ACTION_ACCESSIBILITY_SETTINGS
);
if
(
b
)
{
Toast
.
makeText
(
context
,
"Please enable Magisk in accessibility for auto-toggle work."
,
Toast
.
LENGTH_LONG
).
show
();
context
.
start
Service
(
myServiceI
ntent
);
context
.
start
Activity
(
i
ntent
);
}
else
{
}
else
{
context
.
stopService
(
myServiceIntent
);
PreferenceManager
.
getDefaultSharedPreferences
(
context
).
edit
().
putBoolean
(
"autoRootEnable"
,
b
).
apply
();
Intent
myServiceIntent
=
new
Intent
(
context
,
MonitorService
.
class
);
if
(
b
)
{
context
.
startService
(
myServiceIntent
);
}
else
{
context
.
stopService
(
myServiceIntent
);
}
}
}
}
}
if
(
PrefHelper
.
CheckBool
(
"enable_quicktile"
,
context
))
{
SetupQuickSettingsTile
(
context
);
}
UpdateRootFragmentUI
(
context
);
UpdateRootFragmentUI
(
context
);
}
}
public
static
List
<
String
>
getModList
(
String
path
)
{
static
List
<
String
>
getModList
(
String
path
)
{
List
<
String
>
ret
;
List
<
String
>
ret
;
String
command
=
"find "
+
path
+
" -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""
;
String
command
=
"find "
+
path
+
" -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""
;
if
(
Shell
.
rootAccess
())
{
if
(
Shell
.
rootAccess
())
{
...
@@ -175,8 +195,18 @@ public class Utils {
...
@@ -175,8 +195,18 @@ public class Utils {
}
}
File
downloadFile
,
dir
=
new
File
(
Environment
.
getExternalStorageDirectory
()
+
"/MagiskManager"
);
File
downloadFile
,
dir
=
new
File
(
Environment
.
getExternalStorageDirectory
()
+
"/MagiskManager"
);
downloadFile
=
new
File
(
dir
+
"/"
+
file
);
downloadFile
=
new
File
(
dir
+
"/"
+
file
);
if
(!
dir
.
exists
())
dir
.
mkdir
();
if
(!
dir
.
exists
())
{
if
(
downloadFile
.
exists
())
downloadFile
.
delete
();
if
(!
dir
.
mkdirs
())
{
Toast
.
makeText
(
context
,
R
.
string
.
toast_error_makedir
,
Toast
.
LENGTH_LONG
).
show
();
return
;
}
}
if
(
downloadFile
.
exists
())
{
if
(!
downloadFile
.
delete
())
{
Toast
.
makeText
(
context
,
R
.
string
.
toast_error_removing_files
,
Toast
.
LENGTH_LONG
).
show
();
return
;
}
}
DownloadManager
downloadManager
=
(
DownloadManager
)
context
.
getSystemService
(
Context
.
DOWNLOAD_SERVICE
);
DownloadManager
downloadManager
=
(
DownloadManager
)
context
.
getSystemService
(
Context
.
DOWNLOAD_SERVICE
);
DownloadManager
.
Request
request
=
new
DownloadManager
.
Request
(
Uri
.
parse
(
link
));
DownloadManager
.
Request
request
=
new
DownloadManager
.
Request
(
Uri
.
parse
(
link
));
...
@@ -213,8 +243,10 @@ public class Utils {
...
@@ -213,8 +243,10 @@ public class Utils {
public
static
void
SetupQuickSettingsTile
(
Context
mContext
)
{
public
static
void
SetupQuickSettingsTile
(
Context
mContext
)
{
Logger
.
dh
(
"Utils: SetupQuickSettings called"
);
Logger
.
dh
(
"Utils: SetupQuickSettings called"
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
N
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
N
)
{
Logger
.
dh
(
"Utils: Starting N quick settings service"
);
Intent
serviceIntent
=
new
Intent
(
mContext
,
TileServiceNewApi
.
class
);
Intent
serviceIntent
=
new
Intent
(
mContext
,
TileServiceNewApi
.
class
);
mContext
.
startService
(
serviceIntent
);
mContext
.
startService
(
serviceIntent
);
}
}
if
(
Build
.
VERSION
.
SDK_INT
==
Build
.
VERSION_CODES
.
M
)
{
if
(
Build
.
VERSION
.
SDK_INT
==
Build
.
VERSION_CODES
.
M
)
{
Logger
.
dh
(
"Utils: Marshmallow build detected"
);
Logger
.
dh
(
"Utils: Marshmallow build detected"
);
...
@@ -275,10 +307,8 @@ public class Utils {
...
@@ -275,10 +307,8 @@ public class Utils {
List
<
String
>
lines
=
Shell
.
su
(
"settings get secure sysui_qs_tiles"
);
List
<
String
>
lines
=
Shell
.
su
(
"settings get secure sysui_qs_tiles"
);
if
(
lines
!=
null
&&
lines
.
size
()
==
1
)
{
if
(
lines
!=
null
&&
lines
.
size
()
==
1
)
{
List
<
String
>
tiles
=
new
LinkedList
<
String
>(
Arrays
.
asList
(
lines
.
get
(
0
).
split
(
","
)));
List
<
String
>
tiles
=
new
LinkedList
<>(
Arrays
.
asList
(
lines
.
get
(
0
).
split
(
","
)));
List
<
String
>
tiles2
;
Logger
.
dh
(
"Utils: Current Tile String is "
+
tiles
);
int
tileSpace
=
Math
.
round
(
tiles
.
size
()/
2
);
Logger
.
dh
(
"Utils: Current Tile String is "
+
tiles
);
if
(
tiles
.
size
()
>
1
)
{
if
(
tiles
.
size
()
>
1
)
{
for
(
String
tile
:
tiles
)
{
for
(
String
tile
:
tiles
)
{
if
(
tile
.
equals
(
qsTileId
))
{
if
(
tile
.
equals
(
qsTileId
))
{
...
@@ -287,9 +317,9 @@ public class Utils {
...
@@ -287,9 +317,9 @@ public class Utils {
}
}
}
}
tiles
.
add
(
Math
.
round
(
tiles
.
size
()
/
2
),
qsTileId
);
tiles
.
add
(
Math
.
round
(
tiles
.
size
()
/
2
),
qsTileId
);
String
newTiles
=
TextUtils
.
join
(
","
,
tiles
);
String
newTiles
=
TextUtils
.
join
(
","
,
tiles
);
Logger
.
dh
(
"Utils: NewtilesString is "
+
newTiles
);
Logger
.
dh
(
"Utils: NewtilesString is "
+
newTiles
);
Shell
.
su
(
"settings put secure sysui_qs_tiles \""
+
newTiles
+
"\""
);
Shell
.
su
(
"settings put secure sysui_qs_tiles \""
+
newTiles
+
"\""
);
Toast
.
makeText
(
context
,
"Tile installed"
,
Toast
.
LENGTH_SHORT
).
show
();
Toast
.
makeText
(
context
,
"Tile installed"
,
Toast
.
LENGTH_SHORT
).
show
();
if
(
Build
.
VERSION
.
SDK_INT
==
Build
.
VERSION_CODES
.
M
)
{
if
(
Build
.
VERSION
.
SDK_INT
==
Build
.
VERSION_CODES
.
M
)
{
...
@@ -301,7 +331,6 @@ public class Utils {
...
@@ -301,7 +331,6 @@ public class Utils {
Toast
.
makeText
(
context
,
"Tile installation error"
,
Toast
.
LENGTH_SHORT
).
show
();
Toast
.
makeText
(
context
,
"Tile installation error"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
public
static
void
uninstallTile
(
Context
context
)
{
public
static
void
uninstallTile
(
Context
context
)
{
String
qsTileId
;
String
qsTileId
;
...
@@ -312,7 +341,7 @@ public class Utils {
...
@@ -312,7 +341,7 @@ public class Utils {
}
}
List
<
String
>
lines
=
Shell
.
su
(
"settings get secure sysui_qs_tiles"
);
List
<
String
>
lines
=
Shell
.
su
(
"settings get secure sysui_qs_tiles"
);
if
(
lines
!=
null
&&
lines
.
size
()
==
1
)
{
if
(
lines
!=
null
&&
lines
.
size
()
==
1
)
{
List
<
String
>
tiles
=
new
LinkedList
<
String
>(
Arrays
.
asList
(
lines
.
get
(
0
).
split
(
","
)));
List
<
String
>
tiles
=
new
LinkedList
<>(
Arrays
.
asList
(
lines
.
get
(
0
).
split
(
","
)));
if
(
tiles
.
size
()
>
1
)
{
if
(
tiles
.
size
()
>
1
)
{
boolean
isPresent
=
false
;
boolean
isPresent
=
false
;
for
(
int
i
=
0
;
i
<
tiles
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
tiles
.
size
();
i
++)
{
...
@@ -333,25 +362,20 @@ public class Utils {
...
@@ -333,25 +362,20 @@ public class Utils {
}
}
Toast
.
makeText
(
context
,
"Tile already uninstalled"
,
Toast
.
LENGTH_SHORT
).
show
();
Toast
.
makeText
(
context
,
"Tile already uninstalled"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
}
}
Toast
.
makeText
(
context
,
"Tile uninstallation error"
,
Toast
.
LENGTH_SHORT
).
show
();
Toast
.
makeText
(
context
,
"Tile uninstallation error"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
private
static
void
refreshService
(
Context
context
)
{
private
static
void
refreshService
(
Context
context
)
{
context
.
startService
(
new
Intent
(
context
,
TileServiceCompat
.
class
));
context
.
startService
(
new
Intent
(
context
,
TileServiceCompat
.
class
));
}
}
public
static
void
UpdateRootFragmentUI
(
Context
context
)
{
public
static
void
UpdateRootFragmentUI
(
Context
context
)
{
Logger
.
dh
(
"Magisk"
,
"Utils: UpdateRF called"
);
Logger
.
dh
(
"Magisk"
,
"Utils: UpdateRF called"
);
Intent
intent
=
new
Intent
(
context
,
RootFragment
.
class
);
Intent
intent
=
new
Intent
(
context
,
RootFragment
.
class
);
intent
.
setAction
(
"com.magisk.UPDATE
UI
"
);
intent
.
setAction
(
"com.magisk.UPDATE"
);
context
.
sendBroadcast
(
intent
);
context
.
sendBroadcast
(
intent
);
}
}
...
@@ -453,7 +477,6 @@ public class Utils {
...
@@ -453,7 +477,6 @@ public class Utils {
public
abstract
void
task
(
File
file
);
public
abstract
void
task
(
File
file
);
}
}
public
static
boolean
isMyServiceRunning
(
Class
<?>
serviceClass
,
Context
context
)
{
public
static
boolean
isMyServiceRunning
(
Class
<?>
serviceClass
,
Context
context
)
{
ActivityManager
manager
=
(
ActivityManager
)
context
.
getSystemService
(
Context
.
ACTIVITY_SERVICE
);
ActivityManager
manager
=
(
ActivityManager
)
context
.
getSystemService
(
Context
.
ACTIVITY_SERVICE
);
for
(
ActivityManager
.
RunningServiceInfo
service
:
manager
.
getRunningServices
(
Integer
.
MAX_VALUE
))
{
for
(
ActivityManager
.
RunningServiceInfo
service
:
manager
.
getRunningServices
(
Integer
.
MAX_VALUE
))
{
...
...
app/src/main/res/layout/root_fragment.xml
View file @
5b2dce6c
...
@@ -48,8 +48,8 @@
...
@@ -48,8 +48,8 @@
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_margin=
"12dp"
android:layout_margin=
"12dp"
android:checked=
"
tru
e"
android:checked=
"
fals
e"
android:text=
"@string/auto_
root
"
android:text=
"@string/auto_
toggle
"
android:textSize=
"16sp"
/>
android:textSize=
"16sp"
/>
</android.support.v7.widget.CardView>
</android.support.v7.widget.CardView>
...
...
app/src/main/res/layout/settings_fragment.xml
deleted
100644 → 0
View file @
bee9be53
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_height=
"fill_parent"
android:layout_marginBottom=
"8dp"
android:layout_marginTop=
"?attr/actionBarSize"
android:layout_width=
"fill_parent"
>
<PreferenceCategory
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
</PreferenceCategory>
<PreferenceCategory
android:title=
"Test"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<CheckBoxPreference
android:key=
"checkbox_preference"
android:title=
"Pref1"
android:defaultValue=
"Foo"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
<EditTextPreference
android:key=
"edittext_preference"
android:title=
"TextPref"
android:summary=
"This is the summary"
android:dialogTitle=
"Dialog Title"
android:dependency=
"checkbox_preference"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
</PreferenceCategory>
<PreferenceCategory
android:title=
"Section 2"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<Preference
android:title=
"Intent Pref"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<intent
android:action=
"android.intent.action.VIEW"
android:data=
"http://codepath.com/"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
</Preference>
</PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
app/src/main/res/menu/drawer.xml
View file @
5b2dce6c
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
<item
<item
android:id=
"@+id/autoroot"
android:id=
"@+id/autoroot"
android:icon=
"@drawable/ic_autoroot"
android:icon=
"@drawable/ic_autoroot"
android:title=
"@string/auto_toggle"
/>
android:title=
"@string/auto_toggle
_apps
"
/>
<item
<item
android:id=
"@+id/modules"
android:id=
"@+id/modules"
...
...
app/src/main/res/values/strings.xml
View file @
5b2dce6c
...
@@ -124,4 +124,7 @@
...
@@ -124,4 +124,7 @@
<!--General Use -->
<!--General Use -->
<string
name=
"auto_toggle"
>
Auto-toggle
</string>
<string
name=
"auto_toggle"
>
Auto-toggle
</string>
<string
name=
"auto_toggle_apps"
>
Auto-toggle List
</string>
<string
name=
"toast_error_makedir"
>
Error creating directory, could not download file.
</string>
<string
name=
"toast_error_removing_files"
>
Error removing old files, cancelled.
</string>
</resources>
</resources>
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