Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ package com.google.android.horologist.networks.rules
import com.google.android.horologist.networks.ExperimentalHorologistNetworksApi
import com.google.android.horologist.networks.data.NetworkStatus
import com.google.android.horologist.networks.data.NetworkType
import com.google.android.horologist.networks.data.NetworkType.Bluetooth
import com.google.android.horologist.networks.data.NetworkType.Cellular
import com.google.android.horologist.networks.data.NetworkType.Wifi
import com.google.android.horologist.networks.data.Networks
import com.google.android.horologist.networks.data.RequestType
import com.google.android.horologist.networks.data.RequestType.MediaRequest
import com.google.android.horologist.networks.data.RequestType.MediaRequest.MediaRequestType.Download

/**
* Implementation of app rules for network usage. A way to implement logic such as
Expand Down Expand Up @@ -60,7 +65,7 @@ public interface NetworkingRules {
@ExperimentalHorologistNetworksApi
public object Lenient : NetworkingRules {
override fun isHighBandwidthRequest(requestType: RequestType): Boolean {
return requestType is RequestType.MediaRequest
return requestType is MediaRequest
}

override fun checkValidRequest(
Expand All @@ -74,7 +79,8 @@ public interface NetworkingRules {
networks: Networks,
requestType: RequestType
): NetworkStatus? {
return networks.networks.firstOrNull { it.type is NetworkType.Wifi }
val wifi = networks.networks.firstOrNull { it.type is Wifi }
return wifi ?: networks.networks.firstOrNull()
}
}

Expand All @@ -85,22 +91,34 @@ public interface NetworkingRules {
@ExperimentalHorologistNetworksApi
public object Conservative : NetworkingRules {
override fun isHighBandwidthRequest(requestType: RequestType): Boolean {
return requestType is RequestType.MediaRequest
return requestType is MediaRequest
}

override fun checkValidRequest(
requestType: RequestType,
currentNetworkType: NetworkType
): RequestCheck {
if (requestType is RequestType.MediaRequest) {
return if (requestType.type == RequestType.MediaRequest.MediaRequestType.Download) {
if (currentNetworkType is NetworkType.Wifi || currentNetworkType is NetworkType.Cellular) {
Allow
} else {
Fail("downloads only possible over Wifi/LTE")
if (requestType is MediaRequest) {
return when (requestType.type) {
Download -> {
// Only allow Downloads over Wifi
// BT will hog the limited bandwidth
// Cell may include charges and should be checked with user
if (currentNetworkType is Wifi) {
Allow
} else {
Fail("downloads only possible over Wifi")
}
}
MediaRequest.MediaRequestType.Stream -> {
// Only allow Stream over Wifi or BT
// BT may hog the limited bandwidth, but hopefully is small stream.
if (currentNetworkType is Wifi || currentNetworkType is Bluetooth) {
Allow
} else {
Fail("streaming only possible over Wifi or BT")
}
}
} else {
Fail("streaming disabled")
}
}

Expand All @@ -111,15 +129,22 @@ public interface NetworkingRules {
networks: Networks,
requestType: RequestType
): NetworkStatus? {
val cell = networks.networks.firstOrNull { it.type is NetworkType.Cellular }
val ble = networks.networks.firstOrNull { it.type is NetworkType.Bluetooth }
val wifi = networks.networks.firstOrNull { it.type is Wifi }

if (wifi != null) return wifi

return networks.networks.firstOrNull { it.type is NetworkType.Wifi }
?: if (requestType is RequestType.MediaRequest) {
cell
val cell = networks.networks.firstOrNull { it.type is Cellular }
val ble = networks.networks.firstOrNull { it.type is Bluetooth }

return if (requestType is MediaRequest) {
if (requestType.type == Download) {
null
} else {
ble
}
} else {
ble ?: cell
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@file:OptIn(ExperimentalHorologistNetworksApi::class)

package com.google.android.horologist.networks.rules

import com.google.android.horologist.networks.ExperimentalHorologistNetworksApi
import com.google.android.horologist.networks.data.RequestType.ImageRequest
import com.google.android.horologist.networks.data.RequestType.MediaRequest
import com.google.android.horologist.networks.data.RequestType.MediaRequest.MediaRequestType.Download
import com.google.android.horologist.networks.data.RequestType.MediaRequest.MediaRequestType.Stream
import com.google.android.horologist.networks.rules.Fixtures.bt
import com.google.android.horologist.networks.rules.Fixtures.cell
import com.google.android.horologist.networks.rules.Fixtures.wifi
import com.google.android.horologist.networks.rules.NetworkingRules.Conservative
import com.google.common.truth.Truth.assertThat
import org.junit.Test

class ConservativeTest {
val wifiFirst = Fixtures.networks(wifi, bt)
val btFirst = Fixtures.networks(bt, wifi)
val btOnly = Fixtures.networks(bt)
val cellOnly = Fixtures.networks(cell)

@Test
fun getPreferredNetworkForImages() {
assertThat(Conservative.getPreferredNetwork(wifiFirst, ImageRequest)).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btFirst, ImageRequest)).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btOnly, ImageRequest)).isEqualTo(bt)
assertThat(Conservative.getPreferredNetwork(cellOnly, ImageRequest)).isEqualTo(cell)
}

@Test
fun getPreferredNetworkForMediaDownloads() {
assertThat(Conservative.getPreferredNetwork(wifiFirst, MediaRequest(Download))).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btFirst, MediaRequest(Download))).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btOnly, MediaRequest(Download))).isEqualTo(null)
assertThat(Conservative.getPreferredNetwork(cellOnly, MediaRequest(Download))).isEqualTo(null)
}

@Test
fun getPreferredNetworkForMediaStreams() {
assertThat(Conservative.getPreferredNetwork(wifiFirst, MediaRequest(Stream))).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btFirst, MediaRequest(Stream))).isEqualTo(wifi)
assertThat(Conservative.getPreferredNetwork(btOnly, MediaRequest(Stream))).isEqualTo(bt)
assertThat(Conservative.getPreferredNetwork(cellOnly, MediaRequest(Stream))).isEqualTo(null)
}

@Test
fun checkValidRequestForImages() {
assertThat(Conservative.checkValidRequest(ImageRequest, wifi.type)).isInstanceOf(Allow::class.java)
assertThat(Conservative.checkValidRequest(ImageRequest, cell.type)).isInstanceOf(Allow::class.java)
assertThat(Conservative.checkValidRequest(ImageRequest, bt.type)).isInstanceOf(Allow::class.java)
}

@Test
fun checkValidRequestForMediaDownloads() {
assertThat(Conservative.checkValidRequest(MediaRequest(Download), wifi.type)).isInstanceOf(Allow::class.java)
assertThat(Conservative.checkValidRequest(MediaRequest(Download), cell.type)).isInstanceOf(Fail::class.java)
assertThat(Conservative.checkValidRequest(MediaRequest(Download), bt.type)).isInstanceOf(Fail::class.java)
}

@Test
fun checkValidRequestForMediaStream() {
assertThat(Conservative.checkValidRequest(MediaRequest(Stream), wifi.type)).isInstanceOf(Allow::class.java)
assertThat(Conservative.checkValidRequest(MediaRequest(Stream), cell.type)).isInstanceOf(Fail::class.java)
assertThat(Conservative.checkValidRequest(MediaRequest(Stream), bt.type)).isInstanceOf(Allow::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@file:OptIn(ExperimentalHorologistNetworksApi::class)

package com.google.android.horologist.networks.rules

import com.google.android.horologist.networks.ExperimentalHorologistNetworksApi
import com.google.android.horologist.networks.data.NetworkStatus
import com.google.android.horologist.networks.data.NetworkType
import com.google.android.horologist.networks.data.Networks
import com.google.android.horologist.networks.data.Status

object Fixtures {
fun networks(default: NetworkStatus?, vararg rest: NetworkStatus): Networks {
return Networks(default, listOfNotNull(default, *rest))
}

val wifi = NetworkStatus(
id = "wlan0",
status = Status.Available,
type = NetworkType.Wifi("wifi", null),
addresses = listOf(),
capabilities = null,
linkProperties = null,
bindSocket = {}
)

val bt = NetworkStatus(
id = "bt",
status = Status.Available,
type = NetworkType.Bluetooth("bt"),
addresses = listOf(),
capabilities = null,
linkProperties = null,
bindSocket = {}
)

val cell = NetworkStatus(
id = "cell",
status = Status.Available,
type = NetworkType.Cellular("cell", false),
addresses = listOf(),
capabilities = null,
linkProperties = null,
bindSocket = {}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@file:OptIn(ExperimentalHorologistNetworksApi::class)

package com.google.android.horologist.networks.rules

import com.google.android.horologist.networks.ExperimentalHorologistNetworksApi
import com.google.android.horologist.networks.data.RequestType.ImageRequest
import com.google.android.horologist.networks.rules.Fixtures.bt
import com.google.android.horologist.networks.rules.Fixtures.cell
import com.google.android.horologist.networks.rules.Fixtures.wifi
import com.google.android.horologist.networks.rules.NetworkingRules.Lenient
import com.google.common.truth.Truth.assertThat
import org.junit.Test

class LenientTest {
@Test
fun getPreferredNetwork() {
val wifiFirst = Fixtures.networks(wifi, bt)
assertThat(Lenient.getPreferredNetwork(wifiFirst, ImageRequest)).isEqualTo(wifi)

val btFirst = Fixtures.networks(bt, wifi)
assertThat(Lenient.getPreferredNetwork(btFirst, ImageRequest)).isEqualTo(wifi)

val btOnly = Fixtures.networks(bt)
assertThat(Lenient.getPreferredNetwork(btOnly, ImageRequest)).isEqualTo(bt)
}

@Test
fun checkValidRequest() {
assertThat(Lenient.checkValidRequest(ImageRequest, wifi.type)).isInstanceOf(Allow::class.java)

assertThat(Lenient.checkValidRequest(ImageRequest, cell.type)).isInstanceOf(Allow::class.java)

assertThat(Lenient.checkValidRequest(ImageRequest, bt.type)).isInstanceOf(Allow::class.java)
}
}