Controls UI - Support detail panels
Allow apps to specify whether to show full screen or within detail panels. Default camers and thermostats to use the panel by default when the following flag is enabled. Enable by: adb shell settings put secure systemui.controls_use_panel 1 Change offset from the top in Px: adb shell settings put secure systemui.controls_panel_top_offset XXX Bug: 152528130 Test: manual, use camera, thermostat devices Change-Id: Ia1b12afcf4de2a0bcf7957e6425b282b1e220f46
This commit is contained in:
26
packages/SystemUI/res/anim/bottomsheet_in.xml
Normal file
26
packages/SystemUI/res/anim/bottomsheet_in.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 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
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@*android:anim/accelerate_decelerate_interpolator"
|
||||
android:zAdjustment="top">
|
||||
|
||||
<translate android:fromYDelta="100%"
|
||||
android:toYDelta="0"
|
||||
android:startOffset="@android:integer/config_shortAnimTime"
|
||||
android:duration="@*android:integer/config_mediumAnimTime"/>
|
||||
</set>
|
||||
25
packages/SystemUI/res/anim/bottomsheet_out.xml
Normal file
25
packages/SystemUI/res/anim/bottomsheet_out.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 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
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@*android:anim/accelerate_interpolator"
|
||||
android:zAdjustment="top">
|
||||
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="100%"
|
||||
android:duration="@*android:integer/config_shortAnimTime" />
|
||||
</set>
|
||||
22
packages/SystemUI/res/drawable/rounded_bg_top.xml
Normal file
22
packages/SystemUI/res/drawable/rounded_bg_top.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?android:attr/colorPrimaryDark" />
|
||||
<corners
|
||||
android:topLeftRadius="?android:attr/dialogCornerRadius"
|
||||
android:topRightRadius="?android:attr/dialogCornerRadius" />
|
||||
</shape>
|
||||
@@ -15,9 +15,76 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/controls_activity_view"
|
||||
android:id="@+id/control_detail_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/controls_activity_view_top_offset"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="10dp">
|
||||
<ImageView
|
||||
android:id="@+id/control_detail_close"
|
||||
android:contentDescription="@string/accessibility_desc_close"
|
||||
android:src="@drawable/ic_close"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:tint="@color/control_primary_text"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:padding="12dp" />
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="1dp" />
|
||||
<ImageView
|
||||
android:id="@+id/control_detail_open_in_app"
|
||||
android:src="@drawable/ic_open_in_new"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:tint="@color/control_primary_text"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:padding="12dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/controls_activity_view_top_padding"
|
||||
android:paddingLeft="@dimen/controls_activity_view_side_padding"
|
||||
android:paddingRight="@dimen/controls_activity_view_side_padding"
|
||||
android:background="@drawable/rounded_bg_top"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.ControlDialog"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.ControlDialog"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/controls_activity_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -1250,6 +1250,12 @@
|
||||
<dimen name="control_base_item_margin">2dp</dimen>
|
||||
<dimen name="control_status_padding">3dp</dimen>
|
||||
|
||||
<!-- Home Controls activity view detail panel-->
|
||||
<dimen name="controls_activity_view_top_padding">25dp</dimen>
|
||||
<dimen name="controls_activity_view_side_padding">12dp</dimen>
|
||||
<dimen name="controls_activity_view_top_offset">200dp</dimen>
|
||||
<dimen name="controls_activity_view_text_size">17sp</dimen>
|
||||
|
||||
<!-- Home Controls management screens -->
|
||||
<dimen name="controls_management_top_padding">48dp</dimen>
|
||||
<dimen name="controls_management_side_padding">8dp</dimen>
|
||||
|
||||
@@ -671,6 +671,19 @@
|
||||
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
|
||||
<item name="android:windowAnimationStyle">@style/Animation.Bottomsheet</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Animation.Bottomsheet">
|
||||
<item name="android:windowEnterAnimation">@anim/bottomsheet_in</item>
|
||||
<item name="android:windowExitAnimation">@anim/bottomsheet_out</item>
|
||||
</style>
|
||||
|
||||
<style name="Control" />
|
||||
|
||||
<style name="Control.MenuItem">
|
||||
@@ -713,6 +726,11 @@
|
||||
<item name="android:textSize">@dimen/control_text_size</item>
|
||||
<item name="android:textColor">@color/control_secondary_text</item>
|
||||
</style>
|
||||
<style name="TextAppearance.ControlDialog">
|
||||
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
|
||||
<item name="android:textSize">@dimen/controls_activity_view_text_size</item>
|
||||
<item name="android:textColor">@color/control_primary_text</item>
|
||||
</style>
|
||||
<style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow">
|
||||
<item name="android:overlapAnchor">true</item>
|
||||
|
||||
|
||||
@@ -16,19 +16,27 @@
|
||||
|
||||
package com.android.systemui.controls.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.actions.BooleanAction
|
||||
import android.service.controls.actions.CommandAction
|
||||
import android.util.Log
|
||||
import android.view.HapticFeedbackConstants
|
||||
|
||||
import com.android.systemui.R
|
||||
|
||||
object ControlActionCoordinator {
|
||||
public const val MIN_LEVEL = 0
|
||||
public const val MAX_LEVEL = 10000
|
||||
|
||||
private var useDetailDialog: Boolean? = null
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
fun closeDialog() {
|
||||
dialog?.dismiss()
|
||||
dialog = null
|
||||
}
|
||||
|
||||
fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
|
||||
cvh.action(BooleanAction(templateId, !isChecked))
|
||||
@@ -37,31 +45,39 @@ object ControlActionCoordinator {
|
||||
cvh.clipLayer.setLevel(nextLevel)
|
||||
}
|
||||
|
||||
fun touch(cvh: ControlViewHolder, templateId: String) {
|
||||
cvh.action(CommandAction(templateId))
|
||||
fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
|
||||
if (cvh.usePanel()) {
|
||||
showDialog(cvh, control.getAppIntent().getIntent())
|
||||
} else {
|
||||
cvh.action(CommandAction(templateId))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow apps to specify whether they would like to appear in a detail panel or within
|
||||
* the full activity by setting the {@link Control#EXTRA_USE_PANEL} flag. In order for
|
||||
* activities to determine how they are being launched, they should inspect the
|
||||
* {@link Control#EXTRA_USE_PANEL} flag for a value of true.
|
||||
*/
|
||||
fun longPress(cvh: ControlViewHolder) {
|
||||
// Long press snould only be called when there is valid control state, otherwise ignore
|
||||
cvh.cws.control?.let {
|
||||
if (useDetailDialog == null) {
|
||||
useDetailDialog = Settings.Secure.getInt(cvh.context.getContentResolver(),
|
||||
"systemui.controls_use_detail_panel", 0) != 0
|
||||
}
|
||||
|
||||
try {
|
||||
it.getAppIntent().send()
|
||||
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
if (useDetailDialog!!) {
|
||||
DetailDialog(cvh.context, it.getAppIntent()).show()
|
||||
} else {
|
||||
it.getAppIntent().send()
|
||||
val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
|
||||
cvh.context.sendBroadcast(closeDialog)
|
||||
}
|
||||
cvh.context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||
} catch (e: PendingIntent.CanceledException) {
|
||||
Log.e(ControlsUiController.TAG, "Error sending pending intent", e)
|
||||
cvh.setTransientStatus("Error opening application")
|
||||
cvh.setTransientStatus(
|
||||
cvh.context.resources.getString(R.string.controls_error_failed))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDialog(cvh: ControlViewHolder, intent: Intent) {
|
||||
dialog = DetailDialog(cvh, intent).also {
|
||||
it.setOnDismissListener { _ -> dialog = null }
|
||||
it.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,29 @@ import com.android.systemui.R
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val UPDATE_DELAY_IN_MILLIS = 3000L
|
||||
private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
|
||||
private const val ALPHA_DISABLED = 255
|
||||
|
||||
/**
|
||||
* Wraps the widgets that make up the UI representation of a {@link Control}. Updates to the view
|
||||
* are signaled via calls to {@link #bindData}. Similar to the ViewHolder concept used in
|
||||
* RecyclerViews.
|
||||
*/
|
||||
class ControlViewHolder(
|
||||
val layout: ViewGroup,
|
||||
val controlsController: ControlsController,
|
||||
val uiExecutor: DelayableExecutor,
|
||||
val bgExecutor: DelayableExecutor
|
||||
val bgExecutor: DelayableExecutor,
|
||||
val usePanels: Boolean
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val UPDATE_DELAY_IN_MILLIS = 3000L
|
||||
private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
|
||||
private const val ALPHA_DISABLED = 255
|
||||
private val FORCE_PANEL_DEVICES = setOf(
|
||||
DeviceTypes.TYPE_THERMOSTAT,
|
||||
DeviceTypes.TYPE_CAMERA
|
||||
)
|
||||
}
|
||||
|
||||
val icon: ImageView = layout.requireViewById(R.id.icon)
|
||||
val status: TextView = layout.requireViewById(R.id.status)
|
||||
val title: TextView = layout.requireViewById(R.id.title)
|
||||
@@ -59,6 +72,8 @@ class ControlViewHolder(
|
||||
var cancelUpdate: Runnable? = null
|
||||
var behavior: Behavior? = null
|
||||
var lastAction: ControlAction? = null
|
||||
val deviceType: Int
|
||||
get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
|
||||
|
||||
init {
|
||||
val ld = layout.getBackground() as LayerDrawable
|
||||
@@ -76,7 +91,7 @@ class ControlViewHolder(
|
||||
val (controlStatus, template) = cws.control?.let {
|
||||
title.setText(it.getTitle())
|
||||
subtitle.setText(it.getSubtitle())
|
||||
Pair(it.getStatus(), it.getControlTemplate())
|
||||
Pair(it.status, it.controlTemplate)
|
||||
} ?: run {
|
||||
title.setText(cws.ci.controlTitle)
|
||||
subtitle.setText(cws.ci.controlSubtitle)
|
||||
@@ -91,7 +106,7 @@ class ControlViewHolder(
|
||||
})
|
||||
}
|
||||
|
||||
val clazz = findBehavior(controlStatus, template)
|
||||
val clazz = findBehavior(controlStatus, template, deviceType)
|
||||
if (behavior == null || behavior!!::class != clazz) {
|
||||
// Behavior changes can signal a change in template from the app or
|
||||
// first time setup
|
||||
@@ -126,9 +141,17 @@ class ControlViewHolder(
|
||||
controlsController.action(cws.componentName, cws.ci, action)
|
||||
}
|
||||
|
||||
private fun findBehavior(status: Int, template: ControlTemplate): KClass<out Behavior> {
|
||||
fun usePanel(): Boolean =
|
||||
usePanels && deviceType in ControlViewHolder.FORCE_PANEL_DEVICES
|
||||
|
||||
private fun findBehavior(
|
||||
status: Int,
|
||||
template: ControlTemplate,
|
||||
deviceType: Int
|
||||
): KClass<out Behavior> {
|
||||
return when {
|
||||
status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
|
||||
deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
|
||||
template is ToggleTemplate -> ToggleBehavior::class
|
||||
template is StatelessTemplate -> TouchBehavior::class
|
||||
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
|
||||
@@ -140,7 +163,6 @@ class ControlViewHolder(
|
||||
internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
|
||||
setEnabled(enabled)
|
||||
|
||||
val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
|
||||
val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
|
||||
|
||||
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.content.res.Configuration
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Process
|
||||
import android.provider.Settings
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.actions.ControlAction
|
||||
import android.util.TypedValue
|
||||
@@ -85,6 +86,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
private const val PREF_COMPONENT = "controls_component"
|
||||
private const val PREF_STRUCTURE = "controls_structure"
|
||||
|
||||
private const val USE_PANELS = "systemui.controls_use_panel"
|
||||
private const val FADE_IN_MILLIS = 225L
|
||||
|
||||
private val EMPTY_COMPONENT = ComponentName("", "")
|
||||
@@ -407,6 +409,9 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
|
||||
val maxColumns = findMaxColumns()
|
||||
|
||||
// use flag only temporarily for testing
|
||||
val usePanels = Settings.Secure.getInt(context.contentResolver, USE_PANELS, 0) == 1
|
||||
|
||||
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
|
||||
var lastRow: ViewGroup = createRow(inflater, listView)
|
||||
selectedStructure.controls.forEach {
|
||||
@@ -420,7 +425,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
baseLayout,
|
||||
controlsController.get(),
|
||||
uiExecutor,
|
||||
bgExecutor
|
||||
bgExecutor,
|
||||
usePanels
|
||||
)
|
||||
val key = ControlKey(selectedStructure.componentName, it.controlId)
|
||||
cvh.bindData(controlsById.getValue(key))
|
||||
@@ -500,6 +506,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
hidden = true
|
||||
popup?.dismiss()
|
||||
activeDialog?.dismiss()
|
||||
ControlActionCoordinator.closeDialog()
|
||||
|
||||
controlsController.get().unsubscribe()
|
||||
|
||||
|
||||
@@ -17,18 +17,16 @@
|
||||
package com.android.systemui.controls.ui
|
||||
|
||||
import android.app.ActivityView
|
||||
import android.app.ActivityOptions
|
||||
import android.app.Dialog
|
||||
import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.Window
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import com.android.systemui.R
|
||||
|
||||
@@ -38,20 +36,26 @@ import com.android.systemui.R
|
||||
* The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}.
|
||||
*/
|
||||
class DetailDialog(
|
||||
val parentContext: Context,
|
||||
val intent: PendingIntent
|
||||
) : Dialog(parentContext) {
|
||||
val cvh: ControlViewHolder,
|
||||
val intent: Intent
|
||||
) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
|
||||
|
||||
var activityView: ActivityView
|
||||
companion object {
|
||||
private const val ALPHA = (0.8f * 255).toInt()
|
||||
private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset"
|
||||
}
|
||||
|
||||
lateinit var activityView: ActivityView
|
||||
|
||||
val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
|
||||
override fun onActivityViewReady(view: ActivityView) {
|
||||
val fillInIntent = Intent()
|
||||
val launchIntent = Intent(intent)
|
||||
|
||||
// Apply flags to make behaviour match documentLaunchMode=always.
|
||||
fillInIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
view.startActivity(intent, fillInIntent, ActivityOptions.makeBasic())
|
||||
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
|
||||
view.startActivity(launchIntent)
|
||||
}
|
||||
|
||||
override fun onActivityViewDestroyed(view: ActivityView) {}
|
||||
@@ -61,28 +65,8 @@ class DetailDialog(
|
||||
override fun onTaskRemovalStarted(taskId: Int) {}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun Window.setWindowParams() {
|
||||
requestFeature(Window.FEATURE_NO_TITLE)
|
||||
|
||||
// Inflate the decor view, so the attributes below are not overwritten by the theme.
|
||||
decorView
|
||||
attributes.systemUiVisibility =
|
||||
(attributes.systemUiVisibility
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
|
||||
|
||||
setLayout(MATCH_PARENT, MATCH_PARENT)
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||
addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||
or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
|
||||
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
|
||||
setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
|
||||
getAttributes().setFitInsetsTypes(0 /* types */)
|
||||
}
|
||||
|
||||
init {
|
||||
getWindow()?.setWindowParams()
|
||||
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
|
||||
|
||||
setContentView(R.layout.controls_detail_dialog)
|
||||
|
||||
@@ -90,19 +74,61 @@ class DetailDialog(
|
||||
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
|
||||
addView(activityView)
|
||||
}
|
||||
|
||||
requireViewById<ImageView>(R.id.control_detail_close).apply {
|
||||
setOnClickListener { _: View -> dismiss() }
|
||||
}
|
||||
|
||||
requireViewById<TextView>(R.id.title).apply {
|
||||
setText(cvh.title.text)
|
||||
}
|
||||
|
||||
requireViewById<TextView>(R.id.subtitle).apply {
|
||||
setText(cvh.subtitle.text)
|
||||
}
|
||||
|
||||
requireViewById<ImageView>(R.id.control_detail_open_in_app).apply {
|
||||
setOnClickListener { v: View ->
|
||||
dismiss()
|
||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||
v.context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
// consume all insets to achieve slide under effect
|
||||
window.getDecorView().setOnApplyWindowInsetsListener {
|
||||
v: View, insets: WindowInsets ->
|
||||
activityView.apply {
|
||||
val l = getPaddingLeft()
|
||||
val t = getPaddingTop()
|
||||
val r = getPaddingRight()
|
||||
setPadding(l, t, r, insets.getSystemWindowInsets().bottom)
|
||||
}
|
||||
|
||||
insets.consumeSystemWindowInsets()
|
||||
}
|
||||
|
||||
requireViewById<ViewGroup>(R.id.control_detail_root).apply {
|
||||
// use flag only temporarily for testing
|
||||
val resolver = cvh.context.contentResolver
|
||||
val defaultOffsetInPx = cvh.context.resources
|
||||
.getDimensionPixelSize(R.dimen.controls_activity_view_top_offset)
|
||||
val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx)
|
||||
|
||||
val lp = getLayoutParams() as ViewGroup.MarginLayoutParams
|
||||
lp.topMargin = offsetInPx
|
||||
setLayoutParams(lp)
|
||||
}
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
val attrs = getWindow()?.attributes
|
||||
attrs?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
||||
getWindow()?.attributes = attrs
|
||||
|
||||
activityView.setCallback(stateCallback)
|
||||
|
||||
super.show()
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
if (!isShowing()) return
|
||||
activityView.release()
|
||||
|
||||
super.dismiss()
|
||||
|
||||
@@ -33,6 +33,10 @@ class TemperatureControlBehavior : Behavior {
|
||||
|
||||
override fun initialize(cvh: ControlViewHolder) {
|
||||
this.cvh = cvh
|
||||
|
||||
cvh.layout.setOnClickListener { _ ->
|
||||
ControlActionCoordinator.touch(cvh, template.getTemplateId(), control)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bind(cws: ControlWithState) {
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.view.View
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.templates.StatelessTemplate
|
||||
import android.service.controls.templates.ControlTemplate
|
||||
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
|
||||
@@ -31,7 +31,7 @@ import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
|
||||
*/
|
||||
class TouchBehavior : Behavior {
|
||||
lateinit var clipLayer: Drawable
|
||||
lateinit var template: StatelessTemplate
|
||||
lateinit var template: ControlTemplate
|
||||
lateinit var control: Control
|
||||
lateinit var cvh: ControlViewHolder
|
||||
|
||||
@@ -40,14 +40,14 @@ class TouchBehavior : Behavior {
|
||||
cvh.applyRenderInfo(false)
|
||||
|
||||
cvh.layout.setOnClickListener(View.OnClickListener() {
|
||||
ControlActionCoordinator.touch(cvh, template.getTemplateId())
|
||||
ControlActionCoordinator.touch(cvh, template.getTemplateId(), control)
|
||||
})
|
||||
}
|
||||
|
||||
override fun bind(cws: ControlWithState) {
|
||||
this.control = cws.control!!
|
||||
cvh.status.setText(control.getStatusText())
|
||||
template = control.getControlTemplate() as StatelessTemplate
|
||||
template = control.getControlTemplate()
|
||||
|
||||
val ld = cvh.layout.getBackground() as LayerDrawable
|
||||
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
|
||||
|
||||
Reference in New Issue
Block a user