Last active
July 14, 2017 10:22
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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