1 /* <lambda>null2 * Copyright (C) 2024 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.quickstep 18 19 import android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS 20 import android.app.PendingIntent 21 import android.app.RemoteAction 22 import android.content.Context 23 import android.graphics.drawable.Icon 24 import android.provider.Settings 25 import android.provider.Settings.Secure.USER_SETUP_COMPLETE 26 import android.view.accessibility.AccessibilityManager 27 import com.android.launcher3.R 28 import com.android.launcher3.util.SettingsCache 29 import com.android.launcher3.util.SettingsCache.OnChangeListener 30 import java.util.concurrent.Executor 31 32 private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPLETE) 33 34 /** 35 * Registers a [RemoteAction] for toggling All Apps if needed. 36 * 37 * We need this action when either [isHomeAndOverviewSame] or [isTaskbarPresent] is `true`. When 38 * home and overview are the same, we can control Launcher's or Taskbar's All Apps tray. If they are 39 * not the same, but Taskbar is present, we can only control Taskbar's tray. 40 */ 41 class AllAppsActionManager( 42 private val context: Context, 43 private val bgExecutor: Executor, 44 private val createAllAppsPendingIntent: () -> PendingIntent, 45 ) { 46 47 private val onSettingsChangeListener = OnChangeListener { v -> isUserSetupComplete = v } 48 49 init { 50 SettingsCache.INSTANCE[context].register(USER_SETUP_COMPLETE_URI, onSettingsChangeListener) 51 } 52 53 /** `true` if home and overview are the same Activity. */ 54 var isHomeAndOverviewSame = false 55 set(value) { 56 field = value 57 updateSystemAction() 58 } 59 60 /** `true` if Taskbar is enabled. */ 61 var isTaskbarPresent = false 62 set(value) { 63 field = value 64 updateSystemAction() 65 } 66 67 /** `true` if the setup UI is visible. */ 68 var isSetupUiVisible = false 69 set(value) { 70 field = value 71 updateSystemAction() 72 } 73 74 private var isUserSetupComplete = 75 SettingsCache.INSTANCE[context].getValue(USER_SETUP_COMPLETE_URI, 0) 76 set(value) { 77 field = value 78 updateSystemAction() 79 } 80 81 /** `true` if the action should be registered. */ 82 var isActionRegistered = false 83 private set 84 85 private fun updateSystemAction() { 86 val isInSetupFlow = isSetupUiVisible || !isUserSetupComplete 87 val shouldRegisterAction = (isHomeAndOverviewSame || isTaskbarPresent) && !isInSetupFlow 88 if (isActionRegistered == shouldRegisterAction) return 89 isActionRegistered = shouldRegisterAction 90 91 bgExecutor.execute { 92 val accessibilityManager = 93 context.getSystemService(AccessibilityManager::class.java) ?: return@execute 94 if (shouldRegisterAction) { 95 accessibilityManager.registerSystemAction( 96 RemoteAction( 97 Icon.createWithResource(context, R.drawable.ic_apps), 98 context.getString(R.string.all_apps_label), 99 context.getString(R.string.all_apps_label), 100 createAllAppsPendingIntent(), 101 ), 102 GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, 103 ) 104 } else { 105 accessibilityManager.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS) 106 } 107 } 108 } 109 110 fun onDestroy() { 111 isActionRegistered = false 112 context 113 .getSystemService(AccessibilityManager::class.java) 114 ?.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS) 115 SettingsCache.INSTANCE[context].unregister( 116 USER_SETUP_COMPLETE_URI, 117 onSettingsChangeListener, 118 ) 119 } 120 } 121