Skip to content

Instantly share code, notes, and snippets.

@Ahmed-Adel-Ismail
Last active July 14, 2017 10:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ahmed-Adel-Ismail/7440d1896db4666eaba7f0e5bcea3802 to your computer and use it in GitHub Desktop.
Save Ahmed-Adel-Ismail/7440d1896db4666eaba7f0e5bcea3802 to your computer and use it in GitHub Desktop.
A class that retrieves Android's Mac address by all possible means (so far), used dependencies are RxJava2, Retrolambda, Guava, custom Preferences class to handle saving / loading from Shared Preferences, and J-Curry (https://github.com/Terebentikh/J-Curry) for currying functions in RxJava2 operators
/**
* a {@link Maybe} that retrieves the Mac address from any of the following sources :
* <p>
* {@code Shared Preference}<br>
* {@code Wifi}<br>
* {@code Network interfaces}
* <p>
* then saves it to {@code Shared preferences} if found
* <p>
* Created by Ahmed Adel Ismail on 7/10/2017.
*/
public class MacAddressScanner extends Maybe<String>{
public static final String INVALID_MAC_ADDRESS = "02:00:00:00:00:00";
private static final String PREFERENCES_KEY = "com.commons.system.MacAddressScanner";
private final Context context;
public MacAddressScanner(Context context) {
this.context = context.getApplicationContext();
}
@Override
@SuppressWarnings("unchecked")
protected void subscribeActual(MaybeObserver<? super String> observer) {
Observable.concatArrayDelayError(preferences(), wifi(), networkInterface())
.firstElement()
.doOnSuccess(Curry.apply(new PreferenceSaver<>(), PREFERENCES_KEY))
.subscribe(observer::onSuccess, observer::onError, observer::onComplete);
}
private Observable<String> preferences() {
return Observable.just(PREFERENCES_KEY)
.map(Curry.apply(new PreferenceLoader<>(), INVALID_MAC_ADDRESS))
.filter(MacAddressScanner::isValid);
}
@SuppressLint("WifiManagerPotentialLeak")
private Observable<String> wifi() {
return Observable.just((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
.filter(WifiManager::isWifiEnabled)
.map(WifiManager::getConnectionInfo)
.map(WifiInfo::getMacAddress)
.filter(MacAddressScanner::isValid);
}
private Observable<String> networkInterface() {
return Observable.fromIterable(networkInterfacesList())
.filter(MacAddressScanner::isWlan0)
.firstElement()
.map(NetworkInterface::getHardwareAddress)
.map(Bytes::asList)
.flatMapObservable(Observable::fromIterable)
.map(MacAddressScanner::toFormattedByte)
.reduce(MacAddressScanner::concatenate)
.map(String::toLowerCase)
.flatMapObservable(Observable::just)
.filter(MacAddressScanner::isValid);
}
@NonNull
private List<NetworkInterface> networkInterfacesList() {
try {
return Collections.list(NetworkInterface.getNetworkInterfaces());
}catch (SocketException e) {
L.x(e);
return new ArrayList<>();
}
}
private static boolean isWlan0(NetworkInterface networkInterface) {
return networkInterface.getName().equalsIgnoreCase("wlan0");
}
private static String toFormattedByte(Byte b) {
return String.format("%02X", b);
}
private static String concatenate(String firstString, String secondString) {
return Joiner.on(":").join(firstString, secondString);
}
private static boolean isValid(String macAddress) {
return !INVALID_MAC_ADDRESS.equals(macAddress) && !TextUtils.isEmpty(macAddress);
}
}
/**
* a function that saves data in Preferences
*
* Created by Ahmed Adel Ismail on 7/11/2017.
*/
class PreferenceSaver<T> implements BiConsumer<String, T>{
@Override
public void accept(String key, T value){
Preferences.getInstance().save(key, value);
}
}
/**
* a function that loads a value from preference, and if it failed, it returns a default value
* passed as the first parameter
* <p>
* Created by Ahmed Adel Ismail on 7/11/2017.
*/
class PreferenceLoader<T> implements BiFunction<T, String, T>{
@Override
public T apply(@NonNull T defaultValue, @NonNull String key) {
return Preferences.getInstance().load(key, defaultValue);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment