Wifi tethering without root above Oreo works again.

This commit is contained in:
jens 2021-05-30 12:27:27 +02:00
parent 7fd8d1cfd0
commit 7182698b8a
5 changed files with 87 additions and 367 deletions

View File

@ -20,9 +20,12 @@ import android.telephony.SmsManager;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Toast; import android.widget.Toast;
import com.jens.automation2.actions.wifi_router.MyOnStartTetheringCallback;
import com.jens.automation2.actions.wifi_router.MyOreoWifiManager;
import com.jens.automation2.location.WifiBroadcastReceiver; import com.jens.automation2.location.WifiBroadcastReceiver;
import com.jens.automation2.receivers.ConnectivityReceiver; import com.jens.automation2.receivers.ConnectivityReceiver;
@ -190,45 +193,71 @@ public class Actions
if(((state && !desiredState) || (!state && desiredState))) if(((state && !desiredState) || (!state && desiredState)))
{ {
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
{
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method[] methods = wifiManager.getClass().getDeclaredMethods(); Method[] methods = wifiManager.getClass().getDeclaredMethods();
for(Method method : methods) for (Method method : methods)
{ {
Miscellaneous.logEvent("i", "WifiAp", "Trying to find appropriate method... " + method.getName(), 5); Miscellaneous.logEvent("i", "WifiAp", "Trying to find appropriate method... " + method.getName(), 5);
if(method.getName().equals("setWifiApEnabled")) if (method.getName().equals("setWifiApEnabled"))
{ {
try try
{ {
String desiredString = ""; String desiredString = "";
if(desiredState) if (desiredState)
desiredString = "activate"; desiredString = "activate";
else else
desiredString = "deactivate"; desiredString = "deactivate";
if(!toggleActionIfPossible) if (!toggleActionIfPossible)
{ {
Miscellaneous.logEvent("i", "WifiAp", "Trying to " + desiredString + " wifi ap...", 2); Miscellaneous.logEvent("i", "WifiAp", "Trying to " + desiredString + " wifi ap...", 2);
if(!method.isAccessible()) if (!method.isAccessible())
method.setAccessible(true); method.setAccessible(true);
method.invoke(wifiManager, null, desiredState); method.invoke(wifiManager, null, desiredState);
} }
else else
{ {
Miscellaneous.logEvent("i", "WifiAp", "Trying to " + context.getResources().getString(R.string.toggle) + " wifi ap...", 2); Miscellaneous.logEvent("i", "WifiAp", "Trying to " + context.getResources().getString(R.string.toggle) + " wifi ap...", 2);
if(!method.isAccessible()) if (!method.isAccessible())
method.setAccessible(true); method.setAccessible(true);
method.invoke(wifiManager, null, !state); method.invoke(wifiManager, null, !state);
} }
Miscellaneous.logEvent("i", "WifiAp", "Wifi ap " + desiredString + "d.", 2); Miscellaneous.logEvent("i", "WifiAp", "Wifi ap " + desiredString + "d.", 2);
} }
catch(Exception e) catch (Exception e)
{ {
Miscellaneous.logEvent("i", "WifiAp", context.getResources().getString(R.string.errorActivatingWifiAp) + ". " + e.getMessage(), 2); Miscellaneous.logEvent("i", "WifiAp", context.getResources().getString(R.string.errorActivatingWifiAp) + ". " + e.getMessage(), 2);
} }
} }
} }
} }
else
{
MyOnStartTetheringCallback cb = new MyOnStartTetheringCallback()
{
@Override
public void onTetheringStarted()
{
Log.i("Tether", "Läuft");
}
@Override
public void onTetheringFailed()
{
Log.i("Tether", "Doof");
}
};
MyOreoWifiManager mowm = new MyOreoWifiManager(context);
if(desiredState)
mowm.startTethering(cb);
else
mowm.stopTethering();
}
}
return true; return true;
} }

View File

@ -1,255 +0,0 @@
package com.jens.automation2.actions.wifi_router;
import android.Manifest;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import java.lang.reflect.Method;
import static android.content.ContentValues.TAG;
/**
* An {@link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
*/
public class HotSpotIntentService extends IntentService
{
/**
Id for running service in foreground
*/
private static int FOREGROUND_ID=1338;
private static final String CHANNEL_ID = "control_app";
// Action names...assigned in manifest.
private String ACTION_TURNON;
private String ACTION_TURNOFF;
private String DATAURI_TURNON;
private String DATAURI_TURNOFF;
private Intent mStartIntent;
@RequiresApi(api = Build.VERSION_CODES.O)
MyOreoWifiManager mMyOreoWifiManager;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
*/
public HotSpotIntentService()
{
super("HotSpotIntentService");
}
/**
* Helper method to start this intent from {@link HotSpotIntentReceiver}
* @param context
* @param intent
*/
public static void start(Context context,Intent intent)
{
Intent i = new Intent(context, HotSpotIntentService.class);
i.setAction(intent.getAction());
i.setData(intent.getData());
context.startService(i);
}
@Override
protected void onHandleIntent(@Nullable Intent intent)
{
ACTION_TURNON = getString(R.string.intent_action_turnon);
ACTION_TURNOFF = getString(R.string.intent_action_turnoff);
DATAURI_TURNON = getString(R.string.intent_data_host_turnon);
DATAURI_TURNOFF = getString(R.string.intent_data_host_turnoff);
// Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
Log.i(TAG,"Received start intent");
mStartIntent = intent;
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
}
else
{
carryOn();
}
}
private void carryOn()
{
boolean turnOn = true;
if (mStartIntent != null)
{
final String action = mStartIntent.getAction();
final String data = mStartIntent.getDataString();
if (ACTION_TURNON.equals(action) || (data!=null && data.contains(DATAURI_TURNON)))
{
turnOn = true;
Log.i(TAG,"Action/data to turn on hotspot");
}
else if (ACTION_TURNOFF.equals(action)|| (data!=null && data.contains(DATAURI_TURNOFF)))
{
turnOn = false;
Log.i(TAG,"Action/data to turn off hotspot");
}
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.O)
{
hotspotOreo(turnOn);
}
else
{
turnOnHotspotPreOreo(turnOn);
}
}
}
private boolean turnOnHotspotPreOreo(boolean turnOn)
{
{
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
Method[] methods = wifiManager.getClass().getDeclaredMethods();
for (Method method : methods)
{
if (method.getName().equals("setWifiApEnabled"))
{
try
{
if (turnOn)
{
wifiManager.setWifiEnabled(false); //Turning off wifi because tethering requires wifi to be off
method.invoke(wifiManager, null, true); //Activating tethering
return true;
}
else
{
method.invoke(wifiManager, null, false); //Deactivating tethering
wifiManager.setWifiEnabled(true); //Turning on wifi ...should probably be done from a saved setting
return true;
}
}
catch (Exception e)
{
return false;
}
}
}
//Error setWifiApEnabled not found
return false;
}
}
/**
*
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private void hotspotOreo(boolean turnOn){
if (mMyOreoWifiManager ==null)
{
mMyOreoWifiManager = new MyOreoWifiManager(this);
}
if (turnOn)
{
//this dont work
MyOnStartTetheringCallback callback = new MyOnStartTetheringCallback()
{
@Override
public void onTetheringStarted()
{
startForeground(FOREGROUND_ID, buildForegroundNotification());
}
@Override
public void onTetheringFailed()
{
}
};
mMyOreoWifiManager.startTethering(callback);
}
else
{
mMyOreoWifiManager.stopTethering();
stopForeground(true);
stopSelf();
}
}
//****************************************************************************************
/**
* Build low priority notification for running this service as a foreground service.
* @return
*/
private Notification buildForegroundNotification()
{
registerNotifChnnl(this);
Intent stopIntent = new Intent(this, HotSpotIntentService.class);
stopIntent.setAction(getString(R.string.intent_action_turnoff));
PendingIntent pendingIntent = PendingIntent.getService(this,0, stopIntent, 0);
NotificationCompat.Builder b=new NotificationCompat.Builder(this,CHANNEL_ID);
b.setOngoing(true)
.setContentTitle("WifiHotSpot is On")
.addAction(new NotificationCompat.Action(
R.drawable.turn_off,
"TURN OFF HOTSPOT",
pendingIntent
))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(Notification.CATEGORY_SERVICE)
.setSmallIcon(R.drawable.notif_hotspot_black_24dp);
return(b.build());
}
private static void registerNotifChnnl(Context context)
{
if (Build.VERSION.SDK_INT >= 26)
{
NotificationManager mngr = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
if (mngr.getNotificationChannel(CHANNEL_ID) != null)
{
return;
}
//
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
context.getString(R.string.notification_chnnl),
NotificationManager.IMPORTANCE_LOW);
// Configure the notification channel.
channel.setDescription(context.getString(R.string.notification_chnnl_location_descr));
channel.enableLights(false);
channel.enableVibration(false);
mngr.createNotificationChannel(channel);
}
}
}

View File

@ -1,58 +0,0 @@
package com.jens.automation2.actions.wifi_router;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MagicActivity extends Activity
{
public static void useMagicActivityToTurnOn(Context c)
{
Uri uri = new Uri.Builder().scheme(c.getString(R.string.intent_data_scheme)).authority(c.getString(R.string.intent_data_host_turnon)).build();
Toast.makeText(c,"Turn on. Uri: "+uri.toString(),Toast.LENGTH_LONG).show();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(uri);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(i);
}
public static void useMagicActivityToTurnOff(Context c)
{
Uri uri = new Uri.Builder().scheme(c.getString(R.string.intent_data_scheme)).authority(c.getString(R.string.intent_data_host_turnoff)).build();
Toast.makeText(c,"Turn off. Uri: "+uri.toString(),Toast.LENGTH_LONG).show();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(uri);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(i);
}
private static final String TAG = MagicActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
}
@Override
void onPermissionsOkay()
{
carryOnWithHotSpotting();
}
/**
* The whole purpose of this activity - to start {@link HotSpotIntentService}
* This may be called straright away in {@code onCreate} or after permissions granted.
*/
private void carryOnWithHotSpotting()
{
Intent intent = getIntent();
HotSpotIntentService.start(this, intent);
finish();
}
}

View File

@ -1,5 +1,10 @@
package com.jens.automation2.actions.wifi_router; package com.jens.automation2.actions.wifi_router;
/*
Class taken from here:
https://github.com/aegis1980/WifiHotSpot
*/
public abstract class MyOnStartTetheringCallback public abstract class MyOnStartTetheringCallback
{ {
/** /**
@ -11,5 +16,4 @@ public abstract class MyOnStartTetheringCallback
* Called when starting tethering failed. * Called when starting tethering failed.
*/ */
public abstract void onTetheringFailed(); public abstract void onTetheringFailed();
} }

View File

@ -1,5 +1,10 @@
package com.jens.automation2.actions.wifi_router; package com.jens.automation2.actions.wifi_router;
/*
Class taken from here:
https://github.com/aegis1980/WifiHotSpot
*/
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
@ -10,6 +15,7 @@ import android.util.Log;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.android.dx.stock.ProxyBuilder; import com.android.dx.stock.ProxyBuilder;
import com.jens.automation2.Miscellaneous;
import java.io.File; import java.io.File;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
@ -51,12 +57,11 @@ public class MyOreoWifiManager
{ {
Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class); Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
boolean status = (boolean) setConfigMethod.invoke(mWifiManager, apConfig); boolean status = (boolean) setConfigMethod.invoke(mWifiManager, apConfig);
Log.d(TAG, "setWifiApConfiguration - success? " + status); Miscellaneous.logEvent("i", "configureHotspot()", "setWifiApConfiguration - success? " + status, 2);
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(TAG, "Error in configureHotspot"); Miscellaneous.logEvent("e", "configureHotspot()", "Error in configureHotspot: " + Log.getStackTraceString(e), 2);
e.printStackTrace();
} }
} }
@ -74,13 +79,14 @@ public class MyOreoWifiManager
Method method = mConnectivityManager.getClass().getDeclaredMethod("getTetheredIfaces"); Method method = mConnectivityManager.getClass().getDeclaredMethod("getTetheredIfaces");
if (method == null) if (method == null)
{ {
Log.e(TAG, "getTetheredIfaces is null"); Miscellaneous.logEvent("i", "getTetheredIfaces()", "getTetheredIfaces is null", 2);
} }
else else
{ {
String res[] = (String []) method.invoke(mConnectivityManager, null); String res[] = (String []) method.invoke(mConnectivityManager, null);
Log.d(TAG, "getTetheredIfaces invoked"); Miscellaneous.logEvent("i", "isTetherActive()", "getTetheredIfaces invoked", 5);
Log.d(TAG, Arrays.toString(res)); Miscellaneous.logEvent("i", "isTetherActive()", Arrays.toString(res), 4);
if (res.length > 0) if (res.length > 0)
{ {
return true; return true;
@ -89,8 +95,7 @@ public class MyOreoWifiManager
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(TAG, "Error in getTetheredIfaces"); Miscellaneous.logEvent("e", "isTetherActive()", "Error in getTetheredIfaces: " + Log.getStackTraceString(e), 2);
e.printStackTrace();
} }
return false; return false;
} }
@ -102,12 +107,11 @@ public class MyOreoWifiManager
*/ */
public boolean startTethering(final MyOnStartTetheringCallback callback) public boolean startTethering(final MyOnStartTetheringCallback callback)
{ {
// On Pie if we try to start tethering while it is already on, it will // 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. // be disabled. This is needed when startTethering() is called programmatically.
if (isTetherActive()) if (isTetherActive())
{ {
Log.d(TAG, "Tether already active, returning"); Miscellaneous.logEvent("i", "startTethering()", "Tether already active, returning", 2);
return false; return false;
} }
@ -139,8 +143,7 @@ public class MyOreoWifiManager
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(TAG, "Error in enableTethering ProxyBuilder"); Miscellaneous.logEvent("e", "startTethering()", "Error in enableTethering ProxyBuilder", 2);
e.printStackTrace();
return false; return false;
} }
@ -150,19 +153,18 @@ public class MyOreoWifiManager
method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class); method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
if (method == null) if (method == null)
{ {
Log.e(TAG, "startTetheringMethod is null"); Miscellaneous.logEvent("w", "startTethering()", "startTetheringMethod is null", 2);
} }
else else
{ {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null); method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
Log.d(TAG, "startTethering invoked"); Miscellaneous.logEvent("i", "startTethering()", "startTethering invoked", 5);
} }
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(TAG, "Error in enableTethering"); Miscellaneous.logEvent("w", "startTethering()", "Error in enableTethering: " + Log.getStackTraceString(e), 2);
e.printStackTrace();
} }
return false; return false;
} }
@ -174,18 +176,17 @@ public class MyOreoWifiManager
Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class); Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
if (method == null) if (method == null)
{ {
Log.e(TAG, "stopTetheringMethod is null"); Miscellaneous.logEvent("w", "stopTethering", "stopTetheringMethod is null", 2);
} }
else else
{ {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE); method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
Log.d(TAG, "stopTethering invoked"); Miscellaneous.logEvent("i", "stopTethering", "stopTethering invoked", 5);
} }
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(TAG, "stopTethering error: " + e.toString()); Miscellaneous.logEvent("e", "stopTethering", "stopTethering error: " + Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
} }
@ -197,8 +198,7 @@ public class MyOreoWifiManager
} }
catch (ClassNotFoundException e) catch (ClassNotFoundException e)
{ {
Log.e(TAG, "OnStartTetheringCallbackClass error: " + e.toString()); Miscellaneous.logEvent("e", "OnStartTetheringCallbackClass()", "OnStartTetheringCallbackClass error: " + Log.getStackTraceString(e), 1);
e.printStackTrace();
} }
return null; return null;
} }