Here I am trying to connect to wifi through it's ssid by following code. After calling bindProcessToNetwork, it does not getting connected to wifi, nor any warning or error. I have also provide required permissions already.
requireContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkCallback: NetworkCallback = object : NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
connectivityManager.bindProcessToNetwork(network)
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
}
override fun onLost(network: Network) {
super.onLost(network)
}
override fun onUnavailable() {
super.onUnavailable()
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities,
) {
super.onCapabilitiesChanged(network, networkCapabilities)
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
super.onLinkPropertiesChanged(network, linkProperties)
}
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
super.onBlockedStatusChanged(network, blocked)
}
}
// connectivityManager.requestNetwork(networkRequest,networkCallback);
connectivityManager.registerNetworkCallback(NetworkRequest.Builder()
.build(), networkCallback)```
Related
I'm trying to connect to wifi from my android application, using the wifi Network request API.
Here is the code:
val builder =
WifiNetworkSpecifier.Builder()
.setBssid(MacAddress.fromString(item.bssid))
.setWpa2Passphrase("somePassword")
if (item.ssid.isNotEmpty()) {
builder.setSsid(item.ssid)
}
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(builder.build())
.build()
Next I do that
cm.requestNetwork(
networkRequest,
WifiConnectionCallBack(ConnectivityManager)
)
WifiConnectionCallBack is my class, what extends NetworkCallback
class WifiConnectionCallBack(
private val connectionWatcher : ConnectionWatcher,
private val bssid : String,
private val connManager: ConnectivityManager,
private val onConnection : (Boolean, Network) -> Unit
) : NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
val result = connManager.bindProcessToNetwork(network)
onConnection.invoke(result, network)
connectionWatcher.onChangeState(ConnectionState.WifiConnected(bssid, network))
}
override fun onUnavailable() {
super.onUnavailable()
connectionWatcher.onChangeState(ConnectionState.UnAvailable)
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
super.onLinkPropertiesChanged(network, linkProperties)
connectionWatcher.onChangeState(
ConnectionState.LinkPropertiesChanged(
bssid,
network,
linkProperties
)
)
}
override fun onLost(network: Network) {
super.onLost(network)
connectionWatcher.onChangeState(ConnectionState.Lost(network))
}
It works fine... But, when I HAVE NO access to the internet. Any suggestions, what can be wrong here?
Thank you for reading this!
I tried methods from this topic Connect to Wifi in Android Q programmatically
But it doesnt work
I'm trying to get my app to connect to a WiFi AP to provide Internet with WifiNetworkSpecifier using code like this. But it's always calling onUnavailable in the NetworkCallback.
private val callback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
}
override fun onLost(network: Network) {
super.onLost(network)
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
}
override fun onUnavailable() {
super.onUnavailable()
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
super.onLinkPropertiesChanged(network, linkProperties)
}
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
super.onBlockedStatusChanged(network, blocked)
}
}
val networkSpecifier: NetworkSpecifier = WifiNetworkSpecifier.Builder()
.setSsid("SsidName")
.setWpa2Passphrase("wifipassword")
.build()
val networkRequest: NetworkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setNetworkSpecifier(networkSpecifier)
.build()
connectivityManager.requestNetwork(networkRequest, callback, 100000)
The WifiNetworkSpecifier is only meant to connect to local-only Wifi networks, for example, to set up IoT devices, as confirmed here: https://developer.android.com/guide/topics/connectivity/wifi-bootstrap
So if you .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET), Android will always just do nothing and call onUnavailable.
You can see why in the Android platform code here: https://cs.android.com/android/platform/superproject/+/master:packages/modules/Wifi/service/java/com/android/server/wifi/WifiNetworkFactory.java;drc=08124f52b883c61f3e17bc57dc28eca4c7f7bb72;l=487
The message in your LogCat will be E/WifiNetworkFactory: Request with wifi network specifier cannot contain NET_CAPABILITY_INTERNET. Rejecting
If you want Internet, you need to remove the .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) line (which makes a lot of sense, wha!) and add connectivityManager.bindProcessToNetwork(network) in onAvailable as described over in this answer. Note this is a bit of a hack and will enable Internet via Wifi for your app only.
When android device is not connected to the Internet,
I'm going to check if Wi-Fi can be connected with connection live data and connect to a specific Wi-Fi.
ConnectionLiveData
private val TAG = "ConnectionLiveData"
class ConnectionLiveData(context: Context) : LiveData<Boolean>() {
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
private val validNetworks: MutableSet<Network> = HashSet()
private fun checkValidNetworks() {
postValue(validNetworks.size > 0)
}
override fun onActive() {
networkCallback = createNetworkCallback()
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
override fun onInactive() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d(TAG, "---Location onAvailable: $network")
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
val hasInternetCapability = networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
Log.d(TAG, "---Location onAvailable: $network, $hasInternetCapability")
if (hasInternetCapability == true) {
CoroutineScope(Dispatchers.IO).launch {
val hasInternet = DoesNetworkHaveInternet.execute(network.socketFactory)
if (hasInternet) {
withContext(Dispatchers.Main) {
Log.d(TAG, "onAvailable: adding network. $network")
validNetworks.add(network)
checkValidNetworks()
}
}
}
}else {
Log.d(TAG, "There is no active network")
}
}
override fun onLost(network: Network) {
Log.d(TAG,
"The application no longer has a default network. The last default network was $network"
)
validNetworks.remove(network)
checkValidNetworks()
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
Log.d(TAG, "The default network changed capabilities: $networkCapabilities")
}
override fun onLinkPropertiesChanged(
network: Network,
linkProperties: LinkProperties
) {
Log.d(TAG, "The default network changed link properties: $linkProperties")
}
}
}
ConnectivityManager
#Singleton
class ConnectivityManager
#Inject
constructor(
application: Application,
) {
private val connectionLiveData = ConnectionLiveData(application)
// observe this in ui
val isNetworkAvailable = mutableStateOf(false)
fun registerConnectionObserver(lifecycleOwner: LifecycleOwner){
connectionLiveData.observe(lifecycleOwner) { isConnected ->
isConnected?.let { isNetworkAvailable.value = it }
}
}
fun unregisterConnectionObserver(lifecycleOwner: LifecycleOwner){
connectionLiveData.removeObservers(lifecycleOwner)
}
}
And then, when I connect the wifi, it logs like this.
2021-11-27 10:09:10.808 28100-28143/com.connectapp D/ConnectionLiveData: ---Location onAvailable: 152
2021-11-27 10:09:10.810 28100-28143/com.connectapp D/ConnectionLiveData: ---Location onAvailable: 152, true
2021-11-27 10:09:10.812 28100-28143/com.connectapp D/ConnectionLiveData: The default network changed capabilities: [ Transports: WIFI Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED LinkUpBandwidth>=1048576Kbps LinkDnBandwidth>=1048576Kbps SignalStrength: -56]
2021-11-27 10:09:10.814 28100-28143/com.connectapp D/ConnectionLiveData: The default network changed link properties: {Network Interface}
2021-11-27 10:09:10.885 28100-28100/com.connectapp D/ConnectionLiveData: onAvailable: adding network. 152
But when I remove stored Wi-Fi data at device, it doesn't return Log
So my question is this, when android device is not connected to internet, connect to specific Wi-Fi.
How I can connect it?
I'm interested to know if there is a way to get a callback when there are chromecast casting failures:
The user start to cast something from my app, background the app and start casting a different asset from a different application like YouTube/Spotify
When there is a power drop and the chromecast disconnected from the wifi.
Connectivity issues with chromecast and the router
I'm currently using RemoteMediaClient with setResultCallback but setResultCallback is never been called when there is one of those failures.
There is a session manager listener , you can use it
val mSessionManagerListener = object : SessionManagerListener<CastSession> {
override fun onSessionEnded(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
onApplicationConnected(session)
}
override fun onSessionResumeFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
showToast("ResumeFailed $error")
}
override fun onSessionStarted(session: CastSession, sessionId: String) {
onApplicationConnected(session)
}
override fun onSessionStartFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
showToast("Error $error")
}
override fun onSessionStarting(session: CastSession) {}
override fun onSessionEnding(session: CastSession) {}
override fun onSessionResuming(session: CastSession, sessionId: String) {}
override fun onSessionSuspended(session: CastSession, reason: Int) {}
private fun onApplicationConnected(castSession: CastSession) {
mCastSession = castSession
}
private fun onApplicationDisconnected() {
}
}
mCastContext?.sessionManager?.addSessionManagerListener(
mSessionManagerListener!!,
CastSession::class.java
)
I'm currently using NetworkRequest and NetworkCallback approach (recommended by Google official) to get status of Wifi connection, and it works partially.
I'm expecting the onUnavailable() will get called when: close app -> turn off Wifi -> launch app, however there is nothing happened:
private fun getNetworkRequest(): NetworkRequest {
return NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) //restric to Wifi type only
.build()
}
private fun getNetworkCallBack(): ConnectivityManager.NetworkCallback {
return object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) { //works
super.onAvailable(network)
Toast.makeText(requireContext(), "Wifi is on!", Toast.LENGTH_SHORT).show()
}
override fun onLost(network: Network) { //works
super.onLost(network)
Toast.makeText(requireContext(), "Wifi turns off!", Toast.LENGTH_SHORT).show()
}
override fun onUnavailable() { //not works as expected
super.onUnavailable()
Toast.makeText(requireContext(), "Wifi unavailable!", Toast.LENGTH_SHORT).show()
}
}
}
fun Fragment.getConnectivityManager() = requireContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
override fun onResume() {
super.onResume()
getConnectivityManager().registerNetworkCallback(networkRequest, networkCallback)
}
Ok, I got the solution:
val isWifiOn = with(getConnectivityManager()) {
getNetworkCapabilities(activeNetwork)?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}
Demo: https://youtu.be/OHFrtXVW4x4