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 + + +