Closed frankot-inf closed 4 years ago
@zplesac I've checked the demo project. Everything works fine, except Wi-Fi on Android 10, which is expected. A small change had to be introduced to the URL used for checking the network connection, though:
private static final String NETWORK_CHECK_URL = "https://clients3.google.com/generate_204";
Previously, it was http
, now it's https
. It would throw an IOException
saying that cleartext traffic is not permitted.
I also noticed that the output was not readable in the demo app, so I've added toString
overrides in the models.
The following method has been added to address your comment about extracting the null-check:
private static void assertNotNull(ConnectionBuddyConfiguration configuration) {
if (configuration == null) {
throw new IllegalStateException(NOT_INITIALIZED_ERROR);
}
}
However, this had the side-effect that the IDE would not recognise the null-check in the calling method. For example, consider:
public void registerForConnectivityEvents(@NonNull Object object, @NonNull ConnectivityChangeListener listener) {
assertNotNull(configuration);
registerForConnectivityEvents(object, configuration.isNotifyImmediately(), listener);
}
The IDE would issue a warning at configuration.isNotifyImmediately()
saying that it might result in a NPE.
Fortunately, there exists JetBrains' annotation library: https://github.com/JetBrains/java-annotations. This introduces the @Contract
annotation that solves the problem. The library is included with compileOnly
, so this should only have an effect on the library during compile-time.
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects. This is true when using Gradle project dependencies and also when publishing to Maven or Ivy repositories. In the latter case, compile-only dependencies are simply omitted from published metadata.
Modified Readme.md
.
ConnectivityEvent
Maybe we should set compileSdkVersion
and targetSdkVersion
back to 28, as we don't really properly support Android 10?
I think this is a good time to think about ConnectionBuddy 3.0.0 with breaking API changes.
@frankot-inf yeah, I agree.
Let's go with this a introduce breaking changes with 3.0.0, I have a couple of ideas which I would like to introduce.
@zplesac I've had some ideas as well. I'd be happy to discuss further in about a month, when I get back to work after my exams, if that's fine with you.
I've set targetSdkVersion
to 28. The explicit buildToolsVersion
setting has been removed, as this is automatically set by the Gradle plugin since version 3.0.0.
The buildscript
block in build.gradle
of :sampleapp
has been removed, as I think this shouldn't be there. Can you double check if this is okay, please?
Gradle has been updated to 6.1.1 and Gradle plugin to 4.0.0 to keep up to date with the latest Android Studio 4.0.
This made the FindBugs
plugin obsolete, and it had to be removed. Gradle recommends SpotBugs
instead: https://docs.gradle.org/current/userguide/upgrading_version_5.html#the_findbugs_plugin_has_been_removed. You should decide if this should be included.
For the record, there's also a deprecation warning in the build scan here: https://scans.gradle.com/s/ux2yv6fvqujc4.
-Xlint:deprecation
compiler option to see all deprecated methods. All of them are about Wi-Fi. This is fine, they can stay.Null safety
Added
@NonNull
and@Nullable
annotations where appropriate. The only places I didn't know how to resolve were theinit
method inConnectionBuddy
andonReceive
overrides ofBroadcastReceiver
.The
init
method receives aConnectionBuddyConfiguration
parameter. This parameter shouldn't benull
, as there is a check for this inside the method:However, if I put the
@NonNull
annotation to the parameter, then AS marks theif
condition and saysCondition 'configuration == null' is always 'false'
. I don't like the idea of putting@Nullable
on this parameter, as obviously it's not supposed to benull
. (Theconfiguration
field is marked as@Nullable
, though.) Options are to ignore the warning, to remove the check, or to remove the annotation. I've chosen to remove the annotation, but I want your opinion on this.Regarding
onReceive
, theintent
parameter seems unannotated by the SDK, so I've left it unannotated as well. I think that, in Kotlin, when you override this, it puts a nullable type. What do you think?These annotations have enabled much better null-analysis, and I've gone through the warnings and added null-checks.
Wi-Fi logic
Android 10
In Android 10, it is not possible to manipulate
WifiConfiguration
objects anymore usingaddNetwork
,enableNetwork
, and the likes. You cannot access them through thegetConfiguredNetworks
call, either.The way to connect to Wi-Fi is entirely through suggestions and requests.
CHANGE_NETWORK_STATE
permission is needed for connecting to Wi-Fi usingConnectivityManager
APIs likerequestNetwork
.I've kept the
connectToWifiConfiguration
names, as they're public API. If you think it's fine to rename them, comment on this.A new private
connectToWifiUsingNetworkSpecifier
method has been added, that uses aWifiNetworkSpecifier
API to connect to the desired network. This is called on Android 10 whenconnectToWifiConfiguration
is called by the library user.When using this API, a system dialog is displayed asking the user to connect to the network. When connected this way, the connection is only available while using the app, and once the process is killed, the connection is killed as well. It also seems to not provide internet access by default. (I get an exclamation mark over my Wi-Fi icon in the system tray.) I've added a
bindProcessToNetwork
call when establishing the connection, so traffic should go over this network anyway. I've not tested whether you can really access the internet after this, though.It seems that another API is supposed to be used if internet access is desired, and it is the
WifiNetworkSuggestion
. I've not used this API, so I'm not sure how it behaves, but it seems that the device ultimately decides whether to connect or not, if it thinks this is really the best connection.Apparently, we are no longer going to be able to explicitly connect to any Wi-Fi network, and our control over this is going away. Perhaps we should rethink the API.
What do you think about this?
Pre- Android 10
In
WifiScanResultReceiver
, we've had the following logic:This had the following problems. In the
else
branch, it seemingly updated thepreSharedKey
. This did not happen, however, it only updated theWifiConfiguration
object local to the process. The real object is inside the Wi-Fi service process, and to update it,updateNetwork
would need to be called here. (oraddNetwork
, as internally, they both calladdOrUpdateNetwork
.)This call can still fail, as well as any of the methods that manipulate the configurations.
addNetwork
call remembers the package name of the creator. If the package doesn't match, no configuration manipulation can be done. (Except forenableNetwork
when called withtrue
to attempt connection. It seems to allow connecting to a configuration regardless of the creator. This is entirely experimental information, however, I don't see it in the documentation.)This is unfortunate, because that means if the user connected to a Wi-Fi network using the system settings, then we cannot manipulate the configuration and update the password. Nothing we can do about it.
Either way, the connection is attempted.
Another problem this code had was the way the configuration is created in the
if
branch. It seems to work at times, but the configuration needs to be constructed with many other parameters available from the scan results. This is why a new helper methodcreateWifiConfiguration
has been created.Further, in
WifiConnectionStateChangedReceiver
, the receiver would be unregistered after the firstonReceive
call. This is incorrect, as this receiver is notified about every step of the connection attempt. This is an example of a series of calls toonReceive
:It can even be called with
DISCONNECED
at the beginning (though, not always), even though a connection attempt is in progress.It now waits to enter the
CONNECTING
state. After this, ifCONNECTED
is received, the connection is considered a success, and ifDISCONNECTED
orSUSPENDED
is received, the connection is considered a failure.ConnectionBuddyConfiguration
changesWifiManager
service field for convenience, just likeConnectivityManager
was a part of it.context
field has been renamed toapplicationContext
. I've left the getter as-is (getContext
), as it is public API, but I've added a docstring for clarification. Comment on this if you think renaming is fine.