1 /* 2 * Copyright (C) 2019 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 19 import android.app.ActivityOptions 20 import android.content.ComponentName 21 import android.content.Intent 22 import android.os.Bundle 23 import android.view.LayoutInflater 24 import android.view.View 25 import android.view.ViewGroup 26 import android.view.ViewStub 27 import android.widget.Button 28 import android.widget.TextView 29 import androidx.recyclerview.widget.LinearLayoutManager 30 import androidx.recyclerview.widget.RecyclerView 31 import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver 32 import com.android.systemui.R 33 import com.android.systemui.broadcast.BroadcastDispatcher 34 import com.android.systemui.controls.controller.ControlsController 35 import com.android.systemui.controls.ui.ControlsActivity 36 import com.android.systemui.controls.ui.ControlsUiController 37 import com.android.systemui.dagger.qualifiers.Background 38 import com.android.systemui.dagger.qualifiers.Main 39 import com.android.systemui.settings.CurrentUserTracker 40 import com.android.systemui.util.LifecycleActivity 41 import java.util.concurrent.Executor 42 import javax.inject.Inject 43 44 /** 45 * Activity to select an application to favorite the [Control] provided by them. 46 */ 47 class ControlsProviderSelectorActivity @Inject constructor( 48 @Main private val executor: Executor, 49 @Background private val backExecutor: Executor, 50 private val listingController: ControlsListingController, 51 private val controlsController: ControlsController, 52 private val broadcastDispatcher: BroadcastDispatcher, 53 private val uiController: ControlsUiController 54 ) : LifecycleActivity() { 55 56 companion object { 57 private const val TAG = "ControlsProviderSelectorActivity" 58 const val BACK_SHOULD_EXIT = "back_should_exit" 59 } 60 private var backShouldExit = false 61 private lateinit var recyclerView: RecyclerView 62 private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { 63 private val startingUser = listingController.currentUserId 64 65 override fun onUserSwitched(newUserId: Int) { 66 if (newUserId != startingUser) { 67 stopTracking() 68 finish() 69 } 70 } 71 } 72 73 override fun onCreate(savedInstanceState: Bundle?) { 74 super.onCreate(savedInstanceState) 75 76 setContentView(R.layout.controls_management) 77 78 getLifecycle().addObserver( 79 ControlsAnimations.observerForAnimations( 80 requireViewById<ViewGroup>(R.id.controls_management_root), 81 window, 82 intent 83 ) 84 ) 85 86 requireViewById<ViewStub>(R.id.stub).apply { 87 layoutResource = R.layout.controls_management_apps 88 inflate() 89 } 90 91 recyclerView = requireViewById(R.id.list) 92 recyclerView.layoutManager = LinearLayoutManager(applicationContext) 93 94 requireViewById<TextView>(R.id.title).apply { 95 text = resources.getText(R.string.controls_providers_title) 96 } 97 98 requireViewById<Button>(R.id.other_apps).apply { 99 visibility = View.VISIBLE 100 setText(com.android.internal.R.string.cancel) 101 setOnClickListener { 102 onBackPressed() 103 } 104 } 105 requireViewById<View>(R.id.done).visibility = View.GONE 106 107 backShouldExit = intent.getBooleanExtra(BACK_SHOULD_EXIT, false) 108 } 109 110 override fun onBackPressed() { 111 if (!backShouldExit) { 112 val i = Intent().apply { 113 component = ComponentName(applicationContext, ControlsActivity::class.java) 114 } 115 startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) 116 } 117 animateExitAndFinish() 118 } 119 120 override fun onStart() { 121 super.onStart() 122 currentUserTracker.startTracking() 123 124 recyclerView.alpha = 0.0f 125 recyclerView.adapter = AppAdapter( 126 backExecutor, 127 executor, 128 lifecycle, 129 listingController, 130 LayoutInflater.from(this), 131 ::launchFavoritingActivity, 132 FavoritesRenderer(resources, controlsController::countFavoritesForComponent), 133 resources).apply { 134 registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { 135 var hasAnimated = false 136 override fun onChanged() { 137 if (!hasAnimated) { 138 hasAnimated = true 139 ControlsAnimations.enterAnimation(recyclerView).start() 140 } 141 } 142 }) 143 } 144 } 145 146 override fun onStop() { 147 super.onStop() 148 currentUserTracker.stopTracking() 149 } 150 151 /** 152 * Launch the [ControlsFavoritingActivity] for the specified component. 153 * @param component a component name for a [ControlsProviderService] 154 */ 155 fun launchFavoritingActivity(component: ComponentName?) { 156 executor.execute { 157 component?.let { 158 val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java) 159 .apply { 160 putExtra(ControlsFavoritingActivity.EXTRA_APP, 161 listingController.getAppLabel(it)) 162 putExtra(Intent.EXTRA_COMPONENT_NAME, it) 163 putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true) 164 } 165 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) 166 animateExitAndFinish() 167 } 168 } 169 } 170 171 override fun onDestroy() { 172 currentUserTracker.stopTracking() 173 super.onDestroy() 174 } 175 176 private fun animateExitAndFinish() { 177 val rootView = requireViewById<ViewGroup>(R.id.controls_management_root) 178 ControlsAnimations.exitAnimation( 179 rootView, 180 object : Runnable { 181 override fun run() { 182 finish() 183 } 184 } 185 ).start() 186 } 187 } 188