blob: c65462193758ff536b93385a38fc0db8f1d40be8 [file] [log] [blame]
/*
* Copyright (C) 2019 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.qs
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import com.android.systemui.R
/**
* Container for the Next Alarm and Ringer status texts in [QuickStatusBarHeader].
*
* If both elements are visible, it splits the available space according to the following rules:
* * If both views add up to less than the total space, they take all the space they need.
* * If both views are larger than half the space, each view takes half the space.
* * Otherwise, the smaller view takes the space it needs and the larger one takes all remaining
* space.
*/
class QSHeaderInfoLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyle, defStyleRes) {
private lateinit var alarmContainer: View
private lateinit var ringerContainer: View
private lateinit var statusSeparator: View
private val location = Location(0, 0)
override fun onFinishInflate() {
super.onFinishInflate()
alarmContainer = findViewById(R.id.alarm_container)
ringerContainer = findViewById(R.id.ringer_container)
statusSeparator = findViewById(R.id.status_separator)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
// At most one view is there
if (statusSeparator.visibility == View.GONE) super.onLayout(changed, l, t, r, b)
else {
val layoutRTL = isLayoutRtl
val width = r - l
val height = b - t
var offset = 0
offset += alarmContainer.layoutView(width, height, offset, layoutRTL)
offset += statusSeparator.layoutView(width, height, offset, layoutRTL)
ringerContainer.layoutView(width, height, offset, layoutRTL)
}
}
private fun View.layoutView(pWidth: Int, pHeight: Int, offset: Int, RTL: Boolean): Int {
location.setLocationFromOffset(pWidth, offset, this.measuredWidth, RTL)
layout(location.left, 0, location.right, pHeight)
return this.measuredWidth
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(
MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST),
heightMeasureSpec)
val width = MeasureSpec.getSize(widthMeasureSpec)
// Once we measure the views, using as much space as they need, we need to remeasure them
// assigning them their final width. This is because TextViews decide whether to MARQUEE
// after onMeasure.
if (statusSeparator.visibility != View.GONE) {
val alarmWidth = alarmContainer.measuredWidth
val separatorWidth = statusSeparator.measuredWidth
val ringerWidth = ringerContainer.measuredWidth
val availableSpace = MeasureSpec.getSize(width) - separatorWidth
if (alarmWidth < availableSpace / 2) {
measureChild(
ringerContainer,
MeasureSpec.makeMeasureSpec(
Math.min(ringerWidth, availableSpace - alarmWidth),
MeasureSpec.AT_MOST),
heightMeasureSpec)
} else if (ringerWidth < availableSpace / 2) {
measureChild(alarmContainer,
MeasureSpec.makeMeasureSpec(
Math.min(alarmWidth, availableSpace - ringerWidth),
MeasureSpec.AT_MOST),
heightMeasureSpec)
} else {
measureChild(
alarmContainer,
MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
heightMeasureSpec)
measureChild(
ringerContainer,
MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
heightMeasureSpec)
}
}
setMeasuredDimension(width, measuredHeight)
}
private data class Location(var left: Int, var right: Int) {
/**
* Sets the [left] and [right] with the correct values for laying out the child, respecting
* RTL. Only set the variable through here to prevent concurrency issues.
* This is done to prevent allocation of [Pair] in [onLayout].
*/
fun setLocationFromOffset(parentWidth: Int, offset: Int, width: Int, RTL: Boolean) {
if (RTL) {
left = parentWidth - offset - width
right = parentWidth - offset
} else {
left = offset
right = offset + width
}
}
}
}