1 /* 2 * Copyright (C) 2021 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 package com.android.launcher3.taskbar; 17 18 import static android.view.KeyEvent.ACTION_UP; 19 import static android.view.KeyEvent.KEYCODE_BACK; 20 21 import android.content.Context; 22 import android.graphics.Canvas; 23 import android.graphics.RectF; 24 import android.media.permission.SafeCloseable; 25 import android.util.AttributeSet; 26 import android.util.FloatProperty; 27 import android.view.KeyEvent; 28 import android.view.MotionEvent; 29 import android.view.View; 30 import android.view.ViewTreeObserver; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 35 import com.android.app.viewcapture.SettingsAwareViewCapture; 36 import com.android.launcher3.AbstractFloatingView; 37 import com.android.launcher3.testing.TestLogging; 38 import com.android.launcher3.testing.shared.TestProtocol; 39 import com.android.launcher3.util.MultiPropertyFactory; 40 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; 41 import com.android.launcher3.views.BaseDragLayer; 42 43 /** 44 * Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder. 45 */ 46 public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> { 47 48 private static final int INDEX_ALL_OTHER_STATES = 0; 49 private static final int INDEX_STASH_ANIM = 1; 50 private static final int INDEX_COUNT = 2; 51 52 private static final FloatProperty<TaskbarDragLayer> BG_ALPHA = 53 new FloatProperty<>("taskbarBgAlpha") { 54 @Override 55 public void setValue(TaskbarDragLayer dragLayer, float alpha) { 56 dragLayer.mBackgroundRenderer.getPaint().setAlpha((int) (alpha * 255)); 57 dragLayer.invalidate(); 58 } 59 60 @Override 61 public Float get(TaskbarDragLayer dragLayer) { 62 return dragLayer.mBackgroundRenderer.getPaint().getAlpha() / 255f; 63 } 64 }; 65 66 67 private final TaskbarBackgroundRenderer mBackgroundRenderer; 68 private final ViewTreeObserver.OnComputeInternalInsetsListener mTaskbarInsetsComputer = 69 this::onComputeTaskbarInsets; 70 71 // Initialized in init. 72 private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks; 73 private SafeCloseable mViewCaptureCloseable; 74 75 private float mTaskbarBackgroundOffset; 76 77 private final MultiPropertyFactory<TaskbarDragLayer> mTaskbarBackgroundAlpha; 78 TaskbarDragLayer(@onNull Context context)79 public TaskbarDragLayer(@NonNull Context context) { 80 this(context, null); 81 } 82 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs)83 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs) { 84 this(context, attrs, 0); 85 } 86 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)87 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs, 88 int defStyleAttr) { 89 this(context, attrs, defStyleAttr, 0); 90 } 91 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)92 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs, 93 int defStyleAttr, int defStyleRes) { 94 super(context, attrs, 1 /* alphaChannelCount */); 95 mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity); 96 97 mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT, 98 (a, b) -> a * b, 1f); 99 mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0); 100 mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(1); 101 } 102 init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks)103 public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) { 104 mControllerCallbacks = callbacks; 105 mBackgroundRenderer.updateStashedHandleWidth(mActivity.getDeviceProfile(), getResources()); 106 recreateControllers(); 107 } 108 109 @Override recreateControllers()110 public void recreateControllers() { 111 mControllers = mControllerCallbacks.getTouchControllers(); 112 } 113 onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo)114 private void onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo) { 115 if (mControllerCallbacks != null) { 116 mControllerCallbacks.updateInsetsTouchability(insetsInfo); 117 } 118 } 119 onDestroy(boolean forceDestroy)120 protected void onDestroy(boolean forceDestroy) { 121 if (forceDestroy) { 122 getViewTreeObserver().removeOnComputeInternalInsetsListener(mTaskbarInsetsComputer); 123 } 124 } 125 onDestroy()126 protected void onDestroy() { 127 onDestroy(!TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW); 128 } 129 130 @Override onAttachedToWindow()131 protected void onAttachedToWindow() { 132 super.onAttachedToWindow(); 133 getViewTreeObserver().addOnComputeInternalInsetsListener(mTaskbarInsetsComputer); 134 mViewCaptureCloseable = SettingsAwareViewCapture.getInstance(getContext()) 135 .startCapture(getRootView(), ".Taskbar"); 136 } 137 138 @Override onDetachedFromWindow()139 protected void onDetachedFromWindow() { 140 super.onDetachedFromWindow(); 141 mViewCaptureCloseable.close(); 142 onDestroy(true); 143 } 144 145 @Override canFindActiveController()146 protected boolean canFindActiveController() { 147 // Unlike super class, we want to be able to find controllers when touches occur in the 148 // gesture area. For example, this allows Folder to close itself when touching the Taskbar. 149 return true; 150 } 151 152 @Override onViewRemoved(View child)153 public void onViewRemoved(View child) { 154 super.onViewRemoved(child); 155 if (mControllerCallbacks != null) { 156 mControllerCallbacks.onDragLayerViewRemoved(); 157 } 158 } 159 160 @Override dispatchDraw(Canvas canvas)161 protected void dispatchDraw(Canvas canvas) { 162 float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight() 163 * (1f - mTaskbarBackgroundOffset); 164 mBackgroundRenderer.setBackgroundHeight(backgroundHeight); 165 mBackgroundRenderer.draw(canvas); 166 super.dispatchDraw(canvas); 167 } 168 getBackgroundRendererAlpha()169 protected MultiProperty getBackgroundRendererAlpha() { 170 return mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES); 171 } 172 getBackgroundRendererAlphaForStash()173 protected MultiProperty getBackgroundRendererAlphaForStash() { 174 return mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM); 175 } 176 177 /** 178 * Sets the translation of the background color behind all the Taskbar contents. 179 * @param offset 0 is fully onscreen, 1 is fully offscreen. 180 */ setTaskbarBackgroundOffset(float offset)181 protected void setTaskbarBackgroundOffset(float offset) { 182 mTaskbarBackgroundOffset = offset; 183 invalidate(); 184 } 185 186 /** 187 * Sets the roundness of the round corner above Taskbar. 188 * @param cornerRoundness 0 has no round corner, 1 has complete round corner. 189 */ setCornerRoundness(float cornerRoundness)190 protected void setCornerRoundness(float cornerRoundness) { 191 mBackgroundRenderer.setCornerRoundness(cornerRoundness); 192 invalidate(); 193 } 194 195 /* 196 * Sets the translation of the background during the swipe up gesture. 197 */ setBackgroundTranslationYForSwipe(float translationY)198 protected void setBackgroundTranslationYForSwipe(float translationY) { 199 mBackgroundRenderer.setTranslationYForSwipe(translationY); 200 invalidate(); 201 } 202 203 /* 204 * Sets the translation of the background during the spring on stash animation. 205 */ setBackgroundTranslationYForStash(float translationY)206 protected void setBackgroundTranslationYForStash(float translationY) { 207 mBackgroundRenderer.setTranslationYForStash(translationY); 208 invalidate(); 209 } 210 211 /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */ getLastDrawnTransientRect()212 protected RectF getLastDrawnTransientRect() { 213 return mBackgroundRenderer.getLastDrawnTransientRect(); 214 } 215 216 @Override dispatchTouchEvent(MotionEvent ev)217 public boolean dispatchTouchEvent(MotionEvent ev) { 218 TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); 219 return super.dispatchTouchEvent(ev); 220 } 221 222 /** Called while Taskbar window is focusable, e.g. when pressing back while a folder is open */ 223 @Override dispatchKeyEvent(KeyEvent event)224 public boolean dispatchKeyEvent(KeyEvent event) { 225 if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) { 226 AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); 227 if (topView != null && topView.canHandleBack()) { 228 topView.onBackInvoked(); 229 // Handled by the floating view. 230 return true; 231 } 232 } 233 return super.dispatchKeyEvent(event); 234 } 235 236 /** 237 * Sets the width percentage to inset the transient taskbar's background from the left and from 238 * the right. 239 */ setBackgroundHorizontalInsets(float insetPercentage)240 public void setBackgroundHorizontalInsets(float insetPercentage) { 241 mBackgroundRenderer.setBackgroundHorizontalInsets(insetPercentage); 242 invalidate(); 243 } 244 } 245