From 1e3178de3b51aa14046b30d9d633af518e5eb114 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Wed, 19 Feb 2020 09:32:27 -0500 Subject: [PATCH] Changed management to just show all controls This is the first of a series of CLs to update management screens to latest mocks. Now ControlModel is an interface to interact with the Adapters. Different implementers can be used to surface different views of all the controls. Zones are now sorted according to the order they appear on load. Zones with no name (or blank name) are given a generic "Other" and put at the end. Test: atest Test: manual Bug: 149138395 Change-Id: Ica708d903afed582c4c6ad4a5142351cd81cec89 --- .../res/layout/controls_management.xml | 9 +- .../layout/controls_management_favorites.xml | 79 +------ packages/SystemUI/res/values/strings.xml | 10 +- .../systemui/controls/management/AllModel.kt | 114 +++++++++++ .../controls/management/AppAdapter.kt | 6 +- .../controls/management/ControlAdapter.kt | 49 +++-- .../management/ControlsFavoritingActivity.kt | 81 +++----- .../controls/management/ControlsModel.kt | 59 ++++++ .../ControlsProviderSelectorActivity.kt | 5 + .../controls/management/FavoriteModel.kt | 10 +- .../controls/management/AllModelTest.kt | 192 ++++++++++++++++++ 11 files changed, 446 insertions(+), 168 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt create mode 100644 packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml index a7379bedebefe..6533c18a41a97 100644 --- a/packages/SystemUI/res/layout/controls_management.xml +++ b/packages/SystemUI/res/layout/controls_management.xml @@ -70,12 +70,14 @@ android:layout_height="match_parent" android:padding="4dp"> - @@ -85,6 +87,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:text="Done" + style="@*android:style/Widget.DeviceDefault.Button.Colored" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/> diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml index 62056e60372d8..aab32f45e77a4 100644 --- a/packages/SystemUI/res/layout/controls_management_favorites.xml +++ b/packages/SystemUI/res/layout/controls_management_favorites.xml @@ -14,97 +14,26 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - - - - - - - - - + android:nestedScrollingEnabled="false"/> - \ No newline at end of file + \ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4aafec886a371..ff28b4d289e86 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2614,8 +2614,8 @@ Choose an app from which to add controls - %s current favorite. - %s current favorites. + %s control added. + %s controls added. @@ -2626,6 +2626,10 @@ Favorites All - + The list of all controls could not be loaded. + + Other + + diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt new file mode 100644 index 0000000000000..c05351795aed2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019 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.text.TextUtils +import android.util.ArrayMap +import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.controller.ControlInfo + +/** + * This model is used to show all 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 + * @property noZoneString text to use as header for all controls that have blank or `null` zone. + */ +class AllModel( + private val controls: List, + initialFavoriteIds: List, + private val emptyZoneString: CharSequence +) : ControlsModel { + + override val favorites: List + get() = favoriteIds.mapNotNull { id -> + val control = controls.firstOrNull { it.control.controlId == id }?.control + control?.let { + ControlInfo.Builder().apply { + controlId = it.controlId + controlTitle = it.title + deviceType = it.deviceType + } + } + } + + private val favoriteIds = initialFavoriteIds.toMutableList() + + override val elements: List = createWrappers(controls) + + override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { + if (favorite) { + favoriteIds.add(controlId) + } else { + favoriteIds.remove(controlId) + } + } + + private fun createWrappers(list: List): List { + val map = list.groupByTo(OrderedMap(ArrayMap>())) { + it.control.zone ?: "" + } + val output = mutableListOf() + var emptyZoneValues: Sequence? = null + for (zoneName in map.orderedKeys) { + val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) } + if (TextUtils.isEmpty(zoneName)) { + emptyZoneValues = values + } else { + output.add(ZoneNameWrapper(zoneName)) + output.addAll(values) + } + } + // Add controls with empty zone at the end + if (emptyZoneValues != null) { + if (map.size != 1) { + output.add(ZoneNameWrapper(emptyZoneString)) + } + output.addAll(emptyZoneValues) + } + return output + } + + private class OrderedMap(private val map: MutableMap) : MutableMap by map { + + val orderedKeys = mutableListOf() + + override fun put(key: K, value: V): V? { + if (key !in map) { + orderedKeys.add(key) + } + return map.put(key, value) + } + + override fun clear() { + orderedKeys.clear() + map.clear() + } + + override fun remove(key: K): V? { + val removed = map.remove(key) + if (removed != null) { + orderedKeys.remove(key) + } + return removed + } + } +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt index ac5e0893b526a..25ebc65357ee7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt @@ -116,6 +116,10 @@ class FavoritesRenderer( fun renderFavoritesForComponent(component: ComponentName): String { val qty = favoriteFunction(component) - return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty) + if (qty != 0) { + return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty) + } else { + return "" + } } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index d3cabe67790e1..0870a4d179c97 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -42,8 +42,7 @@ 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 onlyFavorites: Boolean = false + private val layoutInflater: LayoutInflater ) : RecyclerView.Adapter() { companion object { @@ -57,22 +56,21 @@ class ControlAdapter( } } - var modelList: List = emptyList() - private var favoritesModel: FavoriteModel? = null + private var model: ControlsModel? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return when (viewType) { TYPE_CONTROL -> { ControlHolder( - layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply { - layoutParams.apply { - width = ViewGroup.LayoutParams.MATCH_PARENT - } - elevation = 15f - }, - { id, favorite -> - favoritesModel?.changeFavoriteStatus(id, favorite) - }) + layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply { + layoutParams.apply { + width = ViewGroup.LayoutParams.MATCH_PARENT + } + elevation = 15f + } + ) { id, favorite -> + model?.changeFavoriteStatus(id, favorite) + } } TYPE_ZONE -> { ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false)) @@ -81,27 +79,26 @@ class ControlAdapter( } } - fun changeFavoritesModel(favoritesModel: FavoriteModel) { - this.favoritesModel = favoritesModel - if (onlyFavorites) { - modelList = favoritesModel.favorites - } else { - modelList = favoritesModel.all - } + fun changeModel(model: ControlsModel) { + this.model = model notifyDataSetChanged() } - override fun getItemCount() = modelList.size + override fun getItemCount() = model?.elements?.size ?: 0 override fun onBindViewHolder(holder: Holder, index: Int) { - holder.bindData(modelList[index]) + model?.let { + holder.bindData(it.elements[index]) + } } override fun getItemViewType(position: Int): Int { - return when (modelList[position]) { - is ZoneNameWrapper -> TYPE_ZONE - is ControlWrapper -> TYPE_CONTROL - } + model?.let { + return when (it.elements.get(position)) { + is ZoneNameWrapper -> TYPE_ZONE + is ControlWrapper -> TYPE_CONTROL + } + } ?: throw IllegalStateException("Getting item type for null model") } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index af4a977022ae9..2c014498fdc29 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -26,11 +26,9 @@ import android.view.ViewStub import android.widget.Button import android.widget.TextView import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.settings.CurrentUserTracker @@ -51,33 +49,10 @@ class ControlsFavoritingActivity @Inject constructor( private lateinit var recyclerViewAll: RecyclerView private lateinit var adapterAll: ControlAdapter - private lateinit var recyclerViewFavorites: RecyclerView - private lateinit var adapterFavorites: ControlAdapter - private lateinit var errorText: TextView + private lateinit var statusText: TextView + private var model: ControlsModel? = null private var component: ComponentName? = null - private var currentModel: FavoriteModel? = null - private var itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback( - /* dragDirs */ ItemTouchHelper.UP - or ItemTouchHelper.DOWN - or ItemTouchHelper.LEFT - or ItemTouchHelper.RIGHT, - /* swipeDirs */0 - ) { - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return currentModel?.onMoveItem( - viewHolder.layoutPosition, target.layoutPosition) != null - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} - - override fun isItemViewSwipeEnabled() = false - } - private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { private val startingUser = controller.currentUserId @@ -89,6 +64,10 @@ class ControlsFavoritingActivity @Inject constructor( } } + override fun onBackPressed() { + finish() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.controls_management) @@ -99,21 +78,27 @@ class ControlsFavoritingActivity @Inject constructor( val app = intent.getCharSequenceExtra(EXTRA_APP) component = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) - errorText = requireViewById(R.id.error_message) + statusText = requireViewById(R.id.status_message) - setUpRecyclerViews() + setUpRecyclerView() requireViewById(R.id.title).text = app?.let { it } ?: resources.getText(R.string.controls_favorite_default_title) requireViewById(R.id.subtitle).text = resources.getText(R.string.controls_favorite_subtitle) + requireViewById