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 17 package com.android.systemui.animation 18 19 import android.view.View 20 21 /** A view that can expand/launch into an app or a dialog. */ 22 interface LaunchableView { 23 /** 24 * Set whether this view should block/postpone all calls to [View.setVisibility]. This ensures 25 * that this view: 26 * - remains invisible during the launch animation given that it is ghosted and already drawn 27 * somewhere else. 28 * - remains invisible as long as a dialog expanded from it is shown. 29 * - restores its expected visibility once the dialog expanded from it is dismissed. 30 * 31 * When `setShouldBlockVisibilityChanges(false)` is called, then visibility of the View should 32 * be restored to its expected value, i.e. it should have the visibility of the last call to 33 * `View.setVisibility()` that was made after `setShouldBlockVisibilityChanges(true)`, if any, 34 * or the original view visibility otherwise. 35 * 36 * Note that calls to [View.setTransitionVisibility] shouldn't be blocked. 37 * 38 * @param block whether we should block/postpone all calls to `setVisibility`. 39 */ 40 fun setShouldBlockVisibilityChanges(block: Boolean) 41 } 42 43 /** A delegate that can be used by views to make the implementation of [LaunchableView] easier. */ 44 class LaunchableViewDelegate( 45 private val view: View, 46 47 /** 48 * The lambda that should set the actual visibility of [view], usually by calling 49 * super.setVisibility(visibility). 50 */ 51 private val superSetVisibility: (Int) -> Unit, 52 ) : LaunchableView { 53 private var blockVisibilityChanges = false 54 private var lastVisibility = view.visibility 55 56 /** Call this when [LaunchableView.setShouldBlockVisibilityChanges] is called. */ 57 override fun setShouldBlockVisibilityChanges(block: Boolean) { 58 if (block == blockVisibilityChanges) { 59 return 60 } 61 62 blockVisibilityChanges = block 63 if (block) { 64 // Save the current visibility for later. 65 lastVisibility = view.visibility 66 } else { 67 // Restore the visibility. To avoid accessibility issues, we change the visibility twice 68 // which makes sure that we trigger a visibility flag change (see b/204944038#comment17 69 // for more info). 70 if (lastVisibility == View.VISIBLE) { 71 superSetVisibility(View.INVISIBLE) 72 superSetVisibility(View.VISIBLE) 73 } else { 74 superSetVisibility(View.VISIBLE) 75 superSetVisibility(lastVisibility) 76 } 77 } 78 } 79 80 /** Call this when [View.setVisibility] is called. */ 81 fun setVisibility(visibility: Int) { 82 if (blockVisibilityChanges) { 83 lastVisibility = visibility 84 return 85 } 86 87 superSetVisibility(visibility) 88 } 89 } 90