Merge "Add Structure pages to management screens" into rvc-dev am: 7103ff4a7d
Change-Id: I4d2b09498e63f7ccfda3b3d7be19d02fd29aa62a
This commit is contained in:
@@ -46,6 +46,7 @@ android_library {
|
||||
"SystemUIPluginLib",
|
||||
"SystemUISharedLib",
|
||||
"SettingsLib",
|
||||
"androidx.viewpager2_viewpager2",
|
||||
"androidx.legacy_legacy-support-v4",
|
||||
"androidx.recyclerview_recyclerview",
|
||||
"androidx.preference_preference",
|
||||
@@ -106,6 +107,7 @@ android_library {
|
||||
"SystemUIPluginLib",
|
||||
"SystemUISharedLib",
|
||||
"SettingsLib",
|
||||
"androidx.viewpager2_viewpager2",
|
||||
"androidx.legacy_legacy-support-v4",
|
||||
"androidx.recyclerview_recyclerview",
|
||||
"androidx.preference_preference",
|
||||
|
||||
@@ -25,13 +25,40 @@
|
||||
android:paddingStart="@dimen/controls_management_side_padding"
|
||||
android:paddingEnd="@dimen/controls_management_side_padding" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/controls_title_size"
|
||||
android:textAlignment="center" />
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/icon_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|center_vertical"
|
||||
android:minWidth="56dp"
|
||||
android:visibility="gone"
|
||||
android:paddingTop="@dimen/controls_app_icon_frame_top_padding"
|
||||
android:paddingBottom="@dimen/controls_app_icon_frame_bottom_padding"
|
||||
android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"
|
||||
android:paddingStart="@dimen/controls_app_icon_frame_side_padding" >
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/controls_app_icon_size"
|
||||
android:layout_height="@dimen/controls_app_icon_size" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/controls_title_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
@@ -41,19 +68,11 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
<ViewStub
|
||||
android:id="@+id/stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="@dimen/controls_management_list_margin">
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -14,12 +14,18 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="@dimen/controls_management_list_margin">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
@@ -29,11 +29,17 @@
|
||||
android:gravity="center_horizontal"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/listAll"
|
||||
android:layout_width="match_parent"
|
||||
<com.android.systemui.controls.management.ManagementPageIndicator
|
||||
android:id="@+id/structure_page_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="@dimen/controls_management_list_margin"
|
||||
android:nestedScrollingEnabled="false"/>
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/structure_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
31
packages/SystemUI/res/layout/controls_structure_page.xml
Normal file
31
packages/SystemUI/res/layout/controls_structure_page.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="@dimen/controls_management_list_margin">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/listAll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -1249,6 +1249,7 @@
|
||||
<dimen name="controls_app_icon_size">32dp</dimen>
|
||||
<dimen name="controls_app_icon_frame_side_padding">8dp</dimen>
|
||||
<dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
|
||||
<dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen>
|
||||
<dimen name="controls_app_bottom_margin">8dp</dimen>
|
||||
<dimen name="controls_app_text_padding">8dp</dimen>
|
||||
<dimen name="controls_app_divider_height">2dp</dimen>
|
||||
|
||||
@@ -253,17 +253,21 @@ class ControlsControllerImpl @Inject constructor (
|
||||
}
|
||||
|
||||
override fun error(message: String) {
|
||||
val loadData = Favorites.getControlsForComponent(componentName).let {
|
||||
controls ->
|
||||
executor.execute {
|
||||
val loadData = Favorites.getControlsForComponent(componentName)
|
||||
.let { controls ->
|
||||
val keys = controls.map { it.controlId }
|
||||
createLoadDataObject(
|
||||
controls.map { createRemovedStatus(componentName, it, false) },
|
||||
keys,
|
||||
true
|
||||
controls.map {
|
||||
createRemovedStatus(componentName, it, false)
|
||||
},
|
||||
keys,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dataCallback.accept(loadData)
|
||||
dataCallback.accept(loadData)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -22,14 +22,20 @@ import com.android.systemui.controls.ControlStatus
|
||||
import com.android.systemui.controls.controller.ControlInfo
|
||||
|
||||
/**
|
||||
* This model is used to show all controls separated by zones.
|
||||
* This model is used to show controls separated by zones.
|
||||
*
|
||||
* The model will sort the controls and zones in the following manner:
|
||||
* * The zones will be sorted in a first seen basis
|
||||
* * The controls in each zone will be sorted in a first seen basis.
|
||||
*
|
||||
* @property controls List of all controls as returned by loading
|
||||
* @property initialFavoriteIds sorted ids of favorite controls
|
||||
* The controls passed should belong to the same structure, as an instance of this model will be
|
||||
* created for each structure.
|
||||
*
|
||||
* The list of favorite ids can contain ids for controls not passed to this model. Those will be
|
||||
* filtered out.
|
||||
*
|
||||
* @property controls List of controls as returned by loading
|
||||
* @property initialFavoriteIds sorted ids of favorite controls.
|
||||
* @property noZoneString text to use as header for all controls that have blank or `null` zone.
|
||||
*/
|
||||
class AllModel(
|
||||
@@ -50,7 +56,10 @@ class AllModel(
|
||||
}
|
||||
}
|
||||
|
||||
private val favoriteIds = initialFavoriteIds.toMutableList()
|
||||
private val favoriteIds = run {
|
||||
val ids = controls.mapTo(HashSet()) { it.control.controlId }
|
||||
initialFavoriteIds.filter { it in ids }.toMutableList()
|
||||
}
|
||||
|
||||
override val elements: List<ElementWrapper> = createWrappers(controls)
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
|
||||
* @param onlyFavorites set to true to only display favorites instead of all controls
|
||||
*/
|
||||
class ControlAdapter(
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val elevation: Float
|
||||
) : RecyclerView.Adapter<Holder>() {
|
||||
|
||||
@@ -60,6 +59,7 @@ class ControlAdapter(
|
||||
private var model: ControlsModel? = null
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
return when (viewType) {
|
||||
TYPE_CONTROL -> {
|
||||
ControlHolder(
|
||||
|
||||
@@ -19,20 +19,24 @@ package com.android.systemui.controls.management
|
||||
import android.app.Activity
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.view.ViewStub
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.controls.controller.StructureInfo
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.controller.ControlsControllerImpl
|
||||
import com.android.systemui.controls.controller.StructureInfo
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.qs.PageIndicator
|
||||
import com.android.systemui.settings.CurrentUserTracker
|
||||
import java.text.Collator
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.function.Consumer
|
||||
import javax.inject.Inject
|
||||
@@ -40,6 +44,7 @@ import javax.inject.Inject
|
||||
class ControlsFavoritingActivity @Inject constructor(
|
||||
@Main private val executor: Executor,
|
||||
private val controller: ControlsControllerImpl,
|
||||
private val listingController: ControlsListingController,
|
||||
broadcastDispatcher: BroadcastDispatcher
|
||||
) : Activity() {
|
||||
|
||||
@@ -48,12 +53,18 @@ class ControlsFavoritingActivity @Inject constructor(
|
||||
const val EXTRA_APP = "extra_app_label"
|
||||
}
|
||||
|
||||
private lateinit var recyclerViewAll: RecyclerView
|
||||
private lateinit var adapterAll: ControlAdapter
|
||||
private lateinit var statusText: TextView
|
||||
private var model: ControlsModel? = null
|
||||
private var component: ComponentName? = null
|
||||
private var structureName: CharSequence = ""
|
||||
private var appName: CharSequence? = null
|
||||
|
||||
private lateinit var structurePager: ViewPager2
|
||||
private lateinit var statusText: TextView
|
||||
private lateinit var titleView: TextView
|
||||
private lateinit var iconView: ImageView
|
||||
private lateinit var iconFrame: View
|
||||
private lateinit var pageIndicator: PageIndicator
|
||||
private var listOfStructures = emptyList<StructureContainer>()
|
||||
|
||||
private lateinit var comparator: Comparator<StructureContainer>
|
||||
|
||||
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
|
||||
private val startingUser = controller.currentUserId
|
||||
@@ -66,29 +77,117 @@ class ControlsFavoritingActivity @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
|
||||
private var icon: Drawable? = null
|
||||
|
||||
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
||||
val newIcon = serviceInfos.firstOrNull { it.componentName == component }?.loadIcon()
|
||||
if (icon == newIcon) return
|
||||
icon = newIcon
|
||||
executor.execute {
|
||||
if (icon != null) {
|
||||
iconView.setImageDrawable(icon)
|
||||
}
|
||||
iconFrame.visibility = if (icon != null) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val collator = Collator.getInstance(resources.configuration.locales[0])
|
||||
comparator = compareBy(collator) { it.structureName }
|
||||
appName = intent.getCharSequenceExtra(EXTRA_APP)
|
||||
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
|
||||
|
||||
bindViews()
|
||||
|
||||
setUpPager()
|
||||
|
||||
loadControls()
|
||||
|
||||
listingController.addCallback(listingCallback)
|
||||
|
||||
currentUserTracker.startTracking()
|
||||
}
|
||||
|
||||
private fun loadControls() {
|
||||
component?.let {
|
||||
statusText.text = resources.getText(com.android.internal.R.string.loading)
|
||||
val emptyZoneString = resources.getText(
|
||||
R.string.controls_favorite_other_zone_header)
|
||||
controller.loadForComponent(it, Consumer { data ->
|
||||
val allControls = data.allControls
|
||||
val favoriteKeys = data.favoritesIds
|
||||
val error = data.errorOnLoad
|
||||
val controlsByStructure = allControls.groupBy { it.control.structure ?: "" }
|
||||
listOfStructures = controlsByStructure.map {
|
||||
StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
|
||||
}.sortedWith(comparator)
|
||||
executor.execute {
|
||||
structurePager.adapter = StructureAdapter(listOfStructures)
|
||||
if (error) {
|
||||
statusText.text = resources.getText(R.string.controls_favorite_load_error)
|
||||
} else {
|
||||
statusText.visibility = View.GONE
|
||||
}
|
||||
pageIndicator.setNumPages(listOfStructures.size)
|
||||
pageIndicator.setLocation(0f)
|
||||
pageIndicator.visibility =
|
||||
if (listOfStructures.size > 1) View.VISIBLE else View.GONE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpPager() {
|
||||
structurePager.apply {
|
||||
adapter = StructureAdapter(emptyList())
|
||||
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
val name = listOfStructures[position].structureName
|
||||
titleView.text = if (!TextUtils.isEmpty(name)) name else appName
|
||||
}
|
||||
|
||||
override fun onPageScrolled(
|
||||
position: Int,
|
||||
positionOffset: Float,
|
||||
positionOffsetPixels: Int
|
||||
) {
|
||||
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
|
||||
pageIndicator.setLocation(position + positionOffset)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindViews() {
|
||||
setContentView(R.layout.controls_management)
|
||||
requireViewById<ViewStub>(R.id.stub).apply {
|
||||
layoutResource = R.layout.controls_management_favorites
|
||||
inflate()
|
||||
}
|
||||
|
||||
val app = intent.getCharSequenceExtra(EXTRA_APP)
|
||||
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
|
||||
statusText = requireViewById(R.id.status_message)
|
||||
pageIndicator = requireViewById(R.id.structure_page_indicator)
|
||||
|
||||
setUpRecyclerView()
|
||||
|
||||
requireViewById<TextView>(R.id.title).text = app?.let { it }
|
||||
?: resources.getText(R.string.controls_favorite_default_title)
|
||||
titleView = requireViewById<TextView>(R.id.title).apply {
|
||||
text = appName ?: resources.getText(R.string.controls_favorite_default_title)
|
||||
}
|
||||
requireViewById<TextView>(R.id.subtitle).text =
|
||||
resources.getText(R.string.controls_favorite_subtitle)
|
||||
iconView = requireViewById(com.android.internal.R.id.icon)
|
||||
iconFrame = requireViewById(R.id.icon_frame)
|
||||
structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
|
||||
bindButtons()
|
||||
}
|
||||
|
||||
private fun bindButtons() {
|
||||
requireViewById<Button>(R.id.other_apps).apply {
|
||||
visibility = View.VISIBLE
|
||||
setOnClickListener {
|
||||
@@ -98,64 +197,21 @@ class ControlsFavoritingActivity @Inject constructor(
|
||||
|
||||
requireViewById<Button>(R.id.done).setOnClickListener {
|
||||
if (component == null) return@setOnClickListener
|
||||
val favoritesForStorage = model?.favorites?.map {
|
||||
it.build()
|
||||
}
|
||||
if (favoritesForStorage != null) {
|
||||
controller.replaceFavoritesForStructure(StructureInfo(component!!, structureName,
|
||||
listOfStructures.forEach {
|
||||
val favoritesForStorage = it.model.favorites.map { it.build() }
|
||||
controller.replaceFavoritesForStructure(StructureInfo(component!!, it.structureName,
|
||||
favoritesForStorage))
|
||||
finishAffinity()
|
||||
}
|
||||
}
|
||||
|
||||
component?.let {
|
||||
statusText.text = resources.getText(com.android.internal.R.string.loading)
|
||||
controller.loadForComponent(it, Consumer { data ->
|
||||
val allControls = data.allControls
|
||||
val favoriteKeys = data.favoritesIds
|
||||
val error = data.errorOnLoad
|
||||
val structures = allControls.fold(hashSetOf<CharSequence>()) {
|
||||
s, c ->
|
||||
s.add(c.control.structure ?: "")
|
||||
s
|
||||
}
|
||||
// TODO add multi structure switching support
|
||||
executor.execute {
|
||||
val emptyZoneString = resources.getText(
|
||||
R.string.controls_favorite_other_zone_header)
|
||||
val model = AllModel(allControls, favoriteKeys, emptyZoneString)
|
||||
adapterAll.changeModel(model)
|
||||
this.model = model
|
||||
if (error) {
|
||||
statusText.text = resources.getText(R.string.controls_favorite_load_error)
|
||||
} else {
|
||||
statusText.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
currentUserTracker.startTracking()
|
||||
}
|
||||
|
||||
private fun setUpRecyclerView() {
|
||||
val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
|
||||
val itemDecorator = MarginItemDecorator(margin, margin)
|
||||
val layoutInflater = LayoutInflater.from(applicationContext)
|
||||
val elevation = resources.getFloat(R.dimen.control_card_elevation)
|
||||
|
||||
adapterAll = ControlAdapter(layoutInflater, elevation)
|
||||
recyclerViewAll = requireViewById<RecyclerView>(R.id.listAll).apply {
|
||||
adapter = adapterAll
|
||||
layoutManager = GridLayoutManager(applicationContext, 2).apply {
|
||||
spanSizeLookup = adapterAll.spanSizeLookup
|
||||
}
|
||||
addItemDecoration(itemDecorator)
|
||||
finishAffinity()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
currentUserTracker.stopTracking()
|
||||
listingController.removeCallback(listingCallback)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
data class StructureContainer(val structureName: CharSequence, val model: ControlsModel)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls.management
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.android.systemui.qs.PageIndicator
|
||||
|
||||
/**
|
||||
* Page indicator for management screens.
|
||||
*
|
||||
* Adds RTL support to [PageIndicator]. To be used with [ViewPager2].
|
||||
*/
|
||||
class ManagementPageIndicator(
|
||||
context: Context,
|
||||
attrs: AttributeSet
|
||||
) : PageIndicator(context, attrs) {
|
||||
|
||||
override fun setLocation(location: Float) {
|
||||
// Location doesn't know about RTL
|
||||
if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
|
||||
val numPages = childCount
|
||||
super.setLocation(numPages - 1 - location)
|
||||
} else {
|
||||
super.setLocation(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls.management
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.android.systemui.R
|
||||
|
||||
class StructureAdapter(
|
||||
private val models: List<StructureContainer>
|
||||
) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
return StructureHolder(
|
||||
layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount() = models.size
|
||||
|
||||
override fun onBindViewHolder(holder: StructureHolder, index: Int) {
|
||||
holder.bind(models[index].model)
|
||||
}
|
||||
|
||||
class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val recyclerView: RecyclerView
|
||||
private val controlAdapter: ControlAdapter
|
||||
|
||||
init {
|
||||
recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
|
||||
val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
|
||||
controlAdapter = ControlAdapter(elevation)
|
||||
setUpRecyclerView()
|
||||
}
|
||||
|
||||
fun bind(model: ControlsModel) {
|
||||
controlAdapter.changeModel(model)
|
||||
}
|
||||
|
||||
private fun setUpRecyclerView() {
|
||||
val margin = itemView.context.resources
|
||||
.getDimensionPixelSize(R.dimen.controls_card_margin)
|
||||
val itemDecorator = MarginItemDecorator(margin, margin)
|
||||
|
||||
recyclerView.apply {
|
||||
this.adapter = controlAdapter
|
||||
layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
|
||||
spanSizeLookup = controlAdapter.spanSizeLookup
|
||||
}
|
||||
addItemDecoration(itemDecorator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,6 +340,8 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
||||
|
||||
controlLoadCallbackCaptor.value.error("")
|
||||
|
||||
delayableExecutor.runAllReady()
|
||||
|
||||
assertTrue(loaded)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user