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