blob: b98b92219c33686186e83a3258c3678ac9905039 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.animation
import android.view.View
/** A view that can expand/launch into an app or a dialog. */
interface LaunchableView {
/**
* Set whether this view should block/postpone all calls to [View.setVisibility]. This ensures
* that this view:
* - remains invisible during the launch animation given that it is ghosted and already drawn
* somewhere else.
* - remains invisible as long as a dialog expanded from it is shown.
* - restores its expected visibility once the dialog expanded from it is dismissed.
*
* When `setShouldBlockVisibilityChanges(false)` is called, then visibility of the View should
* be restored to its expected value, i.e. it should have the visibility of the last call to
* `View.setVisibility()` that was made after `setShouldBlockVisibilityChanges(true)`, if any,
* or the original view visibility otherwise.
*
* Note that calls to [View.setTransitionVisibility] shouldn't be blocked.
*
* @param block whether we should block/postpone all calls to `setVisibility`.
*/
fun setShouldBlockVisibilityChanges(block: Boolean)
}
/** A delegate that can be used by views to make the implementation of [LaunchableView] easier. */
class LaunchableViewDelegate(
private val view: View,
/**
* The lambda that should set the actual visibility of [view], usually by calling
* super.setVisibility(visibility).
*/
private val superSetVisibility: (Int) -> Unit,
) : LaunchableView {
private var blockVisibilityChanges = false
private var lastVisibility = view.visibility
/** Call this when [LaunchableView.setShouldBlockVisibilityChanges] is called. */
override fun setShouldBlockVisibilityChanges(block: Boolean) {
if (block == blockVisibilityChanges) {
return
}
blockVisibilityChanges = block
if (block) {
// Save the current visibility for later.
lastVisibility = view.visibility
} else {
// Restore the visibility. To avoid accessibility issues, we change the visibility twice
// which makes sure that we trigger a visibility flag change (see b/204944038#comment17
// for more info).
if (lastVisibility == View.VISIBLE) {
superSetVisibility(View.INVISIBLE)
superSetVisibility(View.VISIBLE)
} else {
superSetVisibility(View.VISIBLE)
superSetVisibility(lastVisibility)
}
}
}
/** Call this when [View.setVisibility] is called. */
fun setVisibility(visibility: Int) {
if (blockVisibilityChanges) {
lastVisibility = visibility
return
}
superSetVisibility(visibility)
}
}