1 /* <lambda>null2 * Copyright (C) 2014 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.systemui.statusbar.phone 17 18 import android.content.Context 19 import android.content.res.Configuration 20 import android.util.AttributeSet 21 import android.view.View 22 import android.view.ViewGroup 23 import android.view.ViewPropertyAnimator 24 import android.view.WindowInsets 25 import android.widget.FrameLayout 26 import androidx.annotation.StringRes 27 import com.android.keyguard.LockIconViewController 28 import com.android.systemui.R 29 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder 30 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind 31 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel 32 import com.android.systemui.plugins.FalsingManager 33 import com.android.systemui.statusbar.VibratorHelper 34 35 /** 36 * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI 37 * elements. A secondary concern is the interaction of the quick affordance elements with the 38 * indication area between them, though the indication area is primarily controlled elsewhere. 39 */ 40 class KeyguardBottomAreaView 41 @JvmOverloads 42 constructor( 43 context: Context, 44 attrs: AttributeSet? = null, 45 defStyleAttr: Int = 0, 46 defStyleRes: Int = 0, 47 ) : 48 FrameLayout( 49 context, 50 attrs, 51 defStyleAttr, 52 defStyleRes, 53 ) { 54 55 interface MessageDisplayer { 56 fun display(@StringRes stringResourceId: Int) 57 } 58 59 private var ambientIndicationArea: View? = null 60 private lateinit var binding: KeyguardBottomAreaViewBinder.Binding 61 private var lockIconViewController: LockIconViewController? = null 62 63 /** Initializes the view. */ 64 fun init( 65 viewModel: KeyguardBottomAreaViewModel, 66 falsingManager: FalsingManager? = null, 67 lockIconViewController: LockIconViewController? = null, 68 messageDisplayer: MessageDisplayer? = null, 69 vibratorHelper: VibratorHelper? = null, 70 ) { 71 binding = 72 bind( 73 this, 74 viewModel, 75 falsingManager, 76 vibratorHelper, 77 ) { 78 messageDisplayer?.display(it) 79 } 80 this.lockIconViewController = lockIconViewController 81 } 82 83 /** 84 * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another 85 * [KeyguardBottomAreaView] 86 */ 87 fun initFrom(oldBottomArea: KeyguardBottomAreaView) { 88 // if it exists, continue to use the original ambient indication container 89 // instead of the newly inflated one 90 ambientIndicationArea?.let { nonNullAmbientIndicationArea -> 91 // remove old ambient indication from its parent 92 val originalAmbientIndicationView = 93 oldBottomArea.findViewById<View>(R.id.ambient_indication_container) 94 (originalAmbientIndicationView.parent as ViewGroup).removeView( 95 originalAmbientIndicationView 96 ) 97 98 // remove current ambient indication from its parent (discard) 99 val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup 100 val ambientIndicationIndex = 101 ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea) 102 ambientIndicationParent.removeView(nonNullAmbientIndicationArea) 103 104 // add the old ambient indication to this view 105 ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex) 106 ambientIndicationArea = originalAmbientIndicationView 107 } 108 } 109 110 override fun onFinishInflate() { 111 super.onFinishInflate() 112 ambientIndicationArea = findViewById(R.id.ambient_indication_container) 113 } 114 115 override fun onConfigurationChanged(newConfig: Configuration) { 116 super.onConfigurationChanged(newConfig) 117 binding.onConfigurationChanged() 118 } 119 120 /** Returns a list of animators to use to animate the indication areas. */ 121 val indicationAreaAnimators: List<ViewPropertyAnimator> 122 get() = binding.getIndicationAreaAnimators() 123 124 override fun hasOverlappingRendering(): Boolean { 125 return false 126 } 127 128 override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { 129 val bottom = insets.displayCutout?.safeInsetBottom ?: 0 130 if (isPaddingRelative) { 131 setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom) 132 } else { 133 setPadding(paddingLeft, paddingTop, paddingRight, bottom) 134 } 135 return insets 136 } 137 138 override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { 139 super.onLayout(changed, left, top, right, bottom) 140 findViewById<View>(R.id.ambient_indication_container)?.let { 141 val (ambientLeft, ambientTop) = it.locationOnScreen 142 if (binding.shouldConstrainToTopOfLockIcon()) { 143 // make top of ambient indication view the bottom of the lock icon 144 it.layout( 145 ambientLeft, 146 lockIconViewController?.bottom?.toInt() ?: 0, 147 right - ambientLeft, 148 ambientTop + it.measuredHeight 149 ) 150 } else { 151 // make bottom of ambient indication view the top of the lock icon 152 val lockLocationTop = lockIconViewController?.top ?: 0 153 it.layout( 154 ambientLeft, 155 lockLocationTop.toInt() - it.measuredHeight, 156 right - ambientLeft, 157 lockLocationTop.toInt() 158 ) 159 } 160 } 161 } 162 } 163