Wifirouter

This commit is contained in:
jens 2021-05-22 02:51:31 +02:00
parent 9b33f13f66
commit f70e45701f
5 changed files with 536 additions and 0 deletions

View File

@ -70,6 +70,9 @@ dependencies {
apkFlavorImplementation 'com.google.firebase:firebase-appindexing:19.2.0'
apkFlavorImplementation 'com.google.android.gms:play-services-location:17.1.0'
implementation 'com.linkedin.dexmaker:dexmaker:2.25.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
testImplementation 'junit:junit:4.+'

View File

@ -0,0 +1,255 @@
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

@ -0,0 +1,58 @@
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

@ -0,0 +1,15 @@
package com.jens.automation2.actions.wifi_router;
public abstract class MyOnStartTetheringCallback
{
/**
* Called when tethering has been successfully started.
*/
public abstract void onTetheringStarted();
/**
* Called when starting tethering failed.
*/
public abstract void onTetheringFailed();
}

View File

@ -0,0 +1,205 @@
package com.jens.automation2.actions.wifi_router;
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 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;
import java.util.Arrays;
/**
* Created by jonro on 19/03/2018.
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public class MyOreoWifiManager
{
private static final String TAG = MyOreoWifiManager.class.getSimpleName();
private Context mContext;
private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
public MyOreoWifiManager(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 MyOnStartTetheringCallback 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;
}
}