diff --git a/app/build.gradle b/app/build.gradle
index bf6e15e12..882747298 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
defaultConfig {
applicationId "com.topjohnwu.magisk"
- minSdkVersion 21
targetSdkVersion rootProject.ext.compileSdkVersion
+ vectorDrawables.useSupportLibrary = true
}
signingConfigs {
@@ -41,6 +41,7 @@ android {
productFlavors {
full {
+ minSdkVersion 21
versionName configProps['appVersion']
versionCode configProps['appVersionCode'] as Integer
javaCompileOptions {
@@ -50,6 +51,7 @@ android {
}
}
stub {
+ minSdkVersion 17
versionCode 1
versionName "stub"
}
diff --git a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java
index 344eb0f37..df17e2d2a 100644
--- a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java
+++ b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java
@@ -20,7 +20,7 @@ import com.topjohnwu.magisk.fragments.ModulesFragment;
import com.topjohnwu.magisk.fragments.ReposFragment;
import com.topjohnwu.magisk.fragments.SettingsFragment;
import com.topjohnwu.magisk.fragments.SuperuserFragment;
-import com.topjohnwu.magisk.utils.Download;
+import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import androidx.annotation.NonNull;
@@ -124,7 +124,7 @@ public class MainActivity extends BaseActivity
menu.findItem(R.id.magiskhide).setVisible(Shell.rootAccess() &&
app.prefs.getBoolean(Const.Key.MAGISKHIDE, false));
menu.findItem(R.id.modules).setVisible(Shell.rootAccess() && Data.magiskVersionCode >= 0);
- menu.findItem(R.id.downloads).setVisible(Download.checkNetworkStatus(this)
+ menu.findItem(R.id.downloads).setVisible(Networking.checkNetworkStatus(this)
&& Shell.rootAccess() && Data.magiskVersionCode >= 0);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(Utils.showSuperUser());
diff --git a/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java b/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java
index fb8e7cac7..efeca53b2 100644
--- a/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java
+++ b/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java
@@ -15,7 +15,7 @@ import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.Notifications;
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
import com.topjohnwu.magisk.utils.AppUtils;
-import com.topjohnwu.magisk.utils.Download;
+import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
public class SplashActivity extends BaseActivity {
@@ -56,7 +56,7 @@ public class SplashActivity extends BaseActivity {
// Setup shortcuts
sendBroadcast(new Intent(this, ClassMap.get(ShortcutReceiver.class)));
- if (Download.checkNetworkStatus(this)) {
+ if (Networking.checkNetworkStatus(this)) {
// Fire update check
CheckUpdates.check();
// Repo update check
diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java
index 2104f1d42..5f45eabdb 100644
--- a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java
+++ b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java
@@ -32,7 +32,7 @@ import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.MagiskInstallDialog;
import com.topjohnwu.magisk.components.ManagerInstallDialog;
import com.topjohnwu.magisk.components.UninstallDialog;
-import com.topjohnwu.magisk.utils.Download;
+import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils;
@@ -169,7 +169,7 @@ public class MagiskFragment extends BaseFragment
shownDialog = false;
// Trigger state check
- if (Download.checkNetworkStatus(app)) {
+ if (Networking.checkNetworkStatus(app)) {
CheckUpdates.check();
} else {
mSwipeRefreshLayout.setRefreshing(false);
@@ -212,7 +212,7 @@ public class MagiskFragment extends BaseFragment
private void updateUI() {
((MainActivity) requireActivity()).checkHideSection();
- boolean hasNetwork = Download.checkNetworkStatus(app);
+ boolean hasNetwork = Networking.checkNetworkStatus(app);
boolean hasRoot = Shell.rootAccess();
magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java
index 137b9310c..84ef33fd4 100644
--- a/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java
+++ b/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java
@@ -20,10 +20,10 @@ import com.topjohnwu.core.utils.Utils;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.AppUtils;
-import com.topjohnwu.magisk.utils.Download;
import com.topjohnwu.magisk.utils.DownloadApp;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.PatchAPK;
+import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.io.IOException;
@@ -155,7 +155,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
if (app.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
generalCatagory.removePreference(restoreManager);
} else {
- if (!Download.checkNetworkStatus(app))
+ if (!Networking.checkNetworkStatus(app))
generalCatagory.removePreference(restoreManager);
generalCatagory.removePreference(hideManager);
}
diff --git a/app/src/main/res/drawable-v26/ic_launcher.xml b/app/src/full/res/drawable-v26/ic_launcher.xml
similarity index 100%
rename from app/src/main/res/drawable-v26/ic_launcher.xml
rename to app/src/full/res/drawable-v26/ic_launcher.xml
diff --git a/app/src/main/res/drawable/ic_magisk_padded.xml b/app/src/full/res/drawable/ic_magisk_padded.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_magisk_padded.xml
rename to app/src/full/res/drawable/ic_magisk_padded.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 79f8345f9..17f5675a4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,8 +4,6 @@
package="com.topjohnwu.magisk">
-
-
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Download.java b/app/src/main/java/com/topjohnwu/magisk/utils/Download.java
deleted file mode 100644
index 91002ad8c..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/utils/Download.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.topjohnwu.magisk.utils;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-
-public class Download {
-
- public static boolean checkNetworkStatus(Context context) {
- ConnectivityManager manager = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = manager.getActiveNetworkInfo();
- return networkInfo != null && networkInfo.isConnected();
- }
-}
diff --git a/app/src/main/res/values/drawables.xml b/app/src/main/res/values-v21/drawables.xml
similarity index 100%
rename from app/src/main/res/values/drawables.xml
rename to app/src/main/res/values-v21/drawables.xml
diff --git a/app/src/stub/java/com/topjohnwu/magisk/MainActivity.java b/app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
index 64b081d06..93ee2ec1f 100644
--- a/app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
+++ b/app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
@@ -6,7 +6,6 @@ import android.app.Application;
import android.os.Bundle;
import com.topjohnwu.magisk.utils.APKInstall;
-import com.topjohnwu.magisk.utils.Download;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.ResponseListener;
@@ -32,7 +31,8 @@ public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (Download.checkNetworkStatus(this)) {
+ Networking.init(this);
+ if (Networking.checkNetworkStatus(this)) {
Networking.get(URL)
.setErrorHandler(((conn, e) -> finish()))
.getAsJSONObject(new JSONLoader());
diff --git a/app/src/stub/res/values/drawables.xml b/app/src/stub/res/values/drawables.xml
new file mode 100644
index 000000000..5242b5d7d
--- /dev/null
+++ b/app/src/stub/res/values/drawables.xml
@@ -0,0 +1,4 @@
+
+
+ @android:drawable/sym_def_app_icon
+
\ No newline at end of file
diff --git a/core/src/main/java/com/topjohnwu/core/App.java b/core/src/main/java/com/topjohnwu/core/App.java
index b133768f4..a07d7274e 100644
--- a/core/src/main/java/com/topjohnwu/core/App.java
+++ b/core/src/main/java/com/topjohnwu/core/App.java
@@ -12,6 +12,7 @@ import com.topjohnwu.core.database.MagiskDB;
import com.topjohnwu.core.database.RepoDatabaseHelper;
import com.topjohnwu.core.utils.LocaleManager;
import com.topjohnwu.core.utils.RootUtils;
+import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.ContainerApp;
import com.topjohnwu.superuser.Shell;
@@ -46,6 +47,7 @@ public class App extends ContainerApp {
mDB = new MagiskDB(this);
repoDB = new RepoDatabaseHelper(this);
+ Networking.init(this);
LocaleManager.setLocale(this);
Data.loadConfig();
}
diff --git a/net/src/main/AndroidManifest.xml b/net/src/main/AndroidManifest.xml
index b8128f247..8a07fd122 100644
--- a/net/src/main/AndroidManifest.xml
+++ b/net/src/main/AndroidManifest.xml
@@ -1,2 +1,5 @@
+ package="com.topjohnwu.net">
+
+
+
diff --git a/net/src/main/java/com/topjohnwu/net/Networking.java b/net/src/main/java/com/topjohnwu/net/Networking.java
index fb4a7630e..d55f80eb5 100644
--- a/net/src/main/java/com/topjohnwu/net/Networking.java
+++ b/net/src/main/java/com/topjohnwu/net/Networking.java
@@ -1,12 +1,17 @@
package com.topjohnwu.net;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
-import java.util.concurrent.ExecutorService;
+
+import javax.net.ssl.HttpsURLConnection;
public class Networking {
@@ -30,4 +35,26 @@ public class Networking {
return request(url, "GET");
}
+ public static void init(Context context) {
+ try {
+ // Try installing new SSL provider from Google Play Service
+ Context gms = context.createPackageContext("com.google.android.gms",
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ gms.getClassLoader()
+ .loadClass("com.google.android.gms.common.security.ProviderInstallerImpl")
+ .getMethod("insertProvider", Context.class)
+ .invoke(null, context);
+ } catch (Exception e) {
+ // Failed to update SSL provider, use NoSSLv3SocketFactory on SDK < 21
+ if (Build.VERSION.SDK_INT < 21)
+ HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3SocketFactory());
+ }
+ }
+
+ public static boolean checkNetworkStatus(Context context) {
+ ConnectivityManager manager = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = manager.getActiveNetworkInfo();
+ return networkInfo != null && networkInfo.isConnected();
+ }
}
diff --git a/net/src/main/java/com/topjohnwu/net/NoSSLv3SocketFactory.java b/net/src/main/java/com/topjohnwu/net/NoSSLv3SocketFactory.java
new file mode 100644
index 000000000..5af965938
--- /dev/null
+++ b/net/src/main/java/com/topjohnwu/net/NoSSLv3SocketFactory.java
@@ -0,0 +1,70 @@
+package com.topjohnwu.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+class NoSSLv3SocketFactory extends SSLSocketFactory {
+
+ private final static SSLSocketFactory base = HttpsURLConnection.getDefaultSSLSocketFactory();
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return base.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return base.getSupportedCipherSuites();
+ }
+
+ private Socket createSafeSocket(Socket socket) {
+ if (socket instanceof SSLSocket)
+ return new SSLSocketWrapper((SSLSocket) socket) {
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ List proto = new ArrayList<>(Arrays.asList(getSupportedProtocols()));
+ proto.remove("SSLv3");
+ super.setEnabledProtocols(proto.toArray(new String[0]));
+ }
+ };
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
+ return createSafeSocket(base.createSocket(s, host, port, autoClose));
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ return createSafeSocket(base.createSocket());
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ return createSafeSocket(base.createSocket(host, port));
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+ return createSafeSocket(base.createSocket(host, port, localHost, localPort));
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return createSafeSocket(base.createSocket(host, port));
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
+ return createSafeSocket(base.createSocket(address, port, localAddress, localPort));
+ }
+}
diff --git a/net/src/main/java/com/topjohnwu/net/SSLSocketWrapper.java b/net/src/main/java/com/topjohnwu/net/SSLSocketWrapper.java
new file mode 100644
index 000000000..a86759c17
--- /dev/null
+++ b/net/src/main/java/com/topjohnwu/net/SSLSocketWrapper.java
@@ -0,0 +1,333 @@
+package com.topjohnwu.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+class SSLSocketWrapper extends SSLSocket {
+
+ private SSLSocket mBase;
+
+ SSLSocketWrapper(SSLSocket socket) {
+ mBase = socket;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return mBase.getSupportedCipherSuites();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return mBase.getEnabledCipherSuites();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ mBase.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ return mBase.getSupportedProtocols();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ return mBase.getEnabledProtocols();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ mBase.setEnabledProtocols(protocols);
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return mBase.getSession();
+ }
+
+ @Override
+ public SSLSession getHandshakeSession() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ mBase.addHandshakeCompletedListener(listener);
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ mBase.removeHandshakeCompletedListener(listener);
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ mBase.startHandshake();
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ mBase.setUseClientMode(mode);
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ return mBase.getUseClientMode();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ mBase.setNeedClientAuth(need);
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ return mBase.getNeedClientAuth();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ mBase.setWantClientAuth(want);
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ return mBase.getWantClientAuth();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ mBase.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ return mBase.getEnableSessionCreation();
+ }
+
+ @Override
+ public SSLParameters getSSLParameters() {
+ return mBase.getSSLParameters();
+ }
+
+ @Override
+ public void setSSLParameters(SSLParameters params) {
+ mBase.setSSLParameters(params);
+ }
+
+ @Override
+ public String toString() {
+ return mBase.toString();
+ }
+
+ @Override
+ public void connect(SocketAddress endpoint) throws IOException {
+ mBase.connect(endpoint);
+ }
+
+ @Override
+ public void connect(SocketAddress endpoint, int timeout) throws IOException {
+ mBase.connect(endpoint, timeout);
+ }
+
+ @Override
+ public void bind(SocketAddress bindpoint) throws IOException {
+ mBase.bind(bindpoint);
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ return mBase.getInetAddress();
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ return mBase.getLocalAddress();
+ }
+
+ @Override
+ public int getPort() {
+ return mBase.getPort();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return mBase.getLocalPort();
+ }
+
+ @Override
+ public SocketAddress getRemoteSocketAddress() {
+ return mBase.getRemoteSocketAddress();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ return mBase.getLocalSocketAddress();
+ }
+
+ @Override
+ public SocketChannel getChannel() {
+ return mBase.getChannel();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return mBase.getInputStream();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return mBase.getOutputStream();
+ }
+
+ @Override
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ mBase.setTcpNoDelay(on);
+ }
+
+ @Override
+ public boolean getTcpNoDelay() throws SocketException {
+ return mBase.getTcpNoDelay();
+ }
+
+ @Override
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ mBase.setSoLinger(on, linger);
+ }
+
+ @Override
+ public int getSoLinger() throws SocketException {
+ return mBase.getSoLinger();
+ }
+
+ @Override
+ public void sendUrgentData(int data) throws IOException {
+ mBase.sendUrgentData(data);
+ }
+
+ @Override
+ public void setOOBInline(boolean on) throws SocketException {
+ mBase.setOOBInline(on);
+ }
+
+ @Override
+ public boolean getOOBInline() throws SocketException {
+ return mBase.getOOBInline();
+ }
+
+ @Override
+ public void setSoTimeout(int timeout) throws SocketException {
+ mBase.setSoTimeout(timeout);
+ }
+
+ @Override
+ public int getSoTimeout() throws SocketException {
+ return mBase.getSoTimeout();
+ }
+
+ @Override
+ public void setSendBufferSize(int size) throws SocketException {
+ mBase.setSendBufferSize(size);
+ }
+
+ @Override
+ public int getSendBufferSize() throws SocketException {
+ return mBase.getSendBufferSize();
+ }
+
+ @Override
+ public void setReceiveBufferSize(int size) throws SocketException {
+ mBase.setReceiveBufferSize(size);
+ }
+
+ @Override
+ public int getReceiveBufferSize() throws SocketException {
+ return mBase.getReceiveBufferSize();
+ }
+
+ @Override
+ public void setKeepAlive(boolean on) throws SocketException {
+ mBase.setKeepAlive(on);
+ }
+
+ @Override
+ public boolean getKeepAlive() throws SocketException {
+ return mBase.getKeepAlive();
+ }
+
+ @Override
+ public void setTrafficClass(int tc) throws SocketException {
+ mBase.setTrafficClass(tc);
+ }
+
+ @Override
+ public int getTrafficClass() throws SocketException {
+ return mBase.getTrafficClass();
+ }
+
+ @Override
+ public void setReuseAddress(boolean on) throws SocketException {
+ mBase.setReuseAddress(on);
+ }
+
+ @Override
+ public boolean getReuseAddress() throws SocketException {
+ return mBase.getReuseAddress();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mBase.close();
+ }
+
+ @Override
+ public void shutdownInput() throws IOException {
+ mBase.shutdownInput();
+ }
+
+ @Override
+ public void shutdownOutput() throws IOException {
+ mBase.shutdownOutput();
+ }
+
+ @Override
+ public boolean isConnected() {
+ return mBase.isConnected();
+ }
+
+ @Override
+ public boolean isBound() {
+ return mBase.isBound();
+ }
+
+ @Override
+ public boolean isClosed() {
+ return mBase.isClosed();
+ }
+
+ @Override
+ public boolean isInputShutdown() {
+ return mBase.isInputShutdown();
+ }
+
+ @Override
+ public boolean isOutputShutdown() {
+ return mBase.isOutputShutdown();
+ }
+
+ @Override
+ public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
+ mBase.setPerformancePreferences(connectionTime, latency, bandwidth);
+ }
+}