1 /* 2 * Copyright (C) 2022 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.wm.shell.back; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 21 22 import static com.android.window.flags.Flags.enableMultidisplayTrackpadBackGesture; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.graphics.Color; 27 import android.graphics.Rect; 28 import android.view.SurfaceControl; 29 30 import com.android.internal.graphics.ColorUtils; 31 import com.android.internal.view.AppearanceRegion; 32 import com.android.wm.shell.RootTaskDisplayAreaOrganizer; 33 34 /** 35 * Controls background surface for the back animations 36 */ 37 public class BackAnimationBackground { 38 private static final int BACKGROUND_LAYER = -1; 39 40 private static final int NO_APPEARANCE = 0; 41 42 private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; 43 private SurfaceControl mBackgroundSurface; 44 45 private StatusBarCustomizer mCustomizer; 46 private boolean mIsRequestingStatusBarAppearance; 47 private boolean mBackgroundIsDark; 48 private Rect mStartBounds; 49 private int mStatusbarHeight; 50 BackAnimationBackground(RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer)51 public BackAnimationBackground(RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { 52 mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; 53 } 54 55 /** 56 * Ensures the back animation background color layer is present. 57 * 58 * @param startRect The start bounds of the closing target. 59 * @param color The background color. 60 * @param transaction The animation transaction. 61 * @param statusbarHeight The height of the statusbar (in px). 62 */ ensureBackground(Rect startRect, int color, @NonNull SurfaceControl.Transaction transaction, int statusbarHeight, int displayId)63 public void ensureBackground(Rect startRect, int color, 64 @NonNull SurfaceControl.Transaction transaction, int statusbarHeight, int displayId) { 65 ensureBackground(startRect, color, transaction, statusbarHeight, 66 null /* cropBounds */, 0 /* cornerRadius */, displayId); 67 } 68 69 /** 70 * Ensures the back animation background color layer is present. 71 * 72 * @param startRect The start bounds of the closing target. 73 * @param color The background color. 74 * @param transaction The animation transaction. 75 * @param statusbarHeight The height of the statusbar (in px). 76 * @param cropBounds The crop bounds of the surface, set to non-empty to show wallpaper. 77 * @param cornerRadius The radius of corner, only work when cropBounds is not empty. 78 */ ensureBackground(Rect startRect, int color, @NonNull SurfaceControl.Transaction transaction, int statusbarHeight, @Nullable Rect cropBounds, float cornerRadius, int displayId)79 public void ensureBackground(Rect startRect, int color, 80 @NonNull SurfaceControl.Transaction transaction, int statusbarHeight, 81 @Nullable Rect cropBounds, float cornerRadius, int displayId) { 82 if (mBackgroundSurface != null) { 83 return; 84 } 85 86 mBackgroundIsDark = ColorUtils.calculateLuminance(color) < 0.5f; 87 88 final float[] colorComponents = new float[] { Color.red(color) / 255.f, 89 Color.green(color) / 255.f, Color.blue(color) / 255.f }; 90 91 final SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder() 92 .setName("back-animation-background") 93 .setCallsite("BackAnimationBackground") 94 .setColorLayer(); 95 96 if (enableMultidisplayTrackpadBackGesture()) { 97 mRootTaskDisplayAreaOrganizer.attachToDisplayArea(displayId, colorLayerBuilder); 98 } else { 99 mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder); 100 } 101 mBackgroundSurface = colorLayerBuilder.build(); 102 transaction.setColor(mBackgroundSurface, colorComponents) 103 .setLayer(mBackgroundSurface, BACKGROUND_LAYER) 104 .show(mBackgroundSurface); 105 if (cropBounds != null && !cropBounds.isEmpty()) { 106 transaction.setCrop(mBackgroundSurface, cropBounds) 107 .setCornerRadius(mBackgroundSurface, cornerRadius); 108 } 109 mStartBounds = startRect; 110 mIsRequestingStatusBarAppearance = false; 111 mStatusbarHeight = statusbarHeight; 112 } 113 114 /** 115 * Remove the back animation background. 116 * 117 * @param transaction The animation transaction. 118 */ 119 public void removeBackground(@NonNull SurfaceControl.Transaction transaction) { 120 if (mBackgroundSurface == null) { 121 return; 122 } 123 124 if (mBackgroundSurface.isValid()) { 125 transaction.remove(mBackgroundSurface); 126 } 127 mBackgroundSurface = null; 128 mIsRequestingStatusBarAppearance = false; 129 } 130 131 /** 132 * Attach a {@link StatusBarCustomizer} instance to allow status bar animate with back progress. 133 * 134 * @param customizer The {@link StatusBarCustomizer} to be used. 135 */ 136 void setStatusBarCustomizer(StatusBarCustomizer customizer) { 137 mCustomizer = customizer; 138 } 139 140 /** 141 * Update back animation background with for the progress. 142 * 143 * @param top The top coordinate of the closing target 144 */ 145 public void customizeStatusBarAppearance(int top) { 146 if (mCustomizer == null || mStartBounds.isEmpty()) { 147 return; 148 } 149 150 final boolean shouldCustomizeSystemBar = top > mStatusbarHeight / 2; 151 if (shouldCustomizeSystemBar == mIsRequestingStatusBarAppearance) { 152 return; 153 } 154 155 mIsRequestingStatusBarAppearance = shouldCustomizeSystemBar; 156 if (mIsRequestingStatusBarAppearance) { 157 final AppearanceRegion region = new AppearanceRegion(!mBackgroundIsDark 158 ? APPEARANCE_LIGHT_STATUS_BARS : NO_APPEARANCE, 159 mStartBounds); 160 mCustomizer.customizeStatusBarAppearance(region); 161 } else { 162 resetStatusBarCustomization(); 163 } 164 } 165 166 /** 167 * Resets the statusbar customization 168 */ resetStatusBarCustomization()169 public void resetStatusBarCustomization() { 170 mCustomizer.customizeStatusBarAppearance(null); 171 } 172 } 173