Skip to content

Commit

Permalink
Adds Push Notification toggle to Device Manager (#7261)
Browse files Browse the repository at this point in the history
* Adds push notifications switch

* Adds functionality to Push notification toggle

* Adds DefaultPushersServiceTest for togglePusher

* Adds DefaultTogglePusherTaskTest

* Adds SessionOverviewViewModelTest for toggling pusher

* Hides pusher toggle if there are no pushers of the device

* Adds changelog file

* Edits changelog file

* Fixes copyrights

* Unregisters checkedChangelistener in onDetachedFromWindow for switch view

* Fixes post merge errors

* Fixes legal copies

* Removes unused imports

* Fixes lint errors

* Fixes test errors

* Fixes error

* Fixes error

* Fixes error

* Fixes error

* Fixes error
  • Loading branch information
ericdecanini authored Oct 10, 2022
1 parent a096ff0 commit 2fe636e
Show file tree
Hide file tree
Showing 27 changed files with 741 additions and 119 deletions.
1 change: 1 addition & 0 deletions changelog.d/7261.wip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds pusher toggle setting to device manager v2
2 changes: 2 additions & 0 deletions library/ui-strings/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3304,6 +3304,8 @@
<string name="device_manager_session_overview_signout">Sign out of this session</string>
<string name="device_manager_session_details_title">Session details</string>
<string name="device_manager_session_details_description">Application, device, and activity information.</string>
<string name="device_manager_push_notifications_title">Push notifications</string>
<string name="device_manager_push_notifications_description">Receive push notifications on this session.</string>
<string name="device_manager_session_details_session_name">Session name</string>
<string name="device_manager_session_details_session_id">Session ID</string>
<string name="device_manager_session_details_session_last_activity">Last activity</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@
<attr name="sessionOverviewEntryDescription" format="string" />
</declare-styleable>

<declare-styleable name="SessionOverviewEntrySwitchView">
<attr name="sessionOverviewEntrySwitchTitle" format="string" />
<attr name="sessionOverviewEntrySwitchDescription" format="string" />
<attr name="sessionOverviewEntrySwitchEnabled" format="boolean" />
</declare-styleable>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ interface PushersService {
append: Boolean = true
)

/**
* Enables or disables a registered pusher.
*
* @param pusher The pusher being toggled
* @param enable Whether the pusher should be enabled or disabled
*/
suspend fun togglePusher(pusher: Pusher, enable: Boolean)

/**
* Directly ask the push gateway to send a push to this device.
* If successful, the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal class DefaultPushersService @Inject constructor(
private val getPusherTask: GetPushersTask,
private val pushGatewayNotifyTask: PushGatewayNotifyTask,
private val addPusherTask: AddPusherTask,
private val togglePusherTask: TogglePusherTask,
private val removePusherTask: RemovePusherTask,
private val taskExecutor: TaskExecutor
) : PushersService {
Expand Down Expand Up @@ -108,6 +109,24 @@ internal class DefaultPushersService @Inject constructor(
)
}

override suspend fun togglePusher(pusher: Pusher, enable: Boolean) {
togglePusherTask.execute(TogglePusherTask.Params(pusher.toJsonPusher(), enable))
}

private fun Pusher.toJsonPusher() = JsonPusher(
pushKey = pushKey,
kind = kind,
appId = appId,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
profileTag = profileTag,
lang = lang,
data = JsonPusherData(data.url, data.format),
append = false,
enabled = enabled,
deviceId = deviceId,
)

private fun enqueueAddPusher(pusher: JsonPusher): UUID {
val params = AddPusherWorker.Params(sessionId, pusher)
val request = workManagerProvider.matrixOneTimeWorkRequestBuilder<AddPusherWorker>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ internal abstract class PushersModule {
@Binds
abstract fun bindAddPusherTask(task: DefaultAddPusherTask): AddPusherTask

@Binds
abstract fun bindTogglePusherTask(task: DefaultTogglePusherTask): TogglePusherTask

@Binds
abstract fun bindRemovePusherTask(task: DefaultRemovePusherTask): RemovePusherTask

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.internal.session.pushers

import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.internal.database.model.PusherEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.RequestExecutor
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import javax.inject.Inject

internal interface TogglePusherTask : Task<TogglePusherTask.Params, Unit> {
data class Params(val pusher: JsonPusher, val enable: Boolean)
}

internal class DefaultTogglePusherTask @Inject constructor(
private val pushersAPI: PushersAPI,
@SessionDatabase private val monarchy: Monarchy,
private val requestExecutor: RequestExecutor,
private val globalErrorReceiver: GlobalErrorReceiver
) : TogglePusherTask {

override suspend fun execute(params: TogglePusherTask.Params) {
val pusher = params.pusher.copy(enabled = params.enable)

requestExecutor.executeRequest(globalErrorReceiver) {
pushersAPI.setPusher(pusher)
}

monarchy.awaitTransaction { realm ->
val entity = PusherEntity.where(realm, params.pusher.pushKey).findFirst()
entity?.apply { enabled = params.enable }?.let { realm.insertOrUpdate(it) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.internal.session.pushers

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.matrix.android.sdk.test.fakes.FakeAddPusherTask
import org.matrix.android.sdk.test.fakes.FakeGetPushersTask
import org.matrix.android.sdk.test.fakes.FakeMonarchy
import org.matrix.android.sdk.test.fakes.FakeRemovePusherTask
import org.matrix.android.sdk.test.fakes.FakeTaskExecutor
import org.matrix.android.sdk.test.fakes.FakeTogglePusherTask
import org.matrix.android.sdk.test.fakes.FakeWorkManagerProvider
import org.matrix.android.sdk.test.fakes.internal.FakePushGatewayNotifyTask
import org.matrix.android.sdk.test.fixtures.PusherFixture

@OptIn(ExperimentalCoroutinesApi::class)
class DefaultPushersServiceTest {

private val workManagerProvider = FakeWorkManagerProvider()
private val monarchy = FakeMonarchy()
private val sessionId = ""
private val getPushersTask = FakeGetPushersTask()
private val pushGatewayNotifyTask = FakePushGatewayNotifyTask()
private val addPusherTask = FakeAddPusherTask()
private val togglePusherTask = FakeTogglePusherTask()
private val removePusherTask = FakeRemovePusherTask()
private val taskExecutor = FakeTaskExecutor()

private val pushersService = DefaultPushersService(
workManagerProvider.instance,
monarchy.instance,
sessionId,
getPushersTask,
pushGatewayNotifyTask,
addPusherTask,
togglePusherTask,
removePusherTask,
taskExecutor.instance,
)

@Test
fun `when togglePusher, then execute task`() = runTest {
val pusher = PusherFixture.aPusher()
val enable = true

pushersService.togglePusher(pusher, enable)

togglePusherTask.verifyExecution(pusher, enable)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.internal.session.pushers

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
import org.matrix.android.sdk.internal.database.model.PusherEntity
import org.matrix.android.sdk.internal.database.model.PusherEntityFields
import org.matrix.android.sdk.test.fakes.FakeGlobalErrorReceiver
import org.matrix.android.sdk.test.fakes.FakeMonarchy
import org.matrix.android.sdk.test.fakes.FakePushersAPI
import org.matrix.android.sdk.test.fakes.FakeRequestExecutor
import org.matrix.android.sdk.test.fakes.givenEqualTo
import org.matrix.android.sdk.test.fakes.givenFindFirst
import org.matrix.android.sdk.test.fixtures.JsonPusherFixture.aJsonPusher
import org.matrix.android.sdk.test.fixtures.PusherEntityFixture.aPusherEntity

@OptIn(ExperimentalCoroutinesApi::class)
class DefaultTogglePusherTaskTest {

private val pushersAPI = FakePushersAPI()
private val monarchy = FakeMonarchy()
private val requestExecutor = FakeRequestExecutor()
private val globalErrorReceiver = FakeGlobalErrorReceiver()

private val togglePusherTask = DefaultTogglePusherTask(pushersAPI, monarchy.instance, requestExecutor, globalErrorReceiver)

@Test
fun `execution toggles enable on both local and remote`() = runTest {
val jsonPusher = aJsonPusher(enabled = false)
val params = TogglePusherTask.Params(aJsonPusher(), true)

val pusherEntity = aPusherEntity(enabled = false)
monarchy.givenWhere<PusherEntity>()
.givenEqualTo(PusherEntityFields.PUSH_KEY, jsonPusher.pushKey)
.givenFindFirst(pusherEntity)

togglePusherTask.execute(params)

val expectedPayload = jsonPusher.copy(enabled = true)
pushersAPI.verifySetPusher(expectedPayload)
monarchy.verifyInsertOrUpdate<PusherEntity> {
withArg { actual ->
actual.enabled shouldBeEqualTo true
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.test.fakes

import io.mockk.mockk
import org.matrix.android.sdk.internal.session.pushers.AddPusherTask

class FakeAddPusherTask : AddPusherTask by mockk()
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.test.fakes

import io.mockk.mockk
import org.matrix.android.sdk.internal.session.pushers.GetPushersTask

class FakeGetPushersTask : GetPushersTask by mockk()
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.test.fakes

import io.mockk.mockk
import org.matrix.android.sdk.internal.session.pushers.RemovePusherTask

class FakeRemovePusherTask : RemovePusherTask by mockk()
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.test.fakes

import io.mockk.mockk
import org.matrix.android.sdk.internal.task.TaskExecutor

internal class FakeTaskExecutor {

val instance: TaskExecutor = mockk()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* 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
*
* http://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.
*/

package org.matrix.android.sdk.test.fakes

import io.mockk.coVerify
import io.mockk.mockk
import io.mockk.slot
import org.amshove.kluent.shouldBeEqualTo
import org.matrix.android.sdk.api.session.pushers.Pusher
import org.matrix.android.sdk.internal.session.pushers.TogglePusherTask

class FakeTogglePusherTask : TogglePusherTask by mockk(relaxed = true) {

fun verifyExecution(pusher: Pusher, enable: Boolean) {
val slot = slot<TogglePusherTask.Params>()
coVerify { execute(capture(slot)) }
val params = slot.captured
params.pusher.pushKey shouldBeEqualTo pusher.pushKey
params.enable shouldBeEqualTo enable
}
}
Loading

0 comments on commit 2fe636e

Please sign in to comment.