1 /* 2 * Copyright (C) 2023 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.car.systembar; 18 19 import android.app.ActivityManager; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.res.TypedArray; 23 import android.hardware.input.InputManager; 24 import android.view.KeyEvent; 25 import android.view.View; 26 27 import androidx.annotation.VisibleForTesting; 28 29 import com.android.systemui.R; 30 import com.android.systemui.shared.system.TaskStackChangeListener; 31 import com.android.systemui.shared.system.TaskStackChangeListeners; 32 import com.android.systemui.statusbar.AlphaOptimizedImageView; 33 34 import java.util.function.Consumer; 35 36 /** 37 * Used to add Recents state functionality to a {@link CarSystemBarButton} 38 * Long click functionality is updated to send KeyEvent instead of regular intents when Recents is 39 * inactive. 40 * click functionality is updated to send KeyEvent when Recents is active. 41 * TaskStackChangeListener helps to toggle the local long clicked state which further helps 42 * determine the appropriate icon and alpha to show. 43 */ 44 public class RecentsButtonStateProvider { 45 private final InputManager mInputManager; 46 private final ComponentName mRecentsComponentName; 47 private final CarSystemBarButton mCarSystemBarButton; 48 private final boolean mIsRecentsEntryPointEnabled; 49 private TaskStackChangeListener mTaskStackChangeListener; 50 private boolean mIsRecentsActive; 51 RecentsButtonStateProvider(Context context, CarSystemBarButton carSystemBarButton)52 public RecentsButtonStateProvider(Context context, CarSystemBarButton carSystemBarButton) { 53 mCarSystemBarButton = carSystemBarButton; 54 mInputManager = context.getSystemService(InputManager.class); 55 mRecentsComponentName = ComponentName.unflattenFromString(context.getString( 56 com.android.internal.R.string.config_recentsComponentName)); 57 mIsRecentsEntryPointEnabled = context.getResources() 58 .getBoolean(R.bool.config_enableRecentsEntryPoint); 59 initialiseListener(); 60 } 61 initialiseListener()62 protected void initialiseListener() { 63 mTaskStackChangeListener = new TaskStackChangeListener() { 64 @Override 65 public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { 66 if (mRecentsComponentName == null) { 67 return; 68 } 69 ComponentName topComponent = 70 taskInfo.topActivity != null ? taskInfo.topActivity 71 : taskInfo.baseIntent.getComponent(); 72 if (topComponent != null && mRecentsComponentName.getClassName().equals( 73 topComponent.getClassName())) { 74 mIsRecentsActive = true; 75 return; 76 } 77 mIsRecentsActive = false; 78 } 79 }; 80 TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackChangeListener); 81 } 82 83 /** 84 * Adds OnLongClickListener to the {@link CarSystemBarButton} to toggle Recents. 85 * 86 * @param defaultSetUpIntents default function to be called for non Recents functionality. 87 * @see CarSystemBarButton#setUpIntents(TypedArray) 88 */ setUpIntents(TypedArray typedArray, Consumer<TypedArray> defaultSetUpIntents)89 public void setUpIntents(TypedArray typedArray, Consumer<TypedArray> defaultSetUpIntents) { 90 if (defaultSetUpIntents != null) { 91 defaultSetUpIntents.accept(typedArray); 92 } 93 mCarSystemBarButton.setOnLongClickListener(v -> { 94 if (mIsRecentsActive) { 95 return false; 96 } 97 return toggleRecents(); 98 }); 99 } 100 101 /** 102 * Adds OnClickListener to the {@link CarSystemBarButton} to toggle Recents. 103 * 104 * @param defaultGetButtonClickListener default function to be called for non Recents 105 * functionality. 106 * @see CarSystemBarButton#getButtonClickListener() 107 */ getButtonClickListener( View.OnClickListener defaultGetButtonClickListener)108 public View.OnClickListener getButtonClickListener( 109 View.OnClickListener defaultGetButtonClickListener) { 110 return v -> { 111 if (mIsRecentsActive) { 112 toggleRecents(); 113 return; 114 } 115 if (defaultGetButtonClickListener != null) { 116 defaultGetButtonClickListener.onClick(v); 117 } 118 }; 119 } 120 121 122 /** 123 * Updates the {@code icon}'s drawable to Recents icon when Recents is active. 124 * 125 * @param defaultUpdateImage default function to be called for non Recents functionality. 126 * @see CarSystemBarButton#updateImage(AlphaOptimizedImageView) 127 */ 128 public void updateImage(AlphaOptimizedImageView icon, 129 Consumer<AlphaOptimizedImageView> defaultUpdateImage) { 130 if (mIsRecentsActive) { 131 icon.setImageResource(R.drawable.car_ic_recents); 132 return; 133 } 134 if (defaultUpdateImage == null) { 135 return; 136 } 137 defaultUpdateImage.accept(icon); 138 } 139 140 /** 141 * Updates the {@code icon}'s alpha to selected alpha when Recents is active. 142 * 143 * @param defaultRefreshIconAlpha default function to be called for non Recents functionality. 144 * @see CarSystemBarButton#refreshIconAlpha(AlphaOptimizedImageView) 145 */ 146 public void refreshIconAlpha(AlphaOptimizedImageView icon, 147 Consumer<AlphaOptimizedImageView> defaultRefreshIconAlpha) { 148 if (mIsRecentsActive) { 149 icon.setAlpha(mCarSystemBarButton.getSelectedAlpha()); 150 return; 151 } 152 if (defaultRefreshIconAlpha == null) { 153 return; 154 } 155 defaultRefreshIconAlpha.accept(icon); 156 } 157 158 /** 159 * Sets if the Recents activity is in foreground. 160 */ 161 public void setIsRecentsActive(boolean isRecentsActive) { 162 mIsRecentsActive = isRecentsActive; 163 } 164 165 /** 166 * Gets if the Recents activity is in foreground. 167 */ 168 public boolean getIsRecentsActive() { 169 return mIsRecentsActive; 170 } 171 172 /** 173 * Opens/closes the Recents Activity. 174 */ 175 protected boolean toggleRecents() { 176 return mIsRecentsEntryPointEnabled && mInputManager.injectInputEvent( 177 new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_APP_SWITCH), 178 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 179 } 180 181 @VisibleForTesting 182 TaskStackChangeListener getTaskStackChangeListener() { 183 return mTaskStackChangeListener; 184 } 185 } 186