Merge "Migrate Controls{ProviderSelector,Favoriting,Editing}Activities" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
10861bf19d
@@ -114,6 +114,7 @@ android_library {
|
|||||||
"androidx.dynamicanimation_dynamicanimation",
|
"androidx.dynamicanimation_dynamicanimation",
|
||||||
"androidx-constraintlayout_constraintlayout",
|
"androidx-constraintlayout_constraintlayout",
|
||||||
"androidx.exifinterface_exifinterface",
|
"androidx.exifinterface_exifinterface",
|
||||||
|
"androidx.test.ext.junit",
|
||||||
"com.google.android.material_material",
|
"com.google.android.material_material",
|
||||||
"kotlin-reflect",
|
"kotlin-reflect",
|
||||||
"kotlinx_coroutines_android",
|
"kotlinx_coroutines_android",
|
||||||
|
|||||||
@@ -20,11 +20,14 @@ import android.app.ActivityOptions
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewStub
|
import android.view.ViewStub
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
@@ -42,7 +45,7 @@ import javax.inject.Inject
|
|||||||
/**
|
/**
|
||||||
* Activity for rearranging and removing controls for a given structure
|
* Activity for rearranging and removing controls for a given structure
|
||||||
*/
|
*/
|
||||||
class ControlsEditingActivity @Inject constructor(
|
open class ControlsEditingActivity @Inject constructor(
|
||||||
private val controller: ControlsControllerImpl,
|
private val controller: ControlsControllerImpl,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val customIconCache: CustomIconCache,
|
private val customIconCache: CustomIconCache,
|
||||||
@@ -50,8 +53,9 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
) : ComponentActivity() {
|
) : ComponentActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val DEBUG = false
|
||||||
private const val TAG = "ControlsEditingActivity"
|
private const val TAG = "ControlsEditingActivity"
|
||||||
private const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE
|
const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE
|
||||||
private val SUBTITLE_ID = R.string.controls_favorite_rearrange
|
private val SUBTITLE_ID = R.string.controls_favorite_rearrange
|
||||||
private val EMPTY_TEXT_ID = R.string.controls_favorite_removed
|
private val EMPTY_TEXT_ID = R.string.controls_favorite_removed
|
||||||
}
|
}
|
||||||
@@ -73,6 +77,13 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val mOnBackInvokedCallback = OnBackInvokedCallback {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -94,11 +105,22 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
setUpList()
|
setUpList()
|
||||||
|
|
||||||
currentUserTracker.startTracking()
|
currentUserTracker.startTracking()
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Registered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
currentUserTracker.stopTracking()
|
currentUserTracker.stopTracking()
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Unregistered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.content.Intent
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -32,6 +33,8 @@ import android.widget.Button
|
|||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import com.android.systemui.Prefs
|
import com.android.systemui.Prefs
|
||||||
@@ -50,7 +53,7 @@ import java.util.concurrent.Executor
|
|||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ControlsFavoritingActivity @Inject constructor(
|
open class ControlsFavoritingActivity @Inject constructor(
|
||||||
@Main private val executor: Executor,
|
@Main private val executor: Executor,
|
||||||
private val controller: ControlsControllerImpl,
|
private val controller: ControlsControllerImpl,
|
||||||
private val listingController: ControlsListingController,
|
private val listingController: ControlsListingController,
|
||||||
@@ -59,6 +62,7 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
) : ComponentActivity() {
|
) : ComponentActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val DEBUG = false
|
||||||
private const val TAG = "ControlsFavoritingActivity"
|
private const val TAG = "ControlsFavoritingActivity"
|
||||||
|
|
||||||
// If provided and no structure is available, use as the title
|
// If provided and no structure is available, use as the title
|
||||||
@@ -67,7 +71,7 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
// If provided, show this structure page first
|
// If provided, show this structure page first
|
||||||
const val EXTRA_STRUCTURE = "extra_structure"
|
const val EXTRA_STRUCTURE = "extra_structure"
|
||||||
const val EXTRA_SINGLE_STRUCTURE = "extra_single_structure"
|
const val EXTRA_SINGLE_STRUCTURE = "extra_single_structure"
|
||||||
internal const val EXTRA_FROM_PROVIDER_SELECTOR = "extra_from_provider_selector"
|
const val EXTRA_FROM_PROVIDER_SELECTOR = "extra_from_provider_selector"
|
||||||
private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
|
private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
|
||||||
private const val TOOLTIP_MAX_SHOWN = 2
|
private const val TOOLTIP_MAX_SHOWN = 2
|
||||||
}
|
}
|
||||||
@@ -102,6 +106,13 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val mOnBackInvokedCallback = OnBackInvokedCallback {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
|
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
|
||||||
|
|
||||||
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
||||||
@@ -353,6 +364,12 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
|
|
||||||
listingController.addCallback(listingCallback)
|
listingController.addCallback(listingCallback)
|
||||||
currentUserTracker.startTracking()
|
currentUserTracker.startTracking()
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Registered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -372,6 +389,12 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
|
|
||||||
listingController.removeCallback(listingCallback)
|
listingController.removeCallback(listingCallback)
|
||||||
currentUserTracker.stopTracking()
|
currentUserTracker.stopTracking()
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Unregistered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.unregisterOnBackInvokedCallback(
|
||||||
|
mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
|||||||
@@ -20,16 +20,18 @@ import android.app.ActivityOptions
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewStub
|
import android.view.ViewStub
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
|
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
import com.android.systemui.controls.controller.ControlsController
|
import com.android.systemui.controls.controller.ControlsController
|
||||||
@@ -44,7 +46,7 @@ import javax.inject.Inject
|
|||||||
/**
|
/**
|
||||||
* Activity to select an application to favorite the [Control] provided by them.
|
* Activity to select an application to favorite the [Control] provided by them.
|
||||||
*/
|
*/
|
||||||
class ControlsProviderSelectorActivity @Inject constructor(
|
open class ControlsProviderSelectorActivity @Inject constructor(
|
||||||
@Main private val executor: Executor,
|
@Main private val executor: Executor,
|
||||||
@Background private val backExecutor: Executor,
|
@Background private val backExecutor: Executor,
|
||||||
private val listingController: ControlsListingController,
|
private val listingController: ControlsListingController,
|
||||||
@@ -54,6 +56,7 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
) : ComponentActivity() {
|
) : ComponentActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val DEBUG = false
|
||||||
private const val TAG = "ControlsProviderSelectorActivity"
|
private const val TAG = "ControlsProviderSelectorActivity"
|
||||||
const val BACK_SHOULD_EXIT = "back_should_exit"
|
const val BACK_SHOULD_EXIT = "back_should_exit"
|
||||||
}
|
}
|
||||||
@@ -70,6 +73,13 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val mOnBackInvokedCallback = OnBackInvokedCallback {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -141,11 +151,22 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Registered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
currentUserTracker.stopTracking()
|
currentUserTracker.stopTracking()
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Unregistered onBackInvokedCallback")
|
||||||
|
}
|
||||||
|
onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -93,6 +93,21 @@
|
|||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<activity android:name="com.android.systemui.controls.management.ControlsEditingActivityTest$TestableControlsEditingActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<activity android:name="com.android.systemui.controls.management.ControlsFavoritingActivityTest$TestableControlsFavoritingActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<activity android:name="com.android.systemui.controls.management.ControlsProviderSelectorActivityTest$TestableControlsProviderSelectorActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
/>
|
||||||
|
|
||||||
<activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
|
<activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.controls.CustomIconCache
|
||||||
|
import com.android.systemui.controls.controller.ControlsControllerImpl
|
||||||
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatchers
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
class ControlsEditingActivityTest : SysuiTestCase() {
|
||||||
|
@Mock lateinit var controller: ControlsControllerImpl
|
||||||
|
|
||||||
|
@Mock lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||||
|
|
||||||
|
@Mock lateinit var customIconCache: CustomIconCache
|
||||||
|
|
||||||
|
@Mock lateinit var uiController: ControlsUiController
|
||||||
|
|
||||||
|
private lateinit var controlsEditingActivity: ControlsEditingActivity_Factory
|
||||||
|
private var latch: CountDownLatch = CountDownLatch(1)
|
||||||
|
|
||||||
|
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
|
||||||
|
@Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback>
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
var activityRule =
|
||||||
|
ActivityTestRule(
|
||||||
|
object :
|
||||||
|
SingleActivityFactory<TestableControlsEditingActivity>(
|
||||||
|
TestableControlsEditingActivity::class.java
|
||||||
|
) {
|
||||||
|
override fun create(intent: Intent?): TestableControlsEditingActivity {
|
||||||
|
return TestableControlsEditingActivity(
|
||||||
|
controller,
|
||||||
|
broadcastDispatcher,
|
||||||
|
customIconCache,
|
||||||
|
uiController,
|
||||||
|
mockDispatcher,
|
||||||
|
latch
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
val intent = Intent()
|
||||||
|
intent.putExtra(ControlsEditingActivity.EXTRA_STRUCTURE, "TestTitle")
|
||||||
|
val cname = ComponentName("TestPackageName", "TestClassName")
|
||||||
|
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, cname)
|
||||||
|
activityRule.launchActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBackCallbackRegistrationAndUnregistration() {
|
||||||
|
// 1. ensure that launching the activity results in it registering a callback
|
||||||
|
verify(mockDispatcher)
|
||||||
|
.registerOnBackInvokedCallback(
|
||||||
|
ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
|
||||||
|
captureCallback.capture()
|
||||||
|
)
|
||||||
|
activityRule.finishActivity()
|
||||||
|
latch.await() // ensure activity is finished
|
||||||
|
// 2. ensure that when the activity is finished, it unregisters the same callback
|
||||||
|
verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestableControlsEditingActivity(
|
||||||
|
private val controller: ControlsControllerImpl,
|
||||||
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
|
private val customIconCache: CustomIconCache,
|
||||||
|
private val uiController: ControlsUiController,
|
||||||
|
private val mockDispatcher: OnBackInvokedDispatcher,
|
||||||
|
private val latch: CountDownLatch
|
||||||
|
) : ControlsEditingActivity(controller, broadcastDispatcher, customIconCache, uiController) {
|
||||||
|
override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher {
|
||||||
|
return mockDispatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
// ensures that test runner thread does not proceed until ui thread is done
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.controls.controller.ControlsControllerImpl
|
||||||
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatchers
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
class ControlsFavoritingActivityTest : SysuiTestCase() {
|
||||||
|
@Main private val executor: Executor = MoreExecutors.directExecutor()
|
||||||
|
|
||||||
|
@Mock lateinit var controller: ControlsControllerImpl
|
||||||
|
|
||||||
|
@Mock lateinit var listingController: ControlsListingController
|
||||||
|
|
||||||
|
@Mock lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||||
|
|
||||||
|
@Mock lateinit var uiController: ControlsUiController
|
||||||
|
|
||||||
|
private lateinit var controlsFavoritingActivity: ControlsFavoritingActivity_Factory
|
||||||
|
private var latch: CountDownLatch = CountDownLatch(1)
|
||||||
|
|
||||||
|
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
|
||||||
|
@Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback>
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
var activityRule =
|
||||||
|
ActivityTestRule(
|
||||||
|
object :
|
||||||
|
SingleActivityFactory<TestableControlsFavoritingActivity>(
|
||||||
|
TestableControlsFavoritingActivity::class.java
|
||||||
|
) {
|
||||||
|
override fun create(intent: Intent?): TestableControlsFavoritingActivity {
|
||||||
|
return TestableControlsFavoritingActivity(
|
||||||
|
executor,
|
||||||
|
controller,
|
||||||
|
listingController,
|
||||||
|
broadcastDispatcher,
|
||||||
|
uiController,
|
||||||
|
mockDispatcher,
|
||||||
|
latch
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
val intent = Intent()
|
||||||
|
intent.putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true)
|
||||||
|
activityRule.launchActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBackCallbackRegistrationAndUnregistration() {
|
||||||
|
// 1. ensure that launching the activity results in it registering a callback
|
||||||
|
verify(mockDispatcher)
|
||||||
|
.registerOnBackInvokedCallback(
|
||||||
|
ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
|
||||||
|
captureCallback.capture()
|
||||||
|
)
|
||||||
|
activityRule.finishActivity()
|
||||||
|
latch.await() // ensure activity is finished
|
||||||
|
// 2. ensure that when the activity is finished, it unregisters the same callback
|
||||||
|
verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestableControlsFavoritingActivity(
|
||||||
|
executor: Executor,
|
||||||
|
controller: ControlsControllerImpl,
|
||||||
|
listingController: ControlsListingController,
|
||||||
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
|
uiController: ControlsUiController,
|
||||||
|
private val mockDispatcher: OnBackInvokedDispatcher,
|
||||||
|
private val latch: CountDownLatch
|
||||||
|
) :
|
||||||
|
ControlsFavoritingActivity(
|
||||||
|
executor,
|
||||||
|
controller,
|
||||||
|
listingController,
|
||||||
|
broadcastDispatcher,
|
||||||
|
uiController
|
||||||
|
) {
|
||||||
|
override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher {
|
||||||
|
return mockDispatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
// ensures that test runner thread does not proceed until ui thread is done
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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
|
||||||
|
*
|
||||||
|
* 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 com.android.systemui.controls.management
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.window.OnBackInvokedCallback
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.controls.controller.ControlsController
|
||||||
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatchers
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
class ControlsProviderSelectorActivityTest : SysuiTestCase() {
|
||||||
|
@Main private val executor: Executor = MoreExecutors.directExecutor()
|
||||||
|
|
||||||
|
@Background private val backExecutor: Executor = MoreExecutors.directExecutor()
|
||||||
|
|
||||||
|
@Mock lateinit var listingController: ControlsListingController
|
||||||
|
|
||||||
|
@Mock lateinit var controlsController: ControlsController
|
||||||
|
|
||||||
|
@Mock lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||||
|
|
||||||
|
@Mock lateinit var uiController: ControlsUiController
|
||||||
|
|
||||||
|
private lateinit var controlsProviderSelectorActivity: ControlsProviderSelectorActivity_Factory
|
||||||
|
private var latch: CountDownLatch = CountDownLatch(1)
|
||||||
|
|
||||||
|
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
|
||||||
|
@Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback>
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
var activityRule =
|
||||||
|
ActivityTestRule(
|
||||||
|
object :
|
||||||
|
SingleActivityFactory<TestableControlsProviderSelectorActivity>(
|
||||||
|
TestableControlsProviderSelectorActivity::class.java
|
||||||
|
) {
|
||||||
|
override fun create(intent: Intent?): TestableControlsProviderSelectorActivity {
|
||||||
|
return TestableControlsProviderSelectorActivity(
|
||||||
|
executor,
|
||||||
|
backExecutor,
|
||||||
|
listingController,
|
||||||
|
controlsController,
|
||||||
|
broadcastDispatcher,
|
||||||
|
uiController,
|
||||||
|
mockDispatcher,
|
||||||
|
latch
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
val intent = Intent()
|
||||||
|
intent.putExtra(ControlsProviderSelectorActivity.BACK_SHOULD_EXIT, true)
|
||||||
|
activityRule.launchActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBackCallbackRegistrationAndUnregistration() {
|
||||||
|
// 1. ensure that launching the activity results in it registering a callback
|
||||||
|
verify(mockDispatcher)
|
||||||
|
.registerOnBackInvokedCallback(
|
||||||
|
ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
|
||||||
|
captureCallback.capture()
|
||||||
|
)
|
||||||
|
activityRule.finishActivity()
|
||||||
|
latch.await() // ensure activity is finished
|
||||||
|
// 2. ensure that when the activity is finished, it unregisters the same callback
|
||||||
|
verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestableControlsProviderSelectorActivity(
|
||||||
|
executor: Executor,
|
||||||
|
backExecutor: Executor,
|
||||||
|
listingController: ControlsListingController,
|
||||||
|
controlsController: ControlsController,
|
||||||
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
|
uiController: ControlsUiController,
|
||||||
|
private val mockDispatcher: OnBackInvokedDispatcher,
|
||||||
|
private val latch: CountDownLatch
|
||||||
|
) :
|
||||||
|
ControlsProviderSelectorActivity(
|
||||||
|
executor,
|
||||||
|
backExecutor,
|
||||||
|
listingController,
|
||||||
|
controlsController,
|
||||||
|
broadcastDispatcher,
|
||||||
|
uiController
|
||||||
|
) {
|
||||||
|
override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher {
|
||||||
|
return mockDispatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
// ensures that test runner thread does not proceed until ui thread is done
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user