Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2020 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.systemui.controls.management |
| 18 | |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 19 | import android.content.ComponentName |
| 20 | import android.content.Intent |
| 21 | import android.os.Bundle |
| 22 | import android.view.View |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 23 | import android.view.ViewGroup |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 24 | import android.view.ViewStub |
| 25 | import android.widget.Button |
| 26 | import android.widget.TextView |
| 27 | import androidx.recyclerview.widget.GridLayoutManager |
| 28 | import androidx.recyclerview.widget.ItemTouchHelper |
| 29 | import androidx.recyclerview.widget.RecyclerView |
| 30 | import com.android.systemui.R |
| 31 | import com.android.systemui.broadcast.BroadcastDispatcher |
| 32 | import com.android.systemui.controls.controller.ControlsControllerImpl |
| 33 | import com.android.systemui.controls.controller.StructureInfo |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 34 | import com.android.systemui.globalactions.GlobalActionsComponent |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 35 | import com.android.systemui.settings.CurrentUserTracker |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 36 | import com.android.systemui.util.LifecycleActivity |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 37 | import javax.inject.Inject |
| 38 | |
| 39 | /** |
| 40 | * Activity for rearranging and removing controls for a given structure |
| 41 | */ |
| 42 | class ControlsEditingActivity @Inject constructor( |
| 43 | private val controller: ControlsControllerImpl, |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 44 | broadcastDispatcher: BroadcastDispatcher, |
| 45 | private val globalActionsComponent: GlobalActionsComponent |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 46 | ) : LifecycleActivity() { |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 47 | |
| 48 | companion object { |
| 49 | private const val TAG = "ControlsEditingActivity" |
| 50 | private const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE |
| 51 | private val SUBTITLE_ID = R.string.controls_favorite_rearrange |
| 52 | private val EMPTY_TEXT_ID = R.string.controls_favorite_removed |
| 53 | } |
| 54 | |
| 55 | private lateinit var component: ComponentName |
| 56 | private lateinit var structure: CharSequence |
| 57 | private lateinit var model: FavoritesModel |
| 58 | private lateinit var subtitle: TextView |
| 59 | private lateinit var saveButton: View |
| 60 | |
| 61 | private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { |
| 62 | private val startingUser = controller.currentUserId |
| 63 | |
| 64 | override fun onUserSwitched(newUserId: Int) { |
| 65 | if (newUserId != startingUser) { |
| 66 | stopTracking() |
| 67 | finish() |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 72 | override fun onCreate(savedInstanceState: Bundle?) { |
| 73 | super.onCreate(savedInstanceState) |
| 74 | |
| 75 | intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)?.let { |
| 76 | component = it |
| 77 | } ?: run(this::finish) |
| 78 | |
| 79 | intent.getCharSequenceExtra(EXTRA_STRUCTURE)?.let { |
| 80 | structure = it |
| 81 | } ?: run(this::finish) |
| 82 | |
| 83 | bindViews() |
| 84 | |
| 85 | bindButtons() |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 86 | } |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 87 | |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 88 | override fun onStart() { |
| 89 | super.onStart() |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 90 | setUpList() |
| 91 | |
| 92 | currentUserTracker.startTracking() |
| 93 | } |
| 94 | |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 95 | override fun onStop() { |
| 96 | super.onStop() |
| 97 | currentUserTracker.stopTracking() |
| 98 | } |
| 99 | |
Fabian Kozynski | 5f561f0 | 2020-04-27 13:38:55 -0400 | [diff] [blame] | 100 | override fun onBackPressed() { |
| 101 | globalActionsComponent.handleShowGlobalActionsMenu() |
| 102 | animateExitAndFinish() |
| 103 | } |
| 104 | |
| 105 | private fun animateExitAndFinish() { |
| 106 | val rootView = requireViewById<ViewGroup>(R.id.controls_management_root) |
| 107 | ControlsAnimations.exitAnimation( |
| 108 | rootView, |
| 109 | object : Runnable { |
| 110 | override fun run() { |
| 111 | finish() |
| 112 | } |
| 113 | } |
| 114 | ).start() |
| 115 | } |
| 116 | |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 117 | private fun bindViews() { |
| 118 | setContentView(R.layout.controls_management) |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 119 | |
| 120 | getLifecycle().addObserver( |
| 121 | ControlsAnimations.observerForAnimations( |
| 122 | requireViewById<ViewGroup>(R.id.controls_management_root), |
| 123 | window, |
| 124 | intent |
| 125 | ) |
| 126 | ) |
| 127 | |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 128 | requireViewById<ViewStub>(R.id.stub).apply { |
| 129 | layoutResource = R.layout.controls_management_editing |
| 130 | inflate() |
| 131 | } |
| 132 | requireViewById<TextView>(R.id.title).text = structure |
| 133 | subtitle = requireViewById<TextView>(R.id.subtitle).apply { |
| 134 | setText(SUBTITLE_ID) |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | private fun bindButtons() { |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 139 | val rootView = requireViewById<ViewGroup>(R.id.controls_management_root) |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 140 | saveButton = requireViewById<Button>(R.id.done).apply { |
| 141 | isEnabled = false |
| 142 | setText(R.string.save) |
| 143 | setOnClickListener { |
| 144 | saveFavorites() |
Fabian Kozynski | 5f561f0 | 2020-04-27 13:38:55 -0400 | [diff] [blame] | 145 | animateExitAndFinish() |
Matt Pietal | d8a6ca6 | 2020-04-21 15:00:15 -0400 | [diff] [blame] | 146 | globalActionsComponent.handleShowGlobalActionsMenu() |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | private fun saveFavorites() { |
| 152 | controller.replaceFavoritesForStructure( |
| 153 | StructureInfo(component, structure, model.favorites)) |
| 154 | } |
| 155 | |
| 156 | private val favoritesModelCallback = object : FavoritesModel.FavoritesModelCallback { |
| 157 | override fun onNoneChanged(showNoFavorites: Boolean) { |
| 158 | if (showNoFavorites) { |
| 159 | subtitle.setText(EMPTY_TEXT_ID) |
| 160 | } else { |
| 161 | subtitle.setText(SUBTITLE_ID) |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | override fun onFirstChange() { |
| 166 | saveButton.isEnabled = true |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | private fun setUpList() { |
| 171 | val controls = controller.getFavoritesForStructure(component, structure) |
| 172 | model = FavoritesModel(component, controls, favoritesModelCallback) |
| 173 | val elevation = resources.getFloat(R.dimen.control_card_elevation) |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 174 | val recyclerView = requireViewById<RecyclerView>(R.id.list) |
| 175 | recyclerView.alpha = 0.0f |
| 176 | val adapter = ControlAdapter(elevation).apply { |
| 177 | registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { |
| 178 | var hasAnimated = false |
| 179 | override fun onChanged() { |
| 180 | if (!hasAnimated) { |
| 181 | hasAnimated = true |
| 182 | ControlsAnimations.enterAnimation(recyclerView).start() |
| 183 | } |
| 184 | } |
| 185 | }) |
| 186 | } |
| 187 | |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 188 | val margin = resources |
| 189 | .getDimensionPixelSize(R.dimen.controls_card_margin) |
| 190 | val itemDecorator = MarginItemDecorator(margin, margin) |
| 191 | |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 192 | recyclerView.apply { |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 193 | this.adapter = adapter |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 194 | layoutManager = GridLayoutManager(recyclerView.context, 2).apply { |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 195 | spanSizeLookup = adapter.spanSizeLookup |
| 196 | } |
| 197 | addItemDecoration(itemDecorator) |
| 198 | } |
| 199 | adapter.changeModel(model) |
| 200 | model.attachAdapter(adapter) |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 201 | ItemTouchHelper(model.itemTouchHelperCallback).attachToRecyclerView(recyclerView) |
Fabian Kozynski | 8765d35 | 2020-04-06 21:16:02 -0400 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | override fun onDestroy() { |
| 205 | currentUserTracker.stopTracking() |
| 206 | super.onDestroy() |
| 207 | } |
Matt Pietal | f4b870b | 2020-04-17 17:11:36 -0400 | [diff] [blame] | 208 | } |