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.util.AttributeSet; 25 import android.view.KeyEvent; 26 import android.view.MotionEvent; 27 import android.view.View; 28 import android.view.ViewTreeObserver; 29 30 import androidx.annotation.NonNull; 31 import androidx.annotation.Nullable; 32 33 import com.android.launcher3.AbstractFloatingView; 34 import com.android.launcher3.testing.TestLogging; 35 import com.android.launcher3.testing.shared.TestProtocol; 36 import com.android.launcher3.views.BaseDragLayer; 37 38 /** 39 * Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder. 40 */ 41 public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> { 42 43 private final TaskbarBackgroundRenderer mBackgroundRenderer; 44 private final ViewTreeObserver.OnComputeInternalInsetsListener mTaskbarInsetsComputer = 45 this::onComputeTaskbarInsets; 46 47 // Initialized in init. 48 private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks; 49 50 private float mTaskbarBackgroundOffset; 51 TaskbarDragLayer(@onNull Context context)52 public TaskbarDragLayer(@NonNull Context context) { 53 this(context, null); 54 } 55 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs)56 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs) { 57 this(context, attrs, 0); 58 } 59 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)60 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs, 61 int defStyleAttr) { 62 this(context, attrs, defStyleAttr, 0); 63 } 64 TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)65 public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs, 66 int defStyleAttr, int defStyleRes) { 67 super(context, attrs, 1 /* alphaChannelCount */); 68 mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity); 69 mBackgroundRenderer.getPaint().setAlpha(0); 70 } 71 init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks)72 public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) { 73 mControllerCallbacks = callbacks; 74 75 recreateControllers(); 76 } 77 78 @Override recreateControllers()79 public void recreateControllers() { 80 mControllers = mControllerCallbacks.getTouchControllers(); 81 } 82 onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo)83 private void onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo) { 84 if (mControllerCallbacks != null) { 85 mControllerCallbacks.updateInsetsTouchability(insetsInfo); 86 } 87 } 88 onDestroy(boolean forceDestroy)89 protected void onDestroy(boolean forceDestroy) { 90 if (forceDestroy) { 91 getViewTreeObserver().removeOnComputeInternalInsetsListener(mTaskbarInsetsComputer); 92 } 93 } 94 onDestroy()95 protected void onDestroy() { 96 onDestroy(!TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW); 97 } 98 99 @Override onAttachedToWindow()100 protected void onAttachedToWindow() { 101 super.onAttachedToWindow(); 102 getViewTreeObserver().addOnComputeInternalInsetsListener(mTaskbarInsetsComputer); 103 } 104 105 @Override onDetachedFromWindow()106 protected void onDetachedFromWindow() { 107 super.onDetachedFromWindow(); 108 109 onDestroy(true); 110 } 111 112 @Override canFindActiveController()113 protected boolean canFindActiveController() { 114 // Unlike super class, we want to be able to find controllers when touches occur in the 115 // gesture area. For example, this allows Folder to close itself when touching the Taskbar. 116 return true; 117 } 118 119 @Override onViewRemoved(View child)120 public void onViewRemoved(View child) { 121 super.onViewRemoved(child); 122 if (mControllerCallbacks != null) { 123 mControllerCallbacks.onDragLayerViewRemoved(); 124 } 125 } 126 127 @Override dispatchDraw(Canvas canvas)128 protected void dispatchDraw(Canvas canvas) { 129 float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight() 130 * (1f - mTaskbarBackgroundOffset); 131 mBackgroundRenderer.setBackgroundHeight(backgroundHeight); 132 mBackgroundRenderer.draw(canvas); 133 super.dispatchDraw(canvas); 134 } 135 136 /** 137 * Sets the alpha of the background color behind all the Taskbar contents. 138 * @param alpha 0 is fully transparent, 1 is fully opaque. 139 */ setTaskbarBackgroundAlpha(float alpha)140 protected void setTaskbarBackgroundAlpha(float alpha) { 141 mBackgroundRenderer.getPaint().setAlpha((int) (alpha * 255)); 142 invalidate(); 143 } 144 145 /** 146 * Sets the translation of the background color behind all the Taskbar contents. 147 * @param offset 0 is fully onscreen, 1 is fully offscreen. 148 */ setTaskbarBackgroundOffset(float offset)149 protected void setTaskbarBackgroundOffset(float offset) { 150 mTaskbarBackgroundOffset = offset; 151 invalidate(); 152 } 153 154 /** 155 * Sets the roundness of the round corner above Taskbar. 156 * @param cornerRoundness 0 has no round corner, 1 has complete round corner. 157 */ setCornerRoundness(float cornerRoundness)158 protected void setCornerRoundness(float cornerRoundness) { 159 mBackgroundRenderer.setCornerRoundness(cornerRoundness); 160 invalidate(); 161 } 162 163 /* 164 * Sets the translation of the background during the swipe up gesture. 165 */ setBackgroundTranslationYForSwipe(float translationY)166 protected void setBackgroundTranslationYForSwipe(float translationY) { 167 mBackgroundRenderer.setTranslationYForSwipe(translationY); 168 invalidate(); 169 } 170 171 /* 172 * Sets the translation of the background during the spring on stash animation. 173 */ setBackgroundTranslationYForStash(float translationY)174 protected void setBackgroundTranslationYForStash(float translationY) { 175 mBackgroundRenderer.setTranslationYForStash(translationY); 176 invalidate(); 177 } 178 179 /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */ getLastDrawnTransientRect()180 protected RectF getLastDrawnTransientRect() { 181 return mBackgroundRenderer.getLastDrawnTransientRect(); 182 } 183 184 @Override dispatchTouchEvent(MotionEvent ev)185 public boolean dispatchTouchEvent(MotionEvent ev) { 186 TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); 187 return super.dispatchTouchEvent(ev); 188 } 189 190 /** Called while Taskbar window is focusable, e.g. when pressing back while a folder is open */ 191 @Override dispatchKeyEvent(KeyEvent event)192 public boolean dispatchKeyEvent(KeyEvent event) { 193 if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) { 194 AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); 195 if (topView != null && topView.canHandleBack()) { 196 topView.onBackInvoked(); 197 // Handled by the floating view. 198 return true; 199 } 200 } 201 return super.dispatchKeyEvent(event); 202 } 203 } 204