diff --git a/app/build.gradle b/app/build.gradle
index 83cbdb7fa..492c62d1e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,7 +8,7 @@ android {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 27
- versionCode 69
+ versionCode 70
versionName "5.4.3"
ndk {
moduleName 'zipadjust'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 769e0458d..8f9062b02 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -52,11 +52,6 @@
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity="internal.superuser"
- android:theme="@android:style/Theme.NoDisplay" />
-
diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md
index 7560f34a0..fbb699fc2 100644
--- a/app/src/main/assets/changelog.md
+++ b/app/src/main/assets/changelog.md
@@ -1,6 +1,7 @@
-### v5.4.3 (69)
+### v5.4.3 (70)
- Fix dynamic resource loading, should prevent crashing when checking SafetyNet
- Update SignAPK to use very little RAM, should expand old device support
- Support settings migration after hiding Magisk Manager
- Add reboot menu in modules section
- Add changelog in app
+- Add dark theme to superuser requests
\ No newline at end of file
diff --git a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java
index bc2dc5b4b..fb185f76b 100644
--- a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java
@@ -31,6 +31,11 @@ public class AboutActivity extends Activity {
@BindView(R.id.support_thread) AboutCardRow supportThread;
@BindView(R.id.donation) AboutCardRow donation;
+ @Override
+ public int getDarkTheme() {
+ return R.style.AppTheme_Transparent_Dark;
+ }
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
index 83b329722..e84363e65 100644
--- a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java
@@ -75,6 +75,11 @@ public class FlashActivity extends Activity {
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
}
+ @Override
+ public int getDarkTheme() {
+ return R.style.AppTheme_Transparent_Dark;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java
index 8d5746a8a..c99b47aa6 100644
--- a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java
@@ -42,6 +42,11 @@ public class MainActivity extends Activity
private float toolbarElevation;
+ @Override
+ public int getDarkTheme() {
+ return R.style.AppTheme_Dark;
+ }
+
@Override
protected void onCreate(final Bundle savedInstanceState) {
diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java
index 9515fdeed..657cbcdbd 100644
--- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java
@@ -35,6 +35,11 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
@BindView(R.id.toolbar) Toolbar toolbar;
+ @Override
+ public int getDarkTheme() {
+ return R.style.AppTheme_Transparent_Dark;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java
index dca4bac66..d81889565 100644
--- a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java
@@ -25,6 +25,11 @@ import java.util.List;
public class SplashActivity extends Activity {
+ @Override
+ public int getDarkTheme() {
+ return -1;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java
index 575cb4a55..68c5a7e40 100644
--- a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java
@@ -9,6 +9,7 @@ import android.os.Bundle;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
import android.support.v7.app.AppCompatActivity;
import android.view.WindowManager;
@@ -17,7 +18,7 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
-public class Activity extends AppCompatActivity {
+public abstract class Activity extends AppCompatActivity {
private AssetManager swappedAssetManager = null;
private Resources swappedResources = null;
@@ -31,14 +32,17 @@ public class Activity extends AppCompatActivity {
applyOverrideConfiguration(configuration);
}
+ @StyleRes
+ abstract public int getDarkTheme();
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (this instanceof Topic.Subscriber) {
((Topic.Subscriber) this).subscribeTopics();
}
- if (getMagiskManager().isDarkTheme) {
- setTheme(R.style.AppTheme_Dark);
+ if (getMagiskManager().isDarkTheme && getDarkTheme() > 0) {
+ setTheme(getDarkTheme());
}
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/superuser/RequestActivity.java b/app/src/main/java/com/topjohnwu/magisk/superuser/RequestActivity.java
index 2da12825c..59233059d 100644
--- a/app/src/main/java/com/topjohnwu/magisk/superuser/RequestActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/superuser/RequestActivity.java
@@ -1,24 +1,240 @@
package com.topjohnwu.magisk.superuser;
+import android.content.ContentValues;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.os.FileObserver;
+import android.text.TextUtils;
+import android.view.Window;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+import com.topjohnwu.magisk.MagiskManager;
+import com.topjohnwu.magisk.R;
+import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Activity;
+import com.topjohnwu.magisk.container.Policy;
+import com.topjohnwu.magisk.utils.Const;
+import com.topjohnwu.magisk.utils.Utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
public class RequestActivity extends Activity {
+ @BindView(R.id.su_popup) LinearLayout suPopup;
+ @BindView(R.id.timeout) Spinner timeout;
+ @BindView(R.id.app_icon) ImageView appIcon;
+ @BindView(R.id.app_name) TextView appNameView;
+ @BindView(R.id.package_name) TextView packageNameView;
+ @BindView(R.id.grant_btn) Button grant_btn;
+ @BindView(R.id.deny_btn) Button deny_btn;
+
+ private String socketPath;
+ private LocalSocket socket;
+ private PackageManager pm;
+ private MagiskManager mm;
+
+ private boolean hasTimeout;
+ private Policy policy;
+ private CountDownTimer timer;
+
+ @Override
+ public int getDarkTheme() {
+ return R.style.SuRequest_Dark;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ pm = getPackageManager();
+ mm = Utils.getMagiskManager(this);
Intent intent = getIntent();
- if (intent == null) {
- finish();
+ socketPath = intent.getStringExtra("socket");
+ hasTimeout = intent.getBooleanExtra("timeout", true);
+
+ new FileObserver(socketPath) {
+ @Override
+ public void onEvent(int fileEvent, String path) {
+ if (fileEvent == FileObserver.DELETE_SELF) {
+ finish();
+ }
+ }
+ }.startWatching();
+
+ new SocketManager(this).exec();
+ }
+
+ private boolean cancelTimeout() {
+ timer.cancel();
+ deny_btn.setText(getString(R.string.deny));
+ return false;
+ }
+
+ private void showRequest() {
+ switch (mm.suResponseType) {
+ case Const.Value.SU_AUTO_DENY:
+ handleAction(Policy.DENY, 0);
+ return;
+ case Const.Value.SU_AUTO_ALLOW:
+ handleAction(Policy.ALLOW, 0);
+ return;
+ case Const.Value.SU_PROMPT:
+ default:
+ }
+
+ // If not interactive, response directly
+ if (policy.policy != Policy.INTERACTIVE) {
+ handleAction();
return;
}
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
- startActivity(intent);
+ setContentView(R.layout.activity_request);
+ ButterKnife.bind(this);
+
+ appIcon.setImageDrawable(policy.info.loadIcon(pm));
+ appNameView.setText(policy.appName);
+ packageNameView.setText(policy.packageName);
+
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
+ R.array.allow_timeout, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ timeout.setAdapter(adapter);
+
+ timer = new CountDownTimer(mm.suRequestTimeout * 1000, 1000) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
+ }
+ @Override
+ public void onFinish() {
+ deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
+ handleAction(Policy.DENY);
+ }
+ };
+
+ grant_btn.setOnClickListener(v -> {
+ handleAction(Policy.ALLOW);
+ timer.cancel();
+ });
+ deny_btn.setOnClickListener(v -> {
+ handleAction(Policy.DENY);
+ timer.cancel();
+ });
+ suPopup.setOnClickListener(v -> cancelTimeout());
+ timeout.setOnTouchListener((v, event) -> cancelTimeout());
+
+ if (hasTimeout) {
+ timer.start();
+ } else {
+ cancelTimeout();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (policy != null) {
+ handleAction(Policy.DENY);
+ }
finish();
}
+
+ void handleAction() {
+ String response;
+ if (policy.policy == Policy.ALLOW) {
+ response = "socket:ALLOW";
+ } else {
+ response = "socket:DENY";
+ }
+ try {
+ socket.getOutputStream().write((response).getBytes());
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ finish();
+ }
+
+ void handleAction(int action) {
+ handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
+ }
+
+ void handleAction(int action, int time) {
+ policy.policy = action;
+ if (time >= 0) {
+ policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
+ mm.suDB.addPolicy(policy);
+ }
+ handleAction();
+ }
+
+ private class SocketManager extends ParallelTask {
+
+ SocketManager(Activity context) {
+ super(context);
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ socket = new LocalSocket();
+ socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
+
+ DataInputStream is = new DataInputStream(socket.getInputStream());
+ ContentValues payload = new ContentValues();
+
+ while (true) {
+ int nameLen = is.readInt();
+ byte[] nameBytes = new byte[nameLen];
+ is.readFully(nameBytes);
+ String name = new String(nameBytes);
+ if (TextUtils.equals(name, "eof"))
+ break;
+
+ int dataLen = is.readInt();
+ byte[] dataBytes = new byte[dataLen];
+ is.readFully(dataBytes);
+ String data = new String(dataBytes);
+ payload.put(name, data);
+ }
+
+ if (payload.getAsInteger("uid") == null) {
+ return false;
+ }
+
+ int uid = payload.getAsInteger("uid");
+ policy = mm.suDB.getPolicy(uid);
+ if (policy == null) {
+ policy = new Policy(uid, pm);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (result) {
+ showRequest();
+ } else {
+ finish();
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java b/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java
deleted file mode 100644
index 294362daa..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java
+++ /dev/null
@@ -1,234 +0,0 @@
-package com.topjohnwu.magisk.superuser;
-
-import android.content.ContentValues;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.os.FileObserver;
-import android.text.TextUtils;
-import android.view.Window;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.topjohnwu.magisk.MagiskManager;
-import com.topjohnwu.magisk.R;
-import com.topjohnwu.magisk.asyncs.ParallelTask;
-import com.topjohnwu.magisk.components.Activity;
-import com.topjohnwu.magisk.container.Policy;
-import com.topjohnwu.magisk.utils.Const;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-
-public class SuRequestActivity extends Activity {
-
- @BindView(R.id.su_popup) LinearLayout suPopup;
- @BindView(R.id.timeout) Spinner timeout;
- @BindView(R.id.app_icon) ImageView appIcon;
- @BindView(R.id.app_name) TextView appNameView;
- @BindView(R.id.package_name) TextView packageNameView;
- @BindView(R.id.grant_btn) Button grant_btn;
- @BindView(R.id.deny_btn) Button deny_btn;
-
- private String socketPath;
- private LocalSocket socket;
- private PackageManager pm;
- private MagiskManager mm;
-
- private boolean hasTimeout;
- private Policy policy;
- private CountDownTimer timer;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-
- pm = getPackageManager();
- mm = getMagiskManager();
-
- Intent intent = getIntent();
- socketPath = intent.getStringExtra("socket");
- hasTimeout = intent.getBooleanExtra("timeout", true);
-
- new FileObserver(socketPath) {
- @Override
- public void onEvent(int fileEvent, String path) {
- if (fileEvent == FileObserver.DELETE_SELF) {
- finish();
- }
- }
- }.startWatching();
-
- new SocketManager(this).exec();
- }
-
- private boolean cancelTimeout() {
- timer.cancel();
- deny_btn.setText(getString(R.string.deny));
- return false;
- }
-
- private void showRequest() {
- switch (mm.suResponseType) {
- case Const.Value.SU_AUTO_DENY:
- handleAction(Policy.DENY, 0);
- return;
- case Const.Value.SU_AUTO_ALLOW:
- handleAction(Policy.ALLOW, 0);
- return;
- case Const.Value.SU_PROMPT:
- default:
- }
-
- // If not interactive, response directly
- if (policy.policy != Policy.INTERACTIVE) {
- handleAction();
- return;
- }
-
- setContentView(R.layout.activity_request);
- ButterKnife.bind(this);
-
- appIcon.setImageDrawable(policy.info.loadIcon(pm));
- appNameView.setText(policy.appName);
- packageNameView.setText(policy.packageName);
-
- ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
- R.array.allow_timeout, android.R.layout.simple_spinner_item);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- timeout.setAdapter(adapter);
-
- timer = new CountDownTimer(mm.suRequestTimeout * 1000, 1000) {
- @Override
- public void onTick(long millisUntilFinished) {
- deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
- }
- @Override
- public void onFinish() {
- deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
- handleAction(Policy.DENY);
- }
- };
-
- grant_btn.setOnClickListener(v -> {
- handleAction(Policy.ALLOW);
- timer.cancel();
- });
- deny_btn.setOnClickListener(v -> {
- handleAction(Policy.DENY);
- timer.cancel();
- });
- suPopup.setOnClickListener(v -> cancelTimeout());
- timeout.setOnTouchListener((v, event) -> cancelTimeout());
-
- if (hasTimeout) {
- timer.start();
- } else {
- cancelTimeout();
- }
- }
-
- @Override
- public void onBackPressed() {
- if (policy != null) {
- handleAction(Policy.DENY);
- }
- finish();
- }
-
- void handleAction() {
- String response;
- if (policy.policy == Policy.ALLOW) {
- response = "socket:ALLOW";
- } else {
- response = "socket:DENY";
- }
- try {
- socket.getOutputStream().write((response).getBytes());
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- finish();
- }
-
- void handleAction(int action) {
- handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
- }
-
- void handleAction(int action, int time) {
- policy.policy = action;
- if (time >= 0) {
- policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
- mm.suDB.addPolicy(policy);
- }
- handleAction();
- }
-
- private class SocketManager extends ParallelTask {
-
- SocketManager(Activity context) {
- super(context);
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- try {
- socket = new LocalSocket();
- socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
-
- DataInputStream is = new DataInputStream(socket.getInputStream());
- ContentValues payload = new ContentValues();
-
- while (true) {
- int nameLen = is.readInt();
- byte[] nameBytes = new byte[nameLen];
- is.readFully(nameBytes);
- String name = new String(nameBytes);
- if (TextUtils.equals(name, "eof"))
- break;
-
- int dataLen = is.readInt();
- byte[] dataBytes = new byte[dataLen];
- is.readFully(dataBytes);
- String data = new String(dataBytes);
- payload.put(name, data);
- }
-
- if (payload.getAsInteger("uid") == null) {
- return false;
- }
-
- int uid = payload.getAsInteger("uid");
- policy = mm.suDB.getPolicy(uid);
- if (policy == null) {
- policy = new Policy(uid, pm);
- }
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (result) {
- showRequest();
- } else {
- finish();
- }
- }
- }
-}
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index daa46e24a..d498585f4 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -42,7 +42,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
- android:src="@mipmap/ic_launcher"/>
+ android:src="@mipmap/ic_launcher_round"/>
+ android:orientation="vertical"
+ android:background="?attr/colorBackgroundFloating">
- false
- - @color/su_request_background
+ - @color/su_request_background
+
+
+