Merge "Controls in QS" into sc-dev
This commit is contained in:
@@ -757,6 +757,7 @@
|
|||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:showWhenLocked="true"
|
android:showWhenLocked="true"
|
||||||
android:showForAllUsers="true"
|
android:showForAllUsers="true"
|
||||||
|
android:finishOnTaskLaunch="true"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
|
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
|
||||||
android:visibleToInstantApps="true">
|
android:visibleToInstantApps="true">
|
||||||
|
|||||||
@@ -30,12 +30,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/global_actions_controls"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.android.systemui.globalactions.MinHeightScrollView>
|
</com.android.systemui.globalactions.MinHeightScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ import com.android.systemui.controls.ui.ControlsUiController
|
|||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Background
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
import com.android.systemui.globalactions.GlobalActionsDialog
|
|
||||||
import com.android.systemui.settings.UserTracker
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
|
||||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
import java.io.FileDescriptor
|
import java.io.FileDescriptor
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
@@ -198,11 +199,11 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
// When a component is uninstalled, allow seeding to happen again if the user
|
// When a component is uninstalled, allow seeding to happen again if the user
|
||||||
// reinstalls the app
|
// reinstalls the app
|
||||||
val prefs = userStructure.userContext.getSharedPreferences(
|
val prefs = userStructure.userContext.getSharedPreferences(
|
||||||
GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
|
PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
|
||||||
val completedSeedingPackageSet = prefs.getStringSet(
|
val completedSeedingPackageSet = prefs.getStringSet(
|
||||||
GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
|
PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
|
||||||
val servicePackageSet = serviceInfoSet.map { it.packageName }
|
val servicePackageSet = serviceInfoSet.map { it.packageName }
|
||||||
prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
|
prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
|
||||||
completedSeedingPackageSet.intersect(servicePackageSet)).apply()
|
completedSeedingPackageSet.intersect(servicePackageSet)).apply()
|
||||||
|
|
||||||
var changed = false
|
var changed = false
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.controls.management
|
package com.android.systemui.controls.management
|
||||||
|
|
||||||
|
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
|
||||||
@@ -34,7 +35,6 @@ import com.android.systemui.controls.controller.ControlsControllerImpl
|
|||||||
import com.android.systemui.controls.controller.StructureInfo
|
import com.android.systemui.controls.controller.StructureInfo
|
||||||
import com.android.systemui.controls.ui.ControlsActivity
|
import com.android.systemui.controls.ui.ControlsActivity
|
||||||
import com.android.systemui.controls.ui.ControlsUiController
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
|
||||||
import com.android.systemui.settings.CurrentUserTracker
|
import com.android.systemui.settings.CurrentUserTracker
|
||||||
import com.android.systemui.util.LifecycleActivity
|
import com.android.systemui.util.LifecycleActivity
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -45,7 +45,6 @@ import javax.inject.Inject
|
|||||||
class ControlsEditingActivity @Inject constructor(
|
class ControlsEditingActivity @Inject constructor(
|
||||||
private val controller: ControlsControllerImpl,
|
private val controller: ControlsControllerImpl,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val globalActionsComponent: GlobalActionsComponent,
|
|
||||||
private val customIconCache: CustomIconCache,
|
private val customIconCache: CustomIconCache,
|
||||||
private val uiController: ControlsUiController
|
private val uiController: ControlsUiController
|
||||||
) : LifecycleActivity() {
|
) : LifecycleActivity() {
|
||||||
@@ -62,7 +61,6 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
private lateinit var model: FavoritesModel
|
private lateinit var model: FavoritesModel
|
||||||
private lateinit var subtitle: TextView
|
private lateinit var subtitle: TextView
|
||||||
private lateinit var saveButton: View
|
private lateinit var saveButton: View
|
||||||
private var backToGlobalActions = true
|
|
||||||
|
|
||||||
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
||||||
private val startingUser = controller.currentUserId
|
private val startingUser = controller.currentUserId
|
||||||
@@ -86,11 +84,6 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
structure = it
|
structure = it
|
||||||
} ?: run(this::finish)
|
} ?: run(this::finish)
|
||||||
|
|
||||||
backToGlobalActions = intent.getBooleanExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
bindViews()
|
bindViews()
|
||||||
|
|
||||||
bindButtons()
|
bindButtons()
|
||||||
@@ -109,15 +102,6 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (backToGlobalActions) {
|
|
||||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
|
||||||
} else {
|
|
||||||
val i = Intent().apply {
|
|
||||||
component = ComponentName(applicationContext, ControlsActivity::class.java)
|
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
startActivity(i)
|
|
||||||
}
|
|
||||||
animateExitAndFinish()
|
animateExitAndFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +145,12 @@ class ControlsEditingActivity @Inject constructor(
|
|||||||
setText(R.string.save)
|
setText(R.string.save)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
saveFavorites()
|
saveFavorites()
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, ControlsActivity::class.java),
|
||||||
|
ActivityOptions
|
||||||
|
.makeSceneTransitionAnimation(this@ControlsEditingActivity).toBundle()
|
||||||
|
)
|
||||||
animateExitAndFinish()
|
animateExitAndFinish()
|
||||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import com.android.systemui.controls.controller.StructureInfo
|
|||||||
import com.android.systemui.controls.ui.ControlsActivity
|
import com.android.systemui.controls.ui.ControlsActivity
|
||||||
import com.android.systemui.controls.ui.ControlsUiController
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
|
||||||
import com.android.systemui.settings.CurrentUserTracker
|
import com.android.systemui.settings.CurrentUserTracker
|
||||||
import com.android.systemui.util.LifecycleActivity
|
import com.android.systemui.util.LifecycleActivity
|
||||||
import java.text.Collator
|
import java.text.Collator
|
||||||
@@ -56,7 +55,6 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
private val controller: ControlsControllerImpl,
|
private val controller: ControlsControllerImpl,
|
||||||
private val listingController: ControlsListingController,
|
private val listingController: ControlsListingController,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val globalActionsComponent: GlobalActionsComponent,
|
|
||||||
private val uiController: ControlsUiController
|
private val uiController: ControlsUiController
|
||||||
) : LifecycleActivity() {
|
) : LifecycleActivity() {
|
||||||
|
|
||||||
@@ -92,7 +90,6 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
private lateinit var comparator: Comparator<StructureContainer>
|
private lateinit var comparator: Comparator<StructureContainer>
|
||||||
private var cancelLoadRunnable: Runnable? = null
|
private var cancelLoadRunnable: Runnable? = null
|
||||||
private var isPagerLoaded = false
|
private var isPagerLoaded = false
|
||||||
private var backToGlobalActions = true
|
|
||||||
|
|
||||||
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
||||||
private val startingUser = controller.currentUserId
|
private val startingUser = controller.currentUserId
|
||||||
@@ -133,11 +130,6 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
|
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
|
||||||
fromProviderSelector = intent.getBooleanExtra(EXTRA_FROM_PROVIDER_SELECTOR, false)
|
fromProviderSelector = intent.getBooleanExtra(EXTRA_FROM_PROVIDER_SELECTOR, false)
|
||||||
|
|
||||||
backToGlobalActions = intent.getBooleanExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
bindViews()
|
bindViews()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,13 +303,6 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
private fun bindButtons() {
|
private fun bindButtons() {
|
||||||
otherAppsButton = requireViewById<Button>(R.id.other_apps).apply {
|
otherAppsButton = requireViewById<Button>(R.id.other_apps).apply {
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val i = Intent().apply {
|
|
||||||
component = ComponentName(context, ControlsProviderSelectorActivity::class.java)
|
|
||||||
putExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
backToGlobalActions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (doneButton.isEnabled) {
|
if (doneButton.isEnabled) {
|
||||||
// The user has made changes
|
// The user has made changes
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
@@ -326,8 +311,11 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
startActivity(i, ActivityOptions
|
startActivity(
|
||||||
.makeSceneTransitionAnimation(this@ControlsFavoritingActivity).toBundle())
|
Intent(context, ControlsProviderSelectorActivity::class.java),
|
||||||
|
ActivityOptions
|
||||||
|
.makeSceneTransitionAnimation(this@ControlsFavoritingActivity).toBundle()
|
||||||
|
)
|
||||||
animateExitAndFinish()
|
animateExitAndFinish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,15 +337,10 @@ class ControlsFavoritingActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openControlsOrigin() {
|
private fun openControlsOrigin() {
|
||||||
if (backToGlobalActions) {
|
startActivity(
|
||||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
Intent(applicationContext, ControlsActivity::class.java),
|
||||||
} else {
|
ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
|
||||||
val i = Intent().apply {
|
)
|
||||||
component = ComponentName(applicationContext, ControlsActivity::class.java)
|
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
startActivity(i)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import com.android.systemui.controls.ui.ControlsActivity
|
|||||||
import com.android.systemui.controls.ui.ControlsUiController
|
import com.android.systemui.controls.ui.ControlsUiController
|
||||||
import com.android.systemui.dagger.qualifiers.Background
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
|
||||||
import com.android.systemui.settings.CurrentUserTracker
|
import com.android.systemui.settings.CurrentUserTracker
|
||||||
import com.android.systemui.util.LifecycleActivity
|
import com.android.systemui.util.LifecycleActivity
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
@@ -50,7 +49,6 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
@Background private val backExecutor: Executor,
|
@Background private val backExecutor: Executor,
|
||||||
private val listingController: ControlsListingController,
|
private val listingController: ControlsListingController,
|
||||||
private val controlsController: ControlsController,
|
private val controlsController: ControlsController,
|
||||||
private val globalActionsComponent: GlobalActionsComponent,
|
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val uiController: ControlsUiController
|
private val uiController: ControlsUiController
|
||||||
) : LifecycleActivity() {
|
) : LifecycleActivity() {
|
||||||
@@ -59,7 +57,6 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
private const val TAG = "ControlsProviderSelectorActivity"
|
private const val TAG = "ControlsProviderSelectorActivity"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var backToGlobalActions = true
|
|
||||||
private lateinit var recyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
||||||
private val startingUser = listingController.currentUserId
|
private val startingUser = listingController.currentUserId
|
||||||
@@ -105,23 +102,13 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
requireViewById<View>(R.id.done).visibility = View.GONE
|
requireViewById<View>(R.id.done).visibility = View.GONE
|
||||||
|
|
||||||
backToGlobalActions = intent.getBooleanExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (backToGlobalActions) {
|
val i = Intent().apply {
|
||||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
component = ComponentName(applicationContext, ControlsActivity::class.java)
|
||||||
} else {
|
|
||||||
val i = Intent().apply {
|
|
||||||
component = ComponentName(applicationContext, ControlsActivity::class.java)
|
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
startActivity(i)
|
|
||||||
}
|
}
|
||||||
|
startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
|
||||||
animateExitAndFinish()
|
animateExitAndFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,10 +156,6 @@ class ControlsProviderSelectorActivity @Inject constructor(
|
|||||||
listingController.getAppLabel(it))
|
listingController.getAppLabel(it))
|
||||||
putExtra(Intent.EXTRA_COMPONENT_NAME, it)
|
putExtra(Intent.EXTRA_COMPONENT_NAME, it)
|
||||||
putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true)
|
putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true)
|
||||||
putExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
backToGlobalActions
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
|
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
|
||||||
animateExitAndFinish()
|
animateExitAndFinish()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.service.controls.Control
|
|||||||
interface ControlActionCoordinator {
|
interface ControlActionCoordinator {
|
||||||
|
|
||||||
// If launched from an Activity, continue within this stack
|
// If launched from an Activity, continue within this stack
|
||||||
var activityContext: Context?
|
var activityContext: Context
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close any dialogs which may have been open
|
* Close any dialogs which may have been open
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
|||||||
private var actionsInProgress = mutableSetOf<String>()
|
private var actionsInProgress = mutableSetOf<String>()
|
||||||
private val isLocked: Boolean
|
private val isLocked: Boolean
|
||||||
get() = !keyguardStateController.isUnlocked()
|
get() = !keyguardStateController.isUnlocked()
|
||||||
override var activityContext: Context? = null
|
override lateinit var activityContext: Context
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L
|
private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L
|
||||||
@@ -153,14 +153,9 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
|||||||
// pending actions will only run after the control state has been refreshed
|
// pending actions will only run after the control state has been refreshed
|
||||||
pendingAction = action
|
pendingAction = action
|
||||||
}
|
}
|
||||||
val wasLocked = isLocked
|
|
||||||
activityStarter.dismissKeyguardThenExecute({
|
activityStarter.dismissKeyguardThenExecute({
|
||||||
Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action")
|
Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action")
|
||||||
if (wasLocked && activityContext == null) {
|
action.invoke()
|
||||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
|
||||||
} else {
|
|
||||||
action.invoke()
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}, { pendingAction = null }, true /* afterKeyguardGone */)
|
}, { pendingAction = null }, true /* afterKeyguardGone */)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ class ControlsActivity @Inject constructor(
|
|||||||
|
|
||||||
setContentView(R.layout.controls_fullscreen)
|
setContentView(R.layout.controls_fullscreen)
|
||||||
|
|
||||||
|
getLifecycle().addObserver(
|
||||||
|
ControlsAnimations.observerForAnimations(
|
||||||
|
requireViewById<ViewGroup>(R.id.control_detail_root),
|
||||||
|
window,
|
||||||
|
intent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
requireViewById<ViewGroup>(R.id.control_detail_root).apply {
|
requireViewById<ViewGroup>(R.id.control_detail_root).apply {
|
||||||
setOnApplyWindowInsetsListener {
|
setOnApplyWindowInsetsListener {
|
||||||
v: View, insets: WindowInsets ->
|
v: View, insets: WindowInsets ->
|
||||||
@@ -61,7 +69,7 @@ class ControlsActivity @Inject constructor(
|
|||||||
|
|
||||||
parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
|
parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
|
||||||
parent.alpha = 0f
|
parent.alpha = 0f
|
||||||
uiController.show(parent, { animateExitAndFinish() }, this)
|
uiController.show(parent, { finish() }, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -71,7 +79,7 @@ class ControlsActivity @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
animateExitAndFinish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
@@ -79,8 +87,4 @@ class ControlsActivity @Inject constructor(
|
|||||||
|
|
||||||
uiController.hide()
|
uiController.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animateExitAndFinish() {
|
|
||||||
ControlsAnimations.exitAnimation(parent, { finish() }).start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,9 @@ interface ControlsUiController {
|
|||||||
companion object {
|
companion object {
|
||||||
public const val TAG = "ControlsUiController"
|
public const val TAG = "ControlsUiController"
|
||||||
public const val EXTRA_ANIMATE = "extra_animate"
|
public const val EXTRA_ANIMATE = "extra_animate"
|
||||||
public const val BACK_TO_GLOBAL_ACTIONS = "back_to_global_actions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context?)
|
fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context)
|
||||||
fun hide()
|
fun hide()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package com.android.systemui.controls.ui
|
|||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.ActivityOptions
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -129,6 +131,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
override val available: Boolean
|
override val available: Boolean
|
||||||
get() = controlsController.get().available
|
get() = controlsController.get().available
|
||||||
|
|
||||||
|
private lateinit var activityContext: Context
|
||||||
private lateinit var listingCallback: ControlsListingController.ControlsListingCallback
|
private lateinit var listingCallback: ControlsListingController.ControlsListingCallback
|
||||||
|
|
||||||
private fun createCallback(
|
private fun createCallback(
|
||||||
@@ -153,11 +156,12 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
override fun show(
|
override fun show(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
onDismiss: Runnable,
|
onDismiss: Runnable,
|
||||||
activityContext: Context?
|
activityContext: Context
|
||||||
) {
|
) {
|
||||||
Log.d(ControlsUiController.TAG, "show()")
|
Log.d(ControlsUiController.TAG, "show()")
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
this.onDismiss = onDismiss
|
this.onDismiss = onDismiss
|
||||||
|
this.activityContext = activityContext
|
||||||
hidden = false
|
hidden = false
|
||||||
retainCache = false
|
retainCache = false
|
||||||
|
|
||||||
@@ -198,7 +202,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
controlViewsById.clear()
|
controlViewsById.clear()
|
||||||
controlsById.clear()
|
controlsById.clear()
|
||||||
|
|
||||||
show(parent, onDismiss, controlActionCoordinator.activityContext)
|
show(parent, onDismiss, activityContext)
|
||||||
val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f)
|
val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f)
|
||||||
showAnim.setInterpolator(DecelerateInterpolator(1.0f))
|
showAnim.setInterpolator(DecelerateInterpolator(1.0f))
|
||||||
showAnim.setDuration(FADE_IN_MILLIS)
|
showAnim.setDuration(FADE_IN_MILLIS)
|
||||||
@@ -220,7 +224,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
inflater.inflate(R.layout.controls_no_favorites, parent, true)
|
inflater.inflate(R.layout.controls_no_favorites, parent, true)
|
||||||
|
|
||||||
val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
|
val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
|
||||||
viewGroup.setOnClickListener { v: View -> startProviderSelectorActivity(v.context) }
|
viewGroup.setOnClickListener { _: View -> startProviderSelectorActivity() }
|
||||||
|
|
||||||
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
|
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
|
||||||
subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle))
|
subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle))
|
||||||
@@ -234,20 +238,18 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startFavoritingActivity(context: Context, si: StructureInfo) {
|
private fun startFavoritingActivity(si: StructureInfo) {
|
||||||
startTargetedActivity(context, si, ControlsFavoritingActivity::class.java)
|
startTargetedActivity(si, ControlsFavoritingActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startEditingActivity(context: Context, si: StructureInfo) {
|
private fun startEditingActivity(si: StructureInfo) {
|
||||||
startTargetedActivity(context, si, ControlsEditingActivity::class.java)
|
startTargetedActivity(si, ControlsEditingActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startTargetedActivity(context: Context, si: StructureInfo, klazz: Class<*>) {
|
private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
|
||||||
val i = Intent(context, klazz).apply {
|
val i = Intent(activityContext, klazz)
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
putIntentExtras(i, si)
|
putIntentExtras(i, si)
|
||||||
startActivity(context, i)
|
startActivity(i)
|
||||||
|
|
||||||
retainCache = true
|
retainCache = true
|
||||||
}
|
}
|
||||||
@@ -261,27 +263,22 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startProviderSelectorActivity(context: Context) {
|
private fun startProviderSelectorActivity() {
|
||||||
val i = Intent(context, ControlsProviderSelectorActivity::class.java).apply {
|
startActivity(Intent(activityContext, ControlsProviderSelectorActivity::class.java))
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
startActivity(context, i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startActivity(context: Context, intent: Intent) {
|
private fun startActivity(intent: Intent) {
|
||||||
// Force animations when transitioning from a dialog to an activity
|
// Force animations when transitioning from a dialog to an activity
|
||||||
intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
|
intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
|
||||||
intent.putExtra(
|
|
||||||
ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
|
|
||||||
controlActionCoordinator.activityContext == null
|
|
||||||
)
|
|
||||||
onDismiss.run()
|
|
||||||
|
|
||||||
activityStarter.dismissKeyguardThenExecute({
|
if (keyguardStateController.isUnlocked()) {
|
||||||
shadeController.collapsePanel(false)
|
activityContext.startActivity(
|
||||||
context.startActivity(intent)
|
intent,
|
||||||
true
|
ActivityOptions.makeSceneTransitionAnimation(activityContext as Activity).toBundle()
|
||||||
}, null, true)
|
)
|
||||||
|
} else {
|
||||||
|
activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showControlsView(items: List<SelectionItem>) {
|
private fun showControlsView(items: List<SelectionItem>) {
|
||||||
@@ -328,9 +325,9 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
) {
|
) {
|
||||||
when (pos) {
|
when (pos) {
|
||||||
// 0: Add Control
|
// 0: Add Control
|
||||||
0 -> startFavoritingActivity(view.context, selectedStructure)
|
0 -> startFavoritingActivity(selectedStructure)
|
||||||
// 1: Edit controls
|
// 1: Edit controls
|
||||||
1 -> startEditingActivity(view.context, selectedStructure)
|
1 -> startEditingActivity(selectedStructure)
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
@@ -399,15 +396,9 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
val inflater = LayoutInflater.from(context)
|
val inflater = LayoutInflater.from(context)
|
||||||
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
||||||
|
|
||||||
if (controlActionCoordinator.activityContext == null) {
|
parent.requireViewById<ImageView>(R.id.controls_close).apply {
|
||||||
parent.requireViewById<View>(R.id.controls_spacer).apply {
|
setOnClickListener { _: View -> onDismiss.run() }
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parent.requireViewById<ImageView>(R.id.controls_close).apply {
|
|
||||||
setOnClickListener { _: View -> onDismiss.run() }
|
|
||||||
visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxColumns = findMaxColumns()
|
val maxColumns = findMaxColumns()
|
||||||
@@ -522,8 +513,6 @@ class ControlsUiControllerImpl @Inject constructor (
|
|||||||
override fun hide() {
|
override fun hide() {
|
||||||
hidden = true
|
hidden = true
|
||||||
|
|
||||||
controlActionCoordinator.activityContext = null
|
|
||||||
|
|
||||||
closeDialogs(true)
|
closeDialogs(true)
|
||||||
controlsController.get().unsubscribe()
|
controlsController.get().unsubscribe()
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ package com.android.systemui.globalactions;
|
|||||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
|
||||||
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
|
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
|
||||||
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
|
|
||||||
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK;
|
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
|
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
@@ -30,10 +28,8 @@ import android.app.IActivityManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.trust.TrustManager;
|
import android.app.trust.TrustManager;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -47,7 +43,6 @@ import android.telecom.TelecomManager;
|
|||||||
import android.transition.AutoTransition;
|
import android.transition.AutoTransition;
|
||||||
import android.transition.TransitionManager;
|
import android.transition.TransitionManager;
|
||||||
import android.transition.TransitionSet;
|
import android.transition.TransitionSet;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.IWindowManager;
|
import android.view.IWindowManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -69,18 +64,12 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
import com.android.systemui.Interpolators;
|
import com.android.systemui.Interpolators;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
import com.android.systemui.controls.ControlsServiceInfo;
|
|
||||||
import com.android.systemui.controls.controller.ControlsController;
|
|
||||||
import com.android.systemui.controls.dagger.ControlsComponent;
|
|
||||||
import com.android.systemui.controls.management.ControlsAnimations;
|
|
||||||
import com.android.systemui.controls.ui.ControlsUiController;
|
|
||||||
import com.android.systemui.dagger.qualifiers.Background;
|
import com.android.systemui.dagger.qualifiers.Background;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.model.SysUiState;
|
import com.android.systemui.model.SysUiState;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
|
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
|
||||||
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
|
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
|
||||||
import com.android.systemui.settings.UserContextProvider;
|
|
||||||
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
||||||
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
@@ -91,12 +80,6 @@ import com.android.systemui.util.leak.RotationUtils;
|
|||||||
import com.android.systemui.util.settings.GlobalSettings;
|
import com.android.systemui.util.settings.GlobalSettings;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -105,7 +88,7 @@ import javax.inject.Provider;
|
|||||||
/**
|
/**
|
||||||
* Helper to show the global actions dialog. Each item is an {@link Action} that may show depending
|
* Helper to show the global actions dialog. Each item is an {@link Action} that may show depending
|
||||||
* on whether the keyguard is showing, and whether the device is provisioned.
|
* on whether the keyguard is showing, and whether the device is provisioned.
|
||||||
* This version includes wallet and controls.
|
* This version includes wallet.
|
||||||
*/
|
*/
|
||||||
public class GlobalActionsDialog extends GlobalActionsDialogLite
|
public class GlobalActionsDialog extends GlobalActionsDialogLite
|
||||||
implements DialogInterface.OnDismissListener,
|
implements DialogInterface.OnDismissListener,
|
||||||
@@ -116,10 +99,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
|
|
||||||
private static final String TAG = "GlobalActionsDialog";
|
private static final String TAG = "GlobalActionsDialog";
|
||||||
|
|
||||||
public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
|
|
||||||
public static final String PREFS_CONTROLS_FILE = "controls_prefs";
|
|
||||||
private static final int SEEDING_MAX = 2;
|
|
||||||
|
|
||||||
private final LockPatternUtils mLockPatternUtils;
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
private final KeyguardStateController mKeyguardStateController;
|
private final KeyguardStateController mKeyguardStateController;
|
||||||
private final NotificationShadeDepthController mDepthController;
|
private final NotificationShadeDepthController mDepthController;
|
||||||
@@ -129,13 +108,9 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
private final IStatusBarService mStatusBarService;
|
private final IStatusBarService mStatusBarService;
|
||||||
private final NotificationShadeWindowController mNotificationShadeWindowController;
|
private final NotificationShadeWindowController mNotificationShadeWindowController;
|
||||||
private GlobalActionsPanelPlugin mWalletPlugin;
|
private GlobalActionsPanelPlugin mWalletPlugin;
|
||||||
private Optional<ControlsUiController> mControlsUiControllerOptional;
|
|
||||||
private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
|
|
||||||
private ControlsComponent mControlsComponent;
|
|
||||||
private Optional<ControlsController> mControlsControllerOptional;
|
|
||||||
private UserContextProvider mUserContextProvider;
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean mShowLockScreenCardsAndControls = false;
|
boolean mShowLockScreenCards = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context everything needs a context :(
|
* @param context everything needs a context :(
|
||||||
@@ -158,9 +133,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
IWindowManager iWindowManager,
|
IWindowManager iWindowManager,
|
||||||
@Background Executor backgroundExecutor,
|
@Background Executor backgroundExecutor,
|
||||||
UiEventLogger uiEventLogger,
|
UiEventLogger uiEventLogger,
|
||||||
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
|
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler) {
|
||||||
ControlsComponent controlsComponent,
|
|
||||||
UserContextProvider userContextProvider) {
|
|
||||||
|
|
||||||
super(context, windowManagerFuncs,
|
super(context, windowManagerFuncs,
|
||||||
audioManager, iDreamManager,
|
audioManager, iDreamManager,
|
||||||
@@ -186,11 +159,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
mSysuiColorExtractor = colorExtractor;
|
mSysuiColorExtractor = colorExtractor;
|
||||||
mStatusBarService = statusBarService;
|
mStatusBarService = statusBarService;
|
||||||
mNotificationShadeWindowController = notificationShadeWindowController;
|
mNotificationShadeWindowController = notificationShadeWindowController;
|
||||||
mControlsComponent = controlsComponent;
|
|
||||||
mControlsUiControllerOptional = controlsComponent.getControlsUiController();
|
|
||||||
mControlsControllerOptional = controlsComponent.getControlsController();
|
|
||||||
mSysUiState = sysUiState;
|
mSysUiState = sysUiState;
|
||||||
mUserContextProvider = userContextProvider;
|
|
||||||
mActivityStarter = activityStarter;
|
mActivityStarter = activityStarter;
|
||||||
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
|
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -201,10 +170,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
if (dialog.mWalletViewController != null) {
|
if (dialog.mWalletViewController != null) {
|
||||||
dialog.mWalletViewController.onDeviceLockStateChanged(!unlocked);
|
dialog.mWalletViewController.onDeviceLockStateChanged(!unlocked);
|
||||||
}
|
}
|
||||||
if (!dialog.isShowingControls()
|
|
||||||
&& mControlsComponent.getVisibility() == AVAILABLE) {
|
|
||||||
dialog.showControls(mControlsUiControllerOptional.get());
|
|
||||||
}
|
|
||||||
if (unlocked) {
|
if (unlocked) {
|
||||||
dialog.hideLockMessage();
|
dialog.hideLockMessage();
|
||||||
}
|
}
|
||||||
@@ -212,25 +178,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mControlsComponent.getControlsListingController().isPresent()) {
|
// Listen for changes to show pay on the power menu while locked
|
||||||
mControlsComponent.getControlsListingController().get()
|
|
||||||
.addCallback(list -> {
|
|
||||||
mControlsServiceInfos = list;
|
|
||||||
// This callback may occur after the dialog has been shown. If so, add
|
|
||||||
// controls into the already visible space or show the lock msg if needed.
|
|
||||||
if (mDialog != null) {
|
|
||||||
ActionsDialog dialog = (ActionsDialog) mDialog;
|
|
||||||
if (!dialog.isShowingControls()
|
|
||||||
&& mControlsComponent.getVisibility() == AVAILABLE) {
|
|
||||||
dialog.showControls(mControlsUiControllerOptional.get());
|
|
||||||
} else if (shouldShowLockMessage(dialog)) {
|
|
||||||
dialog.showLockMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for changes to show controls on the power menu while locked
|
|
||||||
onPowerMenuLockScreenSettingsChanged();
|
onPowerMenuLockScreenSettingsChanged();
|
||||||
mGlobalSettings.registerContentObserver(
|
mGlobalSettings.registerContentObserver(
|
||||||
Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT),
|
Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT),
|
||||||
@@ -243,65 +191,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* See if any available control service providers match one of the preferred components. If
|
|
||||||
* they do, and there are no current favorites for that component, query the preferred
|
|
||||||
* component for a limited number of suggested controls.
|
|
||||||
*/
|
|
||||||
private void seedFavorites() {
|
|
||||||
if (!mControlsControllerOptional.isPresent()
|
|
||||||
|| mControlsServiceInfos.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] preferredControlsPackages = getContext().getResources()
|
|
||||||
.getStringArray(com.android.systemui.R.array.config_controlsPreferredPackages);
|
|
||||||
|
|
||||||
SharedPreferences prefs = mUserContextProvider.getUserContext()
|
|
||||||
.getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE);
|
|
||||||
Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
|
|
||||||
Collections.emptySet());
|
|
||||||
|
|
||||||
List<ComponentName> componentsToSeed = new ArrayList<>();
|
|
||||||
for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) {
|
|
||||||
String pkg = preferredControlsPackages[i];
|
|
||||||
for (ControlsServiceInfo info : mControlsServiceInfos) {
|
|
||||||
if (!pkg.equals(info.componentName.getPackageName())) continue;
|
|
||||||
if (seededPackages.contains(pkg)) {
|
|
||||||
break;
|
|
||||||
} else if (mControlsControllerOptional.get()
|
|
||||||
.countFavoritesForComponent(info.componentName) > 0) {
|
|
||||||
// When there are existing controls but no saved preference, assume it
|
|
||||||
// is out of sync, perhaps through a device restore, and update the
|
|
||||||
// preference
|
|
||||||
addPackageToSeededSet(prefs, pkg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
componentsToSeed.add(info.componentName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (componentsToSeed.isEmpty()) return;
|
|
||||||
|
|
||||||
mControlsControllerOptional.get().seedFavoritesForComponents(
|
|
||||||
componentsToSeed,
|
|
||||||
(response) -> {
|
|
||||||
Log.d(TAG, "Controls seeded: " + response);
|
|
||||||
if (response.getAccepted()) {
|
|
||||||
addPackageToSeededSet(prefs, response.getPackageName());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPackageToSeededSet(SharedPreferences prefs, String pkg) {
|
|
||||||
Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
|
|
||||||
Collections.emptySet());
|
|
||||||
Set<String> updatedPkgs = new HashSet<>(seededPackages);
|
|
||||||
updatedPkgs.add(pkg);
|
|
||||||
prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, updatedPkgs).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the global actions dialog (creating if necessary)
|
* Show the global actions dialog (creating if necessary)
|
||||||
*
|
*
|
||||||
@@ -313,12 +202,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
super.showOrHideDialog(keyguardShowing, isDeviceProvisioned);
|
super.showOrHideDialog(keyguardShowing, isDeviceProvisioned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleShow() {
|
|
||||||
seedFavorites();
|
|
||||||
super.handleShow();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum number of power menu items to show based on which GlobalActions
|
* Returns the maximum number of power menu items to show based on which GlobalActions
|
||||||
* layout is being used.
|
* layout is being used.
|
||||||
@@ -340,14 +223,9 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
initDialogItems();
|
initDialogItems();
|
||||||
|
|
||||||
mDepthController.setShowingHomeControls(true);
|
mDepthController.setShowingHomeControls(true);
|
||||||
ControlsUiController uiController = null;
|
|
||||||
if (mControlsComponent.getVisibility() == AVAILABLE) {
|
|
||||||
uiController = mControlsUiControllerOptional.get();
|
|
||||||
}
|
|
||||||
ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
|
ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
|
||||||
this::getWalletViewController, mDepthController, mSysuiColorExtractor,
|
this::getWalletViewController, mDepthController, mSysuiColorExtractor,
|
||||||
mStatusBarService, mNotificationShadeWindowController,
|
mStatusBarService, mNotificationShadeWindowController,
|
||||||
controlsAvailable(), uiController,
|
|
||||||
mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter);
|
mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter);
|
||||||
|
|
||||||
if (shouldShowLockMessage(dialog)) {
|
if (shouldShowLockMessage(dialog)) {
|
||||||
@@ -407,10 +285,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
private final Provider<GlobalActionsPanelPlugin.PanelViewController> mWalletFactory;
|
private final Provider<GlobalActionsPanelPlugin.PanelViewController> mWalletFactory;
|
||||||
@Nullable private GlobalActionsPanelPlugin.PanelViewController mWalletViewController;
|
@Nullable private GlobalActionsPanelPlugin.PanelViewController mWalletViewController;
|
||||||
private ResetOrientationData mResetOrientationData;
|
private ResetOrientationData mResetOrientationData;
|
||||||
private final boolean mControlsAvailable;
|
|
||||||
|
|
||||||
private ControlsUiController mControlsUiController;
|
|
||||||
private ViewGroup mControlsView;
|
|
||||||
@VisibleForTesting ViewGroup mLockMessageContainer;
|
@VisibleForTesting ViewGroup mLockMessageContainer;
|
||||||
private TextView mLockMessage;
|
private TextView mLockMessage;
|
||||||
|
|
||||||
@@ -419,15 +293,12 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
NotificationShadeDepthController depthController,
|
NotificationShadeDepthController depthController,
|
||||||
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
|
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
|
||||||
NotificationShadeWindowController notificationShadeWindowController,
|
NotificationShadeWindowController notificationShadeWindowController,
|
||||||
boolean controlsAvailable, @Nullable ControlsUiController controlsUiController,
|
|
||||||
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
|
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
|
||||||
MyPowerOptionsAdapter powerAdapter) {
|
MyPowerOptionsAdapter powerAdapter) {
|
||||||
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
|
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
|
||||||
adapter, overflowAdapter, depthController, sysuiColorExtractor,
|
adapter, overflowAdapter, depthController, sysuiColorExtractor,
|
||||||
statusBarService, notificationShadeWindowController, sysuiState,
|
statusBarService, notificationShadeWindowController, sysuiState,
|
||||||
onRotateCallback, keyguardShowing, powerAdapter);
|
onRotateCallback, keyguardShowing, powerAdapter);
|
||||||
mControlsAvailable = controlsAvailable;
|
|
||||||
mControlsUiController = controlsUiController;
|
|
||||||
mWalletFactory = walletFactory;
|
mWalletFactory = walletFactory;
|
||||||
|
|
||||||
// Update window attributes
|
// Update window attributes
|
||||||
@@ -448,16 +319,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
initializeLayout();
|
initializeLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isShowingControls() {
|
|
||||||
return mControlsUiController != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showControls(ControlsUiController controller) {
|
|
||||||
mControlsUiController = controller;
|
|
||||||
mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
|
|
||||||
null /* activityContext */);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWalletViewAvailable() {
|
private boolean isWalletViewAvailable() {
|
||||||
return mWalletViewController != null && mWalletViewController.getPanelContent() != null;
|
return mWalletViewController != null && mWalletViewController.getPanelContent() != null;
|
||||||
}
|
}
|
||||||
@@ -524,10 +385,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
new FrameLayout.LayoutParams(
|
new FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT);
|
FrameLayout.LayoutParams.MATCH_PARENT);
|
||||||
if (!mControlsAvailable) {
|
panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
|
||||||
panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
|
com.android.systemui.R.dimen.global_actions_wallet_top_margin);
|
||||||
com.android.systemui.R.dimen.global_actions_wallet_top_margin);
|
|
||||||
}
|
|
||||||
View walletView = mWalletViewController.getPanelContent();
|
View walletView = mWalletViewController.getPanelContent();
|
||||||
panelContainer.addView(walletView, panelParams);
|
panelContainer.addView(walletView, panelParams);
|
||||||
// Smooth transitions when wallet is resized, which can happen when a card is added
|
// Smooth transitions when wallet is resized, which can happen when a card is added
|
||||||
@@ -554,7 +413,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
@Override
|
@Override
|
||||||
protected void initializeLayout() {
|
protected void initializeLayout() {
|
||||||
super.initializeLayout();
|
super.initializeLayout();
|
||||||
mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
|
|
||||||
mLockMessageContainer = requireViewById(
|
mLockMessageContainer = requireViewById(
|
||||||
com.android.systemui.R.id.global_actions_lock_message_container);
|
com.android.systemui.R.id.global_actions_lock_message_container);
|
||||||
mLockMessage = requireViewById(com.android.systemui.R.id.global_actions_lock_message);
|
mLockMessage = requireViewById(com.android.systemui.R.id.global_actions_lock_message);
|
||||||
@@ -577,10 +435,6 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
windowInsets.getStableInsetBottom());
|
windowInsets.getStableInsetBottom());
|
||||||
return WindowInsets.CONSUMED;
|
return WindowInsets.CONSUMED;
|
||||||
});
|
});
|
||||||
if (mControlsUiController != null) {
|
|
||||||
mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
|
|
||||||
null /* activityContext */);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBackgroundDrawable.setAlpha(0);
|
mBackgroundDrawable.setAlpha(0);
|
||||||
float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
|
float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
|
||||||
@@ -609,20 +463,11 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
@Override
|
@Override
|
||||||
protected void dismissInternal() {
|
protected void dismissInternal() {
|
||||||
super.dismissInternal();
|
super.dismissInternal();
|
||||||
if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dismissForControlsActivity() {
|
|
||||||
dismissWithAnimation(() -> {
|
|
||||||
ViewGroup root = (ViewGroup) mGlobalActionsLayout.getParent();
|
|
||||||
ControlsAnimations.exitAnimation(root, this::completeDismiss).start();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void completeDismiss() {
|
protected void completeDismiss() {
|
||||||
dismissWallet();
|
dismissWallet();
|
||||||
if (mControlsUiController != null) mControlsUiController.hide();
|
|
||||||
resetOrientation();
|
resetOrientation();
|
||||||
super.completeDismiss();
|
super.completeDismiss();
|
||||||
}
|
}
|
||||||
@@ -647,15 +492,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
public void refreshDialog() {
|
public void refreshDialog() {
|
||||||
// ensure dropdown menus are dismissed before re-initializing the dialog
|
// ensure dropdown menus are dismissed before re-initializing the dialog
|
||||||
dismissWallet();
|
dismissWallet();
|
||||||
if (mControlsUiController != null) {
|
|
||||||
mControlsUiController.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
super.refreshDialog();
|
super.refreshDialog();
|
||||||
if (mControlsUiController != null) {
|
|
||||||
mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
|
|
||||||
null /* activityContext */);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideLockMessage() {
|
void hideLockMessage() {
|
||||||
@@ -699,15 +536,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
return isPanelDebugModeEnabled(context);
|
return isPanelDebugModeEnabled(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean controlsAvailable() {
|
|
||||||
return isDeviceProvisioned()
|
|
||||||
&& mControlsComponent.isEnabled()
|
|
||||||
&& !mControlsServiceInfos.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldShowLockMessage(ActionsDialog dialog) {
|
private boolean shouldShowLockMessage(ActionsDialog dialog) {
|
||||||
return mControlsComponent.getVisibility() == AVAILABLE_AFTER_UNLOCK
|
return isWalletAvailableAfterUnlock(dialog);
|
||||||
|| isWalletAvailableAfterUnlock(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary while we move items out of the power menu
|
// Temporary while we move items out of the power menu
|
||||||
@@ -715,12 +545,12 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
|
|||||||
boolean isLockedAfterBoot = mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id)
|
boolean isLockedAfterBoot = mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id)
|
||||||
== STRONG_AUTH_REQUIRED_AFTER_BOOT;
|
== STRONG_AUTH_REQUIRED_AFTER_BOOT;
|
||||||
return !mKeyguardStateController.isUnlocked()
|
return !mKeyguardStateController.isUnlocked()
|
||||||
&& (!mShowLockScreenCardsAndControls || isLockedAfterBoot)
|
&& (!mShowLockScreenCards || isLockedAfterBoot)
|
||||||
&& dialog.isWalletViewAvailable();
|
&& dialog.isWalletViewAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPowerMenuLockScreenSettingsChanged() {
|
private void onPowerMenuLockScreenSettingsChanged() {
|
||||||
mShowLockScreenCardsAndControls = mSecureSettings.getInt(
|
mShowLockScreenCards = mSecureSettings.getInt(
|
||||||
Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0;
|
Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.provider.Settings.Secure;
|
import android.provider.Settings.Secure;
|
||||||
import android.service.quicksettings.Tile;
|
import android.service.quicksettings.Tile;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -57,6 +56,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
|
|||||||
import com.android.systemui.tuner.TunerService;
|
import com.android.systemui.tuner.TunerService;
|
||||||
import com.android.systemui.tuner.TunerService.Tunable;
|
import com.android.systemui.tuner.TunerService.Tunable;
|
||||||
import com.android.systemui.util.leak.GarbageMonitor;
|
import com.android.systemui.util.leak.GarbageMonitor;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -79,6 +79,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
private static final int MAX_QS_INSTANCE_ID = 1 << 20;
|
private static final int MAX_QS_INSTANCE_ID = 1 << 20;
|
||||||
|
|
||||||
|
public static final int POSITION_AT_END = -1;
|
||||||
public static final String TILES_SETTING = Secure.QS_TILES;
|
public static final String TILES_SETTING = Secure.QS_TILES;
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
@@ -101,6 +102,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
private final Optional<StatusBar> mStatusBarOptional;
|
private final Optional<StatusBar> mStatusBarOptional;
|
||||||
private Context mUserContext;
|
private Context mUserContext;
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
|
private SecureSettings mSecureSettings;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public QSTileHost(Context context,
|
public QSTileHost(Context context,
|
||||||
@@ -116,7 +118,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
Optional<StatusBar> statusBarOptional,
|
Optional<StatusBar> statusBarOptional,
|
||||||
QSLogger qsLogger,
|
QSLogger qsLogger,
|
||||||
UiEventLogger uiEventLogger,
|
UiEventLogger uiEventLogger,
|
||||||
UserTracker userTracker) {
|
UserTracker userTracker,
|
||||||
|
SecureSettings secureSettings) {
|
||||||
mIconController = iconController;
|
mIconController = iconController;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUserContext = context;
|
mUserContext = context;
|
||||||
@@ -135,6 +138,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
pluginManager.addPluginListener(this, QSFactory.class, true);
|
pluginManager.addPluginListener(this, QSFactory.class, true);
|
||||||
mDumpManager.registerDumpable(TAG, this);
|
mDumpManager.registerDumpable(TAG, this);
|
||||||
mUserTracker = userTracker;
|
mUserTracker = userTracker;
|
||||||
|
mSecureSettings = secureSettings;
|
||||||
|
|
||||||
mainHandler.post(() -> {
|
mainHandler.post(() -> {
|
||||||
// This is technically a hack to avoid circular dependency of
|
// This is technically a hack to avoid circular dependency of
|
||||||
@@ -343,19 +347,43 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
|
if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a tile to the end
|
||||||
|
*
|
||||||
|
* @param spec string matching a pre-defined tilespec
|
||||||
|
*/
|
||||||
public void addTile(String spec) {
|
public void addTile(String spec) {
|
||||||
changeTileSpecs(tileSpecs-> !tileSpecs.contains(spec) && tileSpecs.add(spec));
|
addTile(spec, POSITION_AT_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveTilesToSettings(List<String> tileSpecs) {
|
/**
|
||||||
Settings.Secure.putStringForUser(mContext.getContentResolver(), TILES_SETTING,
|
* Add a tile into the requested spot, or at the end if the position is greater than the number
|
||||||
TextUtils.join(",", tileSpecs), null /* tag */,
|
* of tiles.
|
||||||
false /* default */, mCurrentUser, true /* overrideable by restore */);
|
* @param spec string matching a pre-defined tilespec
|
||||||
|
* @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
|
||||||
|
*/
|
||||||
|
public void addTile(String spec, int requestPosition) {
|
||||||
|
changeTileSpecs(tileSpecs -> {
|
||||||
|
if (tileSpecs.contains(spec)) return false;
|
||||||
|
|
||||||
|
int size = tileSpecs.size();
|
||||||
|
if (requestPosition == POSITION_AT_END || requestPosition >= size) {
|
||||||
|
tileSpecs.add(spec);
|
||||||
|
} else {
|
||||||
|
tileSpecs.add(requestPosition, spec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveTilesToSettings(List<String> tileSpecs) {
|
||||||
|
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
|
||||||
|
null /* tag */, false /* default */, mCurrentUser,
|
||||||
|
true /* overrideable by restore */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
|
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
|
||||||
final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
|
final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
|
||||||
TILES_SETTING, mCurrentUser);
|
|
||||||
final List<String> tileSpecs = loadTileSpecs(mContext, setting);
|
final List<String> tileSpecs = loadTileSpecs(mContext, setting);
|
||||||
if (changeFunction.test(tileSpecs)) {
|
if (changeFunction.test(tileSpecs)) {
|
||||||
saveTilesToSettings(tileSpecs);
|
saveTilesToSettings(tileSpecs);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.phone.AutoTileManager;
|
|||||||
import com.android.systemui.statusbar.phone.ManagedProfileController;
|
import com.android.systemui.statusbar.phone.ManagedProfileController;
|
||||||
import com.android.systemui.statusbar.policy.CastController;
|
import com.android.systemui.statusbar.policy.CastController;
|
||||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController;
|
||||||
import com.android.systemui.statusbar.policy.HotspotController;
|
import com.android.systemui.statusbar.policy.HotspotController;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ public interface QSModule {
|
|||||||
NightDisplayListener nightDisplayListener,
|
NightDisplayListener nightDisplayListener,
|
||||||
CastController castController,
|
CastController castController,
|
||||||
ReduceBrightColorsController reduceBrightColorsController,
|
ReduceBrightColorsController reduceBrightColorsController,
|
||||||
|
DeviceControlsController deviceControlsController,
|
||||||
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
||||||
AutoTileManager manager = new AutoTileManager(
|
AutoTileManager manager = new AutoTileManager(
|
||||||
context,
|
context,
|
||||||
@@ -74,6 +76,7 @@ public interface QSModule {
|
|||||||
nightDisplayListener,
|
nightDisplayListener,
|
||||||
castController,
|
castController,
|
||||||
reduceBrightColorsController,
|
reduceBrightColorsController,
|
||||||
|
deviceControlsController,
|
||||||
isReduceBrightColorsAvailable
|
isReduceBrightColorsAvailable
|
||||||
);
|
);
|
||||||
manager.init();
|
manager.init();
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
|
|||||||
import com.android.systemui.qs.QSHost
|
import com.android.systemui.qs.QSHost
|
||||||
import com.android.systemui.qs.logging.QSLogger
|
import com.android.systemui.qs.logging.QSLogger
|
||||||
import com.android.systemui.qs.tileimpl.QSTileImpl
|
import com.android.systemui.qs.tileimpl.QSTileImpl
|
||||||
import com.android.systemui.statusbar.FeatureFlags
|
|
||||||
import com.android.systemui.util.settings.GlobalSettings
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -53,9 +51,7 @@ class DeviceControlsTile @Inject constructor(
|
|||||||
statusBarStateController: StatusBarStateController,
|
statusBarStateController: StatusBarStateController,
|
||||||
activityStarter: ActivityStarter,
|
activityStarter: ActivityStarter,
|
||||||
qsLogger: QSLogger,
|
qsLogger: QSLogger,
|
||||||
private val controlsComponent: ControlsComponent,
|
private val controlsComponent: ControlsComponent
|
||||||
private val featureFlags: FeatureFlags,
|
|
||||||
globalSettings: GlobalSettings
|
|
||||||
) : QSTileImpl<QSTile.State>(
|
) : QSTileImpl<QSTile.State>(
|
||||||
host,
|
host,
|
||||||
backgroundLooper,
|
backgroundLooper,
|
||||||
@@ -67,11 +63,6 @@ class DeviceControlsTile @Inject constructor(
|
|||||||
qsLogger
|
qsLogger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val SETTINGS_FLAG = "controls_lockscreen"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val controlsLockscreen = globalSettings.getInt(SETTINGS_FLAG, 0) != 0
|
|
||||||
private var hasControlsApps = AtomicBoolean(false)
|
private var hasControlsApps = AtomicBoolean(false)
|
||||||
private val intent = Intent(Settings.ACTION_DEVICE_CONTROLS_SETTINGS)
|
private val intent = Intent(Settings.ACTION_DEVICE_CONTROLS_SETTINGS)
|
||||||
|
|
||||||
@@ -92,9 +83,7 @@ class DeviceControlsTile @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isAvailable(): Boolean {
|
override fun isAvailable(): Boolean {
|
||||||
return featureFlags.isKeyguardLayoutEnabled &&
|
return controlsComponent.getControlsController().isPresent
|
||||||
controlsLockscreen &&
|
|
||||||
controlsComponent.getControlsController().isPresent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newTileState(): QSTile.State {
|
override fun newTileState(): QSTile.State {
|
||||||
@@ -114,7 +103,7 @@ class DeviceControlsTile @Inject constructor(
|
|||||||
val i = Intent().apply {
|
val i = Intent().apply {
|
||||||
component = ComponentName(mContext, ControlsActivity::class.java)
|
component = ComponentName(mContext, ControlsActivity::class.java)
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false)
|
putExtra(ControlsUiController.EXTRA_ANIMATE, true)
|
||||||
}
|
}
|
||||||
mContext.startActivity(i)
|
mContext.startActivity(i)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.policy.CastController;
|
|||||||
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
||||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||||
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
|
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController;
|
||||||
import com.android.systemui.statusbar.policy.HotspotController;
|
import com.android.systemui.statusbar.policy.HotspotController;
|
||||||
import com.android.systemui.statusbar.policy.HotspotController.Callback;
|
import com.android.systemui.statusbar.policy.HotspotController.Callback;
|
||||||
import com.android.systemui.util.UserAwareController;
|
import com.android.systemui.util.UserAwareController;
|
||||||
@@ -58,6 +59,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
public static final String WORK = "work";
|
public static final String WORK = "work";
|
||||||
public static final String NIGHT = "night";
|
public static final String NIGHT = "night";
|
||||||
public static final String CAST = "cast";
|
public static final String CAST = "cast";
|
||||||
|
public static final String DEVICE_CONTROLS = "controls";
|
||||||
public static final String BRIGHTNESS = "reduce_brightness";
|
public static final String BRIGHTNESS = "reduce_brightness";
|
||||||
static final String SETTING_SEPARATOR = ":";
|
static final String SETTING_SEPARATOR = ":";
|
||||||
|
|
||||||
@@ -74,6 +76,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
private final ManagedProfileController mManagedProfileController;
|
private final ManagedProfileController mManagedProfileController;
|
||||||
private final NightDisplayListener mNightDisplayListener;
|
private final NightDisplayListener mNightDisplayListener;
|
||||||
private final CastController mCastController;
|
private final CastController mCastController;
|
||||||
|
private final DeviceControlsController mDeviceControlsController;
|
||||||
private final ReduceBrightColorsController mReduceBrightColorsController;
|
private final ReduceBrightColorsController mReduceBrightColorsController;
|
||||||
private final boolean mIsReduceBrightColorsAvailable;
|
private final boolean mIsReduceBrightColorsAvailable;
|
||||||
private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
|
private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
|
||||||
@@ -88,6 +91,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
NightDisplayListener nightDisplayListener,
|
NightDisplayListener nightDisplayListener,
|
||||||
CastController castController,
|
CastController castController,
|
||||||
ReduceBrightColorsController reduceBrightColorsController,
|
ReduceBrightColorsController reduceBrightColorsController,
|
||||||
|
DeviceControlsController deviceControlsController,
|
||||||
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mHost = host;
|
mHost = host;
|
||||||
@@ -102,6 +106,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
mCastController = castController;
|
mCastController = castController;
|
||||||
mReduceBrightColorsController = reduceBrightColorsController;
|
mReduceBrightColorsController = reduceBrightColorsController;
|
||||||
mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
|
mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
|
||||||
|
mDeviceControlsController = deviceControlsController;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,6 +143,9 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
if (!mAutoTracker.isAdded(BRIGHTNESS) && mIsReduceBrightColorsAvailable) {
|
if (!mAutoTracker.isAdded(BRIGHTNESS) && mIsReduceBrightColorsAvailable) {
|
||||||
mReduceBrightColorsController.addCallback(mReduceBrightColorsCallback);
|
mReduceBrightColorsController.addCallback(mReduceBrightColorsCallback);
|
||||||
}
|
}
|
||||||
|
if (!mAutoTracker.isAdded(DEVICE_CONTROLS)) {
|
||||||
|
mDeviceControlsController.setCallback(mDeviceControlsCallback);
|
||||||
|
}
|
||||||
|
|
||||||
int settingsN = mAutoAddSettingList.size();
|
int settingsN = mAutoAddSettingList.size();
|
||||||
for (int i = 0; i < settingsN; i++) {
|
for (int i = 0; i < settingsN; i++) {
|
||||||
@@ -158,6 +166,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
mReduceBrightColorsController.removeCallback(mReduceBrightColorsCallback);
|
mReduceBrightColorsController.removeCallback(mReduceBrightColorsCallback);
|
||||||
}
|
}
|
||||||
mCastController.removeCallback(mCastCallback);
|
mCastController.removeCallback(mCastCallback);
|
||||||
|
mDeviceControlsController.removeCallback();
|
||||||
int settingsN = mAutoAddSettingList.size();
|
int settingsN = mAutoAddSettingList.size();
|
||||||
for (int i = 0; i < settingsN; i++) {
|
for (int i = 0; i < settingsN; i++) {
|
||||||
mAutoAddSettingList.get(i).setListening(false);
|
mAutoAddSettingList.get(i).setListening(false);
|
||||||
@@ -274,6 +283,17 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final DeviceControlsController.Callback mDeviceControlsCallback =
|
||||||
|
new DeviceControlsController.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onControlsAvailable(int position) {
|
||||||
|
if (mAutoTracker.isAdded(DEVICE_CONTROLS)) return;
|
||||||
|
mHost.addTile(DEVICE_CONTROLS, position);
|
||||||
|
mAutoTracker.setTileAdded(DEVICE_CONTROLS);
|
||||||
|
mHandler.post(() -> mDeviceControlsController.removeCallback());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final NightDisplayListener.Callback mNightDisplayCallback =
|
final NightDisplayListener.Callback mNightDisplayCallback =
|
||||||
new NightDisplayListener.Callback() {
|
new NightDisplayListener.Callback() {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.statusbar.policy
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports adding a DeviceControls QS tile
|
||||||
|
*/
|
||||||
|
interface DeviceControlsController {
|
||||||
|
interface Callback {
|
||||||
|
/**
|
||||||
|
* If controls become available, initiate this callback with the desired position
|
||||||
|
*/
|
||||||
|
fun onControlsAvailable(position: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add callback, supporting only a single callback at once */
|
||||||
|
fun setCallback(callback: Callback)
|
||||||
|
|
||||||
|
/** Remove any existing callback, if any */
|
||||||
|
fun removeCallback()
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.statusbar.policy
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.controls.ControlsServiceInfo
|
||||||
|
import com.android.systemui.controls.dagger.ControlsComponent
|
||||||
|
import com.android.systemui.controls.management.ControlsListingController
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.QSTileHost.POSITION_AT_END
|
||||||
|
import com.android.systemui.settings.UserContextProvider
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController.Callback
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches for Device Controls QS Tile activation, which can happen in two ways:
|
||||||
|
* <ol>
|
||||||
|
* <li>Migration from Power Menu - For existing Android 11 users, create a tile in a high
|
||||||
|
* priority position.
|
||||||
|
* <li>Device controls service becomes available - For non-migrated users, create a tile and
|
||||||
|
* place at the end of active tiles, and initiate seeding where possible.
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
public class DeviceControlsControllerImpl @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val controlsComponent: ControlsComponent,
|
||||||
|
private val userContextProvider: UserContextProvider
|
||||||
|
) : DeviceControlsController {
|
||||||
|
|
||||||
|
private var callback: Callback? = null
|
||||||
|
internal var position: Int? = null
|
||||||
|
|
||||||
|
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
|
||||||
|
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
||||||
|
if (!serviceInfos.isEmpty()) {
|
||||||
|
seedFavorites(serviceInfos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "DeviceControlsControllerImpl"
|
||||||
|
internal const val QS_PRIORITY_POSITION = 3
|
||||||
|
internal const val QS_DEFAULT_POSITION = POSITION_AT_END
|
||||||
|
|
||||||
|
internal const val PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted"
|
||||||
|
internal const val PREFS_CONTROLS_FILE = "controls_prefs"
|
||||||
|
private const val SEEDING_MAX = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMigrationToQs() {
|
||||||
|
controlsComponent.getControlsController().ifPresent {
|
||||||
|
if (!it.getFavorites().isEmpty()) {
|
||||||
|
position = QS_PRIORITY_POSITION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This migration logic assumes that something like [AutoTileManager] is tracking state
|
||||||
|
* externally, and won't call this method after receiving a response via
|
||||||
|
* [Callback#onControlsAvailable], once per user. Otherwise the calculated position may be
|
||||||
|
* incorrect.
|
||||||
|
*/
|
||||||
|
override fun setCallback(callback: Callback) {
|
||||||
|
// Treat any additional call as a reset before recalculating
|
||||||
|
removeCallback()
|
||||||
|
|
||||||
|
checkMigrationToQs()
|
||||||
|
controlsComponent.getControlsListingController().ifPresent {
|
||||||
|
it.addCallback(listingCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.callback = callback
|
||||||
|
fireControlsAvailable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeCallback() {
|
||||||
|
position = null
|
||||||
|
callback = null
|
||||||
|
controlsComponent.getControlsListingController().ifPresent {
|
||||||
|
it.removeCallback(listingCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fireControlsAvailable() {
|
||||||
|
position?.let {
|
||||||
|
Log.i(TAG, "Setting DeviceControlsTile position: $it")
|
||||||
|
callback?.onControlsAvailable(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if any available control service providers match one of the preferred components. If
|
||||||
|
* they do, and there are no current favorites for that component, query the preferred
|
||||||
|
* component for a limited number of suggested controls.
|
||||||
|
*/
|
||||||
|
private fun seedFavorites(serviceInfos: List<ControlsServiceInfo>) {
|
||||||
|
val preferredControlsPackages = context.getResources().getStringArray(
|
||||||
|
R.array.config_controlsPreferredPackages)
|
||||||
|
|
||||||
|
val prefs = userContextProvider.userContext.getSharedPreferences(
|
||||||
|
PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
|
||||||
|
val seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, emptySet())
|
||||||
|
|
||||||
|
val controlsController = controlsComponent.getControlsController().get()
|
||||||
|
val componentsToSeed = mutableListOf<ComponentName>()
|
||||||
|
var i = 0
|
||||||
|
while (i < Math.min(SEEDING_MAX, preferredControlsPackages.size)) {
|
||||||
|
val pkg = preferredControlsPackages[i]
|
||||||
|
serviceInfos.forEach {
|
||||||
|
if (pkg.equals(it.componentName.packageName) && !seededPackages.contains(pkg)) {
|
||||||
|
if (controlsController.countFavoritesForComponent(it.componentName) > 0) {
|
||||||
|
// When there are existing controls but no saved preference, assume it
|
||||||
|
// is out of sync, perhaps through a device restore, and update the
|
||||||
|
// preference
|
||||||
|
addPackageToSeededSet(prefs, pkg)
|
||||||
|
} else {
|
||||||
|
componentsToSeed.add(it.componentName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentsToSeed.isEmpty()) return
|
||||||
|
|
||||||
|
controlsController.seedFavoritesForComponents(
|
||||||
|
componentsToSeed,
|
||||||
|
{ response ->
|
||||||
|
Log.d(TAG, "Controls seeded: $response")
|
||||||
|
if (response.accepted) {
|
||||||
|
addPackageToSeededSet(prefs, response.packageName)
|
||||||
|
if (position == null) {
|
||||||
|
position = QS_DEFAULT_POSITION
|
||||||
|
}
|
||||||
|
fireControlsAvailable()
|
||||||
|
|
||||||
|
controlsComponent.getControlsListingController().ifPresent {
|
||||||
|
it.removeCallback(listingCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addPackageToSeededSet(prefs: SharedPreferences, pkg: String) {
|
||||||
|
val seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, emptySet())
|
||||||
|
val updatedPkgs = seededPackages.toMutableSet()
|
||||||
|
updatedPkgs.add(pkg)
|
||||||
|
prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, updatedPkgs).apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,8 @@ import com.android.systemui.statusbar.policy.BluetoothController;
|
|||||||
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
|
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.CastController;
|
import com.android.systemui.statusbar.policy.CastController;
|
||||||
import com.android.systemui.statusbar.policy.CastControllerImpl;
|
import com.android.systemui.statusbar.policy.CastControllerImpl;
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController;
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.ExtensionController;
|
import com.android.systemui.statusbar.policy.ExtensionController;
|
||||||
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
|
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.FlashlightController;
|
import com.android.systemui.statusbar.policy.FlashlightController;
|
||||||
@@ -44,8 +46,6 @@ import com.android.systemui.statusbar.policy.RotationLockController;
|
|||||||
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
|
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.SecurityController;
|
import com.android.systemui.statusbar.policy.SecurityController;
|
||||||
import com.android.systemui.statusbar.policy.SecurityControllerImpl;
|
import com.android.systemui.statusbar.policy.SecurityControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.SensorPrivacyController;
|
|
||||||
import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
|
|
||||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||||
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
|
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
|
||||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||||
@@ -113,6 +113,11 @@ public interface StatusBarPolicyModule {
|
|||||||
@Binds
|
@Binds
|
||||||
ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl);
|
ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl);
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Binds
|
||||||
|
DeviceControlsController provideDeviceControlsController(
|
||||||
|
DeviceControlsControllerImpl controllerImpl);
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Binds
|
@Binds
|
||||||
NetworkController.AccessPointController provideAccessPointController(
|
NetworkController.AccessPointController provideAccessPointController(
|
||||||
|
|||||||
@@ -58,15 +58,10 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
import com.android.systemui.controls.controller.ControlsController;
|
|
||||||
import com.android.systemui.controls.dagger.ControlsComponent;
|
|
||||||
import com.android.systemui.controls.management.ControlsListingController;
|
|
||||||
import com.android.systemui.controls.ui.ControlsUiController;
|
|
||||||
import com.android.systemui.model.SysUiState;
|
import com.android.systemui.model.SysUiState;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
import com.android.systemui.plugins.GlobalActions;
|
import com.android.systemui.plugins.GlobalActions;
|
||||||
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
|
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
|
||||||
import com.android.systemui.settings.UserContextProvider;
|
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
||||||
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||||
@@ -118,11 +113,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
@Mock private SysuiColorExtractor mColorExtractor;
|
@Mock private SysuiColorExtractor mColorExtractor;
|
||||||
@Mock private IStatusBarService mStatusBarService;
|
@Mock private IStatusBarService mStatusBarService;
|
||||||
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
|
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
|
||||||
@Mock private ControlsUiController mControlsUiController;
|
|
||||||
@Mock private IWindowManager mWindowManager;
|
@Mock private IWindowManager mWindowManager;
|
||||||
@Mock private Executor mBackgroundExecutor;
|
@Mock private Executor mBackgroundExecutor;
|
||||||
@Mock private ControlsListingController mControlsListingController;
|
|
||||||
@Mock private ControlsController mControlsController;
|
|
||||||
@Mock private UiEventLogger mUiEventLogger;
|
@Mock private UiEventLogger mUiEventLogger;
|
||||||
@Mock private RingerModeTracker mRingerModeTracker;
|
@Mock private RingerModeTracker mRingerModeTracker;
|
||||||
@Mock private RingerModeLiveData mRingerModeLiveData;
|
@Mock private RingerModeLiveData mRingerModeLiveData;
|
||||||
@@ -130,10 +122,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
@Mock GlobalActionsPanelPlugin mWalletPlugin;
|
@Mock GlobalActionsPanelPlugin mWalletPlugin;
|
||||||
@Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
|
@Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
|
||||||
@Mock private Handler mHandler;
|
@Mock private Handler mHandler;
|
||||||
@Mock private UserContextProvider mUserContextProvider;
|
|
||||||
@Mock private UserTracker mUserTracker;
|
@Mock private UserTracker mUserTracker;
|
||||||
@Mock private SecureSettings mSecureSettings;
|
@Mock private SecureSettings mSecureSettings;
|
||||||
private ControlsComponent mControlsComponent;
|
|
||||||
|
|
||||||
private TestableLooper mTestableLooper;
|
private TestableLooper mTestableLooper;
|
||||||
|
|
||||||
@@ -144,18 +134,6 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
allowTestableLooperAsMainThread();
|
allowTestableLooperAsMainThread();
|
||||||
|
|
||||||
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
|
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
|
||||||
when(mUserContextProvider.getUserContext()).thenReturn(mContext);
|
|
||||||
mControlsComponent = new ControlsComponent(
|
|
||||||
true,
|
|
||||||
mContext,
|
|
||||||
() -> mControlsController,
|
|
||||||
() -> mControlsUiController,
|
|
||||||
() -> mControlsListingController,
|
|
||||||
mLockPatternUtils,
|
|
||||||
mKeyguardStateController,
|
|
||||||
mUserTracker,
|
|
||||||
mSecureSettings
|
|
||||||
);
|
|
||||||
|
|
||||||
mGlobalActionsDialog = new GlobalActionsDialog(mContext,
|
mGlobalActionsDialog = new GlobalActionsDialog(mContext,
|
||||||
mWindowManagerFuncs,
|
mWindowManagerFuncs,
|
||||||
@@ -186,9 +164,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
mUiEventLogger,
|
mUiEventLogger,
|
||||||
mRingerModeTracker,
|
mRingerModeTracker,
|
||||||
mSysUiState,
|
mSysUiState,
|
||||||
mHandler,
|
mHandler
|
||||||
mControlsComponent,
|
|
||||||
mUserContextProvider
|
|
||||||
);
|
);
|
||||||
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
|
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
|
||||||
|
|
||||||
@@ -511,7 +487,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
|
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
|
||||||
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
||||||
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
||||||
mGlobalActionsDialog.mShowLockScreenCardsAndControls = false;
|
mGlobalActionsDialog.mShowLockScreenCards = false;
|
||||||
setupDefaultActions();
|
setupDefaultActions();
|
||||||
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
||||||
when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
|
when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
|
||||||
@@ -528,14 +504,14 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShouldNotShowLockScreenMessage_whenWalletOrControlsShownOnLockScreen()
|
public void testShouldNotShowLockScreenMessage_whenWalletShownOnLockScreen()
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
mGlobalActionsDialog = spy(mGlobalActionsDialog);
|
mGlobalActionsDialog = spy(mGlobalActionsDialog);
|
||||||
mGlobalActionsDialog.mDialog = null;
|
mGlobalActionsDialog.mDialog = null;
|
||||||
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
|
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
|
||||||
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
||||||
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
||||||
mGlobalActionsDialog.mShowLockScreenCardsAndControls = true;
|
mGlobalActionsDialog.mShowLockScreenCards = true;
|
||||||
setupDefaultActions();
|
setupDefaultActions();
|
||||||
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
||||||
when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
|
when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
|
||||||
@@ -552,7 +528,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShouldNotShowLockScreenMessage_whenControlsAndWalletBothDisabled()
|
public void testShouldNotShowLockScreenMessage_whenWalletBothDisabled()
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
mGlobalActionsDialog = spy(mGlobalActionsDialog);
|
mGlobalActionsDialog = spy(mGlobalActionsDialog);
|
||||||
mGlobalActionsDialog.mDialog = null;
|
mGlobalActionsDialog.mDialog = null;
|
||||||
@@ -560,11 +536,10 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
|
|||||||
|
|
||||||
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
|
||||||
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
|
||||||
mGlobalActionsDialog.mShowLockScreenCardsAndControls = true;
|
mGlobalActionsDialog.mShowLockScreenCards = true;
|
||||||
setupDefaultActions();
|
setupDefaultActions();
|
||||||
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
|
||||||
when(mWalletController.getPanelContent()).thenReturn(null);
|
when(mWalletController.getPanelContent()).thenReturn(null);
|
||||||
when(mControlsUiController.getAvailable()).thenReturn(false);
|
|
||||||
|
|
||||||
mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
|
mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
|||||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.tuner.TunerService;
|
import com.android.systemui.tuner.TunerService;
|
||||||
import com.android.systemui.util.InjectionInflationController;
|
import com.android.systemui.util.InjectionInflationController;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
@@ -130,7 +131,8 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
mock(PluginManager.class), mock(TunerService.class),
|
mock(PluginManager.class), mock(TunerService.class),
|
||||||
() -> mock(AutoTileManager.class), mock(DumpManager.class),
|
() -> mock(AutoTileManager.class), mock(DumpManager.class),
|
||||||
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
|
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
|
||||||
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class));
|
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
|
||||||
|
mock(SecureSettings.class));
|
||||||
qs.setHost(host);
|
qs.setHost(host);
|
||||||
|
|
||||||
qs.setListening(true);
|
qs.setListening(true);
|
||||||
|
|||||||
@@ -21,20 +21,21 @@ import static junit.framework.Assert.assertEquals;
|
|||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
import static org.mockito.ArgumentMatchers.isNull;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.testing.TestableLooper.RunWithLooper;
|
import android.testing.TestableLooper.RunWithLooper;
|
||||||
@@ -64,11 +65,13 @@ import com.android.systemui.statusbar.phone.AutoTileManager;
|
|||||||
import com.android.systemui.statusbar.phone.StatusBar;
|
import com.android.systemui.statusbar.phone.StatusBar;
|
||||||
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
||||||
import com.android.systemui.tuner.TunerService;
|
import com.android.systemui.tuner.TunerService;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.MockitoSession;
|
import org.mockito.MockitoSession;
|
||||||
@@ -78,7 +81,6 @@ import java.io.FileDescriptor;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
@@ -119,6 +121,8 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
private UiEventLogger mUiEventLogger;
|
private UiEventLogger mUiEventLogger;
|
||||||
@Mock
|
@Mock
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
|
@Mock
|
||||||
|
private SecureSettings mSecureSettings;
|
||||||
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private TestableLooper mLooper;
|
private TestableLooper mLooper;
|
||||||
@@ -138,11 +142,12 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
mHandler = new Handler(mLooper.getLooper());
|
mHandler = new Handler(mLooper.getLooper());
|
||||||
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
|
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
|
||||||
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
|
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
|
||||||
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker);
|
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
|
||||||
|
mSecureSettings);
|
||||||
setUpTileFactory();
|
setUpTileFactory();
|
||||||
|
|
||||||
Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
|
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
|
||||||
"", ActivityManager.getCurrentUser());
|
.thenReturn("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -162,6 +167,8 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
return new TestTile1(mQSTileHost);
|
return new TestTile1(mQSTileHost);
|
||||||
} else if ("spec2".equals(spec)) {
|
} else if ("spec2".equals(spec)) {
|
||||||
return new TestTile2(mQSTileHost);
|
return new TestTile2(mQSTileHost);
|
||||||
|
} else if ("spec3".equals(spec)) {
|
||||||
|
return new TestTile3(mQSTileHost);
|
||||||
} else if ("na".equals(spec)) {
|
} else if ("na".equals(spec)) {
|
||||||
return new NotAvailableTile(mQSTileHost);
|
return new NotAvailableTile(mQSTileHost);
|
||||||
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
|
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
|
||||||
@@ -232,6 +239,8 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoRepeatedSpecs_addTile() {
|
public void testNoRepeatedSpecs_addTile() {
|
||||||
|
mContext.getOrCreateTestableResources()
|
||||||
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
||||||
|
|
||||||
mQSTileHost.addTile("spec1");
|
mQSTileHost.addTile("spec1");
|
||||||
@@ -241,6 +250,48 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddTileAtValidPosition() {
|
||||||
|
mContext.getOrCreateTestableResources()
|
||||||
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
|
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
||||||
|
|
||||||
|
mQSTileHost.addTile("spec2", 1);
|
||||||
|
|
||||||
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
||||||
|
assertEquals("spec3", mQSTileHost.mTileSpecs.get(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddTileAtInvalidPositionAddsToEnd() {
|
||||||
|
mContext.getOrCreateTestableResources()
|
||||||
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
|
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
||||||
|
|
||||||
|
mQSTileHost.addTile("spec2", 100);
|
||||||
|
|
||||||
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
|
assertEquals("spec3", mQSTileHost.mTileSpecs.get(1));
|
||||||
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddTileAtEnd() {
|
||||||
|
mContext.getOrCreateTestableResources()
|
||||||
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
|
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
||||||
|
|
||||||
|
mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END);
|
||||||
|
|
||||||
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
|
assertEquals("spec3", mQSTileHost.mTileSpecs.get(1));
|
||||||
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoRepeatedSpecs_customTile() {
|
public void testNoRepeatedSpecs_customTile() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC);
|
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC);
|
||||||
@@ -318,16 +369,17 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestQSTileHost extends QSTileHost {
|
private class TestQSTileHost extends QSTileHost {
|
||||||
TestQSTileHost(Context context, StatusBarIconController iconController,
|
TestQSTileHost(Context context, StatusBarIconController iconController,
|
||||||
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
|
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
|
||||||
PluginManager pluginManager, TunerService tunerService,
|
PluginManager pluginManager, TunerService tunerService,
|
||||||
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
||||||
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
|
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
|
||||||
UiEventLogger uiEventLogger, UserTracker userTracker) {
|
UiEventLogger uiEventLogger, UserTracker userTracker,
|
||||||
|
SecureSettings secureSettings) {
|
||||||
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
|
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
|
||||||
tunerService, autoTiles, dumpManager, broadcastDispatcher,
|
tunerService, autoTiles, dumpManager, broadcastDispatcher,
|
||||||
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker);
|
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -339,18 +391,16 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changeTiles(List<String> previousTiles, List<String> newTiles) {
|
void saveTilesToSettings(List<String> tileSpecs) {
|
||||||
String previousSetting = Settings.Secure.getStringForUser(
|
super.saveTilesToSettings(tileSpecs);
|
||||||
getContext().getContentResolver(), TILES_SETTING,
|
|
||||||
ActivityManager.getCurrentUser());
|
ArgumentCaptor<String> specs = ArgumentCaptor.forClass(String.class);
|
||||||
super.changeTiles(previousTiles, newTiles);
|
verify(mSecureSettings, atLeastOnce()).putStringForUser(eq(QSTileHost.TILES_SETTING),
|
||||||
|
specs.capture(), isNull(), eq(false), anyInt(), eq(true));
|
||||||
|
|
||||||
// After tiles are changed, make sure to call onTuningChanged with the new setting if it
|
// After tiles are changed, make sure to call onTuningChanged with the new setting if it
|
||||||
// changed
|
// changed
|
||||||
String newSetting = Settings.Secure.getStringForUser(getContext().getContentResolver(),
|
onTuningChanged(TILES_SETTING, specs.getValue());
|
||||||
TILES_SETTING, ActivityManager.getCurrentUser());
|
|
||||||
if (!Objects.equals(newSetting, previousSetting)) {
|
|
||||||
onTuningChanged(TILES_SETTING, newSetting);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,6 +465,13 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestTile3 extends TestTile {
|
||||||
|
|
||||||
|
protected TestTile3(QSHost host) {
|
||||||
|
super(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class NotAvailableTile extends TestTile {
|
private class NotAvailableTile extends TestTile {
|
||||||
|
|
||||||
protected NotAvailableTile(QSHost host) {
|
protected NotAvailableTile(QSHost host) {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
|
|||||||
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
||||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||||
import com.android.systemui.tuner.TunerService;
|
import com.android.systemui.tuner.TunerService;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -95,6 +96,8 @@ public class TileServicesTest extends SysuiTestCase {
|
|||||||
private UiEventLogger mUiEventLogger;
|
private UiEventLogger mUiEventLogger;
|
||||||
@Mock
|
@Mock
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
|
@Mock
|
||||||
|
private SecureSettings mSecureSettings;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -114,7 +117,8 @@ public class TileServicesTest extends SysuiTestCase {
|
|||||||
Optional.of(mStatusBar),
|
Optional.of(mStatusBar),
|
||||||
mQSLogger,
|
mQSLogger,
|
||||||
mUiEventLogger,
|
mUiEventLogger,
|
||||||
mUserTracker);
|
mUserTracker,
|
||||||
|
mSecureSettings);
|
||||||
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
|
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
|
||||||
mUserTracker);
|
mUserTracker);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,9 @@ import com.android.systemui.plugins.ActivityStarter
|
|||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.qs.QSHost
|
import com.android.systemui.qs.QSHost
|
||||||
import com.android.systemui.qs.logging.QSLogger
|
import com.android.systemui.qs.logging.QSLogger
|
||||||
import com.android.systemui.statusbar.FeatureFlags
|
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
import com.android.systemui.util.mockito.capture
|
import com.android.systemui.util.mockito.capture
|
||||||
import com.android.systemui.util.settings.FakeSettings
|
import com.android.systemui.util.settings.FakeSettings
|
||||||
import com.android.systemui.util.settings.GlobalSettings
|
|
||||||
import com.android.systemui.util.settings.SecureSettings
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@@ -83,9 +81,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
private lateinit var controlsController: ControlsController
|
private lateinit var controlsController: ControlsController
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var featureFlags: FeatureFlags
|
|
||||||
private lateinit var globalSettings: GlobalSettings
|
|
||||||
@Mock
|
|
||||||
private lateinit var serviceInfo: ControlsServiceInfo
|
private lateinit var serviceInfo: ControlsServiceInfo
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var uiEventLogger: UiEventLogger
|
private lateinit var uiEventLogger: UiEventLogger
|
||||||
@@ -116,11 +111,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
|
|
||||||
setupControlsComponent()
|
setupControlsComponent()
|
||||||
|
|
||||||
globalSettings = FakeSettings()
|
|
||||||
|
|
||||||
globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 1)
|
|
||||||
`when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(true)
|
|
||||||
|
|
||||||
tile = createTile()
|
tile = createTile()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,13 +145,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
assertThat(tile.isAvailable).isTrue()
|
assertThat(tile.isAvailable).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testNotAvailableFeature() {
|
|
||||||
`when`(featureFlags.isKeyguardLayoutEnabled).thenReturn(false)
|
|
||||||
|
|
||||||
assertThat(tile.isAvailable).isFalse()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNotAvailableControls() {
|
fun testNotAvailableControls() {
|
||||||
featureEnabled = false
|
featureEnabled = false
|
||||||
@@ -178,14 +161,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
assertThat(tile.isAvailable).isTrue()
|
assertThat(tile.isAvailable).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testNotAvailableControlsLockscreenFlag() {
|
|
||||||
globalSettings.putInt(DeviceControlsTile.SETTINGS_FLAG, 0)
|
|
||||||
tile = createTile()
|
|
||||||
|
|
||||||
assertThat(tile.isAvailable).isFalse()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testObservingCallback() {
|
fun testObservingCallback() {
|
||||||
verify(controlsListingController).observe(
|
verify(controlsListingController).observe(
|
||||||
@@ -329,9 +304,7 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
statusBarStateController,
|
statusBarStateController,
|
||||||
activityStarter,
|
activityStarter,
|
||||||
qsLogger,
|
qsLogger,
|
||||||
controlsComponent,
|
controlsComponent
|
||||||
featureFlags,
|
|
||||||
globalSettings
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import com.android.systemui.qs.SecureSetting;
|
|||||||
import com.android.systemui.statusbar.policy.CastController;
|
import com.android.systemui.statusbar.policy.CastController;
|
||||||
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
||||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController;
|
||||||
import com.android.systemui.statusbar.policy.HotspotController;
|
import com.android.systemui.statusbar.policy.HotspotController;
|
||||||
import com.android.systemui.util.settings.FakeSettings;
|
import com.android.systemui.util.settings.FakeSettings;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
@@ -94,6 +95,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
@Mock private ManagedProfileController mManagedProfileController;
|
@Mock private ManagedProfileController mManagedProfileController;
|
||||||
@Mock private NightDisplayListener mNightDisplayListener;
|
@Mock private NightDisplayListener mNightDisplayListener;
|
||||||
@Mock private ReduceBrightColorsController mReduceBrightColorsController;
|
@Mock private ReduceBrightColorsController mReduceBrightColorsController;
|
||||||
|
@Mock private DeviceControlsController mDeviceControlsController;;
|
||||||
@Mock(answer = Answers.RETURNS_SELF)
|
@Mock(answer = Answers.RETURNS_SELF)
|
||||||
private AutoAddTracker.Builder mAutoAddTrackerBuilder;
|
private AutoAddTracker.Builder mAutoAddTrackerBuilder;
|
||||||
@Mock private Context mUserContext;
|
@Mock private Context mUserContext;
|
||||||
@@ -139,6 +141,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
NightDisplayListener nightDisplayListener,
|
NightDisplayListener nightDisplayListener,
|
||||||
CastController castController,
|
CastController castController,
|
||||||
ReduceBrightColorsController reduceBrightColorsController,
|
ReduceBrightColorsController reduceBrightColorsController,
|
||||||
|
DeviceControlsController deviceControlsController,
|
||||||
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
|
||||||
return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
|
return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
|
||||||
Handler.createAsync(TestableLooper.get(this).getLooper()),
|
Handler.createAsync(TestableLooper.get(this).getLooper()),
|
||||||
@@ -149,13 +152,15 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
nightDisplayListener,
|
nightDisplayListener,
|
||||||
castController,
|
castController,
|
||||||
reduceBrightColorsController,
|
reduceBrightColorsController,
|
||||||
|
deviceControlsController,
|
||||||
isReduceBrightColorsAvailable);
|
isReduceBrightColorsAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoTileManager createAutoTileManager(Context context) {
|
private AutoTileManager createAutoTileManager(Context context) {
|
||||||
return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
|
return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
|
||||||
mDataSaverController, mManagedProfileController, mNightDisplayListener,
|
mDataSaverController, mManagedProfileController, mNightDisplayListener,
|
||||||
mCastController, mReduceBrightColorsController, mIsReduceBrightColorsAvailable);
|
mCastController, mReduceBrightColorsController, mDeviceControlsController,
|
||||||
|
mIsReduceBrightColorsAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -169,10 +174,11 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
NightDisplayListener nDS = mock(NightDisplayListener.class);
|
NightDisplayListener nDS = mock(NightDisplayListener.class);
|
||||||
CastController cC = mock(CastController.class);
|
CastController cC = mock(CastController.class);
|
||||||
ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
|
ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
|
||||||
|
DeviceControlsController dCC = mock(DeviceControlsController.class);
|
||||||
|
|
||||||
AutoTileManager manager =
|
AutoTileManager manager =
|
||||||
createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC,
|
createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC,
|
||||||
true);
|
dCC, true);
|
||||||
|
|
||||||
verify(tracker, never()).initialize();
|
verify(tracker, never()).initialize();
|
||||||
verify(hC, never()).addCallback(any());
|
verify(hC, never()).addCallback(any());
|
||||||
@@ -181,6 +187,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
verify(nDS, never()).setCallback(any());
|
verify(nDS, never()).setCallback(any());
|
||||||
verify(cC, never()).addCallback(any());
|
verify(cC, never()).addCallback(any());
|
||||||
verify(rBC, never()).addCallback(any());
|
verify(rBC, never()).addCallback(any());
|
||||||
|
verify(dCC, never()).setCallback(any());
|
||||||
assertNull(manager.getSecureSettingForKey(TEST_SETTING));
|
assertNull(manager.getSecureSettingForKey(TEST_SETTING));
|
||||||
assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT));
|
assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT));
|
||||||
}
|
}
|
||||||
@@ -229,6 +236,10 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
inOrderCast.verify(mCastController).removeCallback(any());
|
inOrderCast.verify(mCastController).removeCallback(any());
|
||||||
inOrderCast.verify(mCastController).addCallback(any());
|
inOrderCast.verify(mCastController).addCallback(any());
|
||||||
|
|
||||||
|
InOrder inOrderDevices = inOrder(mDeviceControlsController);
|
||||||
|
inOrderDevices.verify(mDeviceControlsController).removeCallback();
|
||||||
|
inOrderDevices.verify(mDeviceControlsController).setCallback(any());
|
||||||
|
|
||||||
SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
|
SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
|
||||||
assertEquals(USER + 1, setting.getCurrentUser());
|
assertEquals(USER + 1, setting.getCurrentUser());
|
||||||
assertTrue(setting.isListening());
|
assertTrue(setting.isListening());
|
||||||
@@ -273,6 +284,10 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
inOrderCast.verify(mCastController).removeCallback(any());
|
inOrderCast.verify(mCastController).removeCallback(any());
|
||||||
inOrderCast.verify(mCastController, never()).addCallback(any());
|
inOrderCast.verify(mCastController, never()).addCallback(any());
|
||||||
|
|
||||||
|
InOrder inOrderDevices = inOrder(mDeviceControlsController);
|
||||||
|
inOrderDevices.verify(mDeviceControlsController).removeCallback();
|
||||||
|
inOrderDevices.verify(mDeviceControlsController).setCallback(any());
|
||||||
|
|
||||||
SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
|
SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
|
||||||
assertEquals(USER + 1, setting.getCurrentUser());
|
assertEquals(USER + 1, setting.getCurrentUser());
|
||||||
assertFalse(setting.isListening());
|
assertFalse(setting.isListening());
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.statusbar.policy
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.controls.ControlsServiceInfo
|
||||||
|
import com.android.systemui.controls.dagger.ControlsComponent
|
||||||
|
import com.android.systemui.controls.controller.ControlsController
|
||||||
|
import com.android.systemui.controls.controller.SeedResponse
|
||||||
|
import com.android.systemui.controls.controller.StructureInfo
|
||||||
|
import com.android.systemui.controls.management.ControlsListingController
|
||||||
|
import com.android.systemui.controls.management.ControlsListingController.ControlsListingCallback
|
||||||
|
import com.android.systemui.settings.UserContextProvider
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_DEFAULT_POSITION
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_PRIORITY_POSITION
|
||||||
|
|
||||||
|
import java.util.Optional
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.times
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class DeviceControlsControllerImplTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var controlsComponent: ControlsComponent
|
||||||
|
@Mock
|
||||||
|
private lateinit var controlsController: ControlsController
|
||||||
|
@Mock
|
||||||
|
private lateinit var controlsListingController: ControlsListingController
|
||||||
|
@Mock
|
||||||
|
private lateinit var callback: DeviceControlsController.Callback
|
||||||
|
@Captor
|
||||||
|
private lateinit var listingCallbackCaptor: ArgumentCaptor<ControlsListingCallback>
|
||||||
|
@Mock
|
||||||
|
private lateinit var structureInfo: StructureInfo
|
||||||
|
@Mock
|
||||||
|
private lateinit var serviceInfo: ServiceInfo
|
||||||
|
@Mock
|
||||||
|
private lateinit var userContextProvider: UserContextProvider
|
||||||
|
@Captor
|
||||||
|
private lateinit var seedCallback: ArgumentCaptor<Consumer<SeedResponse>>
|
||||||
|
|
||||||
|
private lateinit var controlsServiceInfo: ControlsServiceInfo
|
||||||
|
private lateinit var controller: DeviceControlsControllerImpl
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
|
||||||
|
fun <T> eq(value: T): T = Mockito.eq(value) ?: value
|
||||||
|
private val TEST_PKG = "test.pkg"
|
||||||
|
private val TEST_COMPONENT = ComponentName(TEST_PKG, "test.class")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
`when`(controlsComponent.getControlsController())
|
||||||
|
.thenReturn(Optional.of(controlsController))
|
||||||
|
`when`(controlsComponent.getControlsListingController())
|
||||||
|
.thenReturn(Optional.of(controlsListingController))
|
||||||
|
|
||||||
|
controller = DeviceControlsControllerImpl(mContext, controlsComponent, userContextProvider)
|
||||||
|
|
||||||
|
`when`(serviceInfo.componentName).thenReturn(TEST_COMPONENT)
|
||||||
|
controlsServiceInfo = ControlsServiceInfo(mContext, serviceInfo)
|
||||||
|
|
||||||
|
`when`(userContextProvider.userContext).thenReturn(mContext)
|
||||||
|
mContext.getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE).edit()
|
||||||
|
.putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, emptySet())
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoCallbackWhenNoServicesAvailable() {
|
||||||
|
`when`(controlsController.getFavorites()).thenReturn(emptyList())
|
||||||
|
controller.setCallback(callback)
|
||||||
|
|
||||||
|
verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
|
||||||
|
listingCallbackCaptor.value.onServicesUpdated(emptyList())
|
||||||
|
verify(callback, never()).onControlsAvailable(anyInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetPriorityPositionIsSetWhenFavoritesAreAvailable() {
|
||||||
|
`when`(controlsController.getFavorites()).thenReturn(listOf(structureInfo))
|
||||||
|
controller.setCallback(callback)
|
||||||
|
|
||||||
|
verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
|
||||||
|
listingCallbackCaptor.value.onServicesUpdated(listOf(controlsServiceInfo))
|
||||||
|
verify(callback).onControlsAvailable(QS_PRIORITY_POSITION)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetDefaultPositionIsSetWhenNoFavoritesAreAvailable() {
|
||||||
|
`when`(controlsController.getFavorites()).thenReturn(emptyList())
|
||||||
|
controller.setCallback(callback)
|
||||||
|
|
||||||
|
mContext.getOrCreateTestableResources().addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PKG))
|
||||||
|
|
||||||
|
verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
|
||||||
|
listingCallbackCaptor.value.onServicesUpdated(listOf(controlsServiceInfo))
|
||||||
|
|
||||||
|
verify(controlsController).seedFavoritesForComponents(
|
||||||
|
eq(listOf(TEST_COMPONENT)),
|
||||||
|
capture(seedCallback)
|
||||||
|
)
|
||||||
|
seedCallback.value.accept(SeedResponse(TEST_PKG, true))
|
||||||
|
verify(callback).onControlsAvailable(QS_DEFAULT_POSITION)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user