/*
|
* 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
|
}
|
}
|
}
|
}
|