diff --git a/common/build.gradle b/common/build.gradle
index e3350724..a488f0fa 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -32,6 +32,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
+ implementation 'com.linkedin.dexmaker:dexmaker:2.28.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
diff --git a/common/src/main/java/com/xypower/common/HotspotManager.java b/common/src/main/java/com/xypower/common/HotspotManager.java
new file mode 100644
index 00000000..c233d28c
--- /dev/null
+++ b/common/src/main/java/com/xypower/common/HotspotManager.java
@@ -0,0 +1,248 @@
+package com.xypower.common;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.os.Handler;
+import androidx.annotation.RequiresApi;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.dx.stock.ProxyBuilder;
+
+import java.io.File;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+
+public class HotspotManager {
+
+
+
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ public static class OreoWifiManager {
+ private static final String TAG = OreoWifiManager.class.getSimpleName();
+
+ private Context mContext;
+ private WifiManager mWifiManager;
+ private ConnectivityManager mConnectivityManager;
+
+ public OreoWifiManager(Context c) {
+ mContext = c;
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mConnectivityManager = (ConnectivityManager) mContext.getSystemService(ConnectivityManager.class);
+ }
+
+ /**
+ * This sets the Wifi SSID and password
+ * Call this before {@code startTethering} if app is a system/privileged app
+ * Requires: android.permission.TETHER_PRIVILEGED which is only granted to system apps
+ */
+ public void configureHotspot(String name, String password) {
+ WifiConfiguration apConfig = new WifiConfiguration();
+ apConfig.SSID = name;
+ apConfig.preSharedKey = password;
+ apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ try {
+ Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
+ boolean status = (boolean) setConfigMethod.invoke(mWifiManager, apConfig);
+ Log.d(TAG, "setWifiApConfiguration - success? " + status);
+ } catch (Exception e) {
+ Log.e(TAG, "Error in configureHotspot");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Checks where tethering is on.
+ * This is determined by the getTetheredIfaces() method,
+ * that will return an empty array if not devices are tethered
+ *
+ * @return true if a tethered device is found, false if not found
+ */
+ /*public boolean isTetherActive() {
+ try {
+ Method method = mConnectivityManager.getClass().getDeclaredMethod("getTetheredIfaces");
+ if (method == null) {
+ Log.e(TAG, "getTetheredIfaces is null");
+ } else {
+ String res[] = (String[]) method.invoke(mConnectivityManager, null);
+ Log.d(TAG, "getTetheredIfaces invoked");
+ Log.d(TAG, Arrays.toString(res));
+ if (res.length > 0) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error in getTetheredIfaces");
+ e.printStackTrace();
+ }
+ return false;
+ }
+*/
+ /**
+ * This enables tethering using the ssid/password defined in Settings App>Hotspot & tethering
+ * Does not require app to have system/privileged access
+ * Credit: Vishal Sharma - https://stackoverflow.com/a/52219887
+ */
+ public boolean startTethering(final OnStartTetheringCallback callback) {
+
+ // On Pie if we try to start tethering while it is already on, it will
+ // be disabled. This is needed when startTethering() is called programmatically.
+ /*if (isTetherActive()) {
+ Log.d(TAG, "Tether already active, returning");
+ return false;
+ }*/
+
+ File outputDir = mContext.getCodeCacheDir();
+ Object proxy;
+ try {
+ proxy = ProxyBuilder.forClass(OnStartTetheringCallbackClass())
+ .dexCache(outputDir).handler(new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ switch (method.getName()) {
+ case "onTetheringStarted":
+ callback.onTetheringStarted();
+ break;
+ case "onTetheringFailed":
+ callback.onTetheringFailed();
+ break;
+ default:
+ ProxyBuilder.callSuper(proxy, method, args);
+ }
+ return null;
+ }
+
+ }).build();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in enableTethering ProxyBuilder");
+ e.printStackTrace();
+ return false;
+ }
+
+ Method method = null;
+ try {
+ method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
+ if (method == null) {
+ Log.e(TAG, "startTetheringMethod is null");
+ } else {
+ method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
+ Log.d(TAG, "startTethering invoked");
+ }
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Error in enableTethering");
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public void stopTethering() {
+ try {
+ Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
+ if (method == null) {
+ Log.e(TAG, "stopTetheringMethod is null");
+ } else {
+ method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
+ Log.d(TAG, "stopTethering invoked");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "stopTethering error: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ private Class OnStartTetheringCallbackClass() {
+ try {
+ return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "OnStartTetheringCallbackClass error: " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+
+ public static abstract class OnStartTetheringCallback {
+ /**
+ * Called when tethering has been successfully started.
+ */
+ public abstract void onTetheringStarted();
+
+ /**
+ * Called when starting tethering failed.
+ */
+ public abstract void onTetheringFailed();
+
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ private static void setHotspotOnPhone(Context mContext, boolean isEnable) {
+
+ OreoWifiManager mTestOreoWifiManager = null;
+
+ if (mTestOreoWifiManager ==null) {
+ mTestOreoWifiManager = new OreoWifiManager(mContext);
+ }
+
+
+ if (isEnable){
+ OnStartTetheringCallback callback = new OnStartTetheringCallback() {
+ @Override
+ public void onTetheringStarted() {
+ }
+
+ @Override
+ public void onTetheringFailed() {
+
+ }
+ };
+
+ mTestOreoWifiManager.startTethering(callback);
+ }else{
+ mTestOreoWifiManager.stopTethering();
+ }
+
+ }
+
+ /*
+ public static void setWiFiApEnable(Context context, boolean isEnable) {
+ ConnectivityManager mConnectivityManager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (isEnable) {
+ mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false, new ConnectivityManager.OnStartTetheringCallback() {
+ @Override
+ public void onTetheringStarted() {
+ Log.d(TAG, "onTetheringStarted");
+ // Don't fire a callback here, instead wait for the next update from wifi.
+ }
+
+ @Override
+ public void onTetheringFailed() {
+ Log.d(TAG, "onTetheringFailed");
+ // TODO: Show error.
+ }
+ });
+ } else {
+ mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ }
+ }
+
+ */
+
+ public static void enableHotspot(Context context, boolean isEnable) {
+ // R: Adnroid 11
+ // O: Android 8
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // Android 11
+ setHotspotOnPhone(context, isEnable);
+ }/* else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // Android 8
+
+ }
+ */
+ }
+}
diff --git a/mpmaster/src/main/AndroidManifest.xml b/mpmaster/src/main/AndroidManifest.xml
index b91d32cb..298e8e10 100644
--- a/mpmaster/src/main/AndroidManifest.xml
+++ b/mpmaster/src/main/AndroidManifest.xml
@@ -12,6 +12,7 @@
+
diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java b/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java
index 239fac0e..b70b1d08 100644
--- a/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java
+++ b/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java
@@ -18,6 +18,7 @@ import android.widget.Switch;
import com.dev.devapi.api.SysApi;
+import com.xypower.common.HotspotManager;
import com.xypower.common.MicroPhotoContext;
import java.text.SimpleDateFormat;
@@ -122,6 +123,13 @@ public class MainActivity extends AppCompatActivity {
});
+ mHandler.postDelayed(
+ new Runnable() {
+ public void run() {
+ HotspotManager.enableHotspot(getApplicationContext(), false);
+ }
+ }, 5000);
+
startMicroPhotoService(getApplicationContext());
}