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()); }