| /* |
| * Copyright (C) 2016 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.statusbar; |
| |
| import android.content.Context; |
| import android.util.AttributeSet; |
| import android.util.DisplayMetrics; |
| import android.util.TypedValue; |
| import android.view.View; |
| import android.view.ViewGroup; |
| |
| /** |
| * Layout used as a container for keyboard shortcut keys. It's children are wrapped and right |
| * aligned. |
| */ |
| public final class KeyboardShortcutKeysLayout extends ViewGroup { |
| private int mLineHeight; |
| private final Context mContext; |
| |
| public KeyboardShortcutKeysLayout(Context context) { |
| super(context); |
| this.mContext = context; |
| } |
| |
| public KeyboardShortcutKeysLayout(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| this.mContext = context; |
| } |
| |
| @Override |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); |
| int childCount = getChildCount(); |
| int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); |
| int lineHeight = 0; |
| int xPos = getPaddingLeft(); |
| int yPos = getPaddingTop(); |
| |
| int childHeightMeasureSpec; |
| if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { |
| childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); |
| } else { |
| childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); |
| } |
| |
| for (int i = 0; i < childCount; i++) { |
| View child = getChildAt(i); |
| if (child.getVisibility() != GONE) { |
| LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); |
| child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), |
| childHeightMeasureSpec); |
| int childWidth = child.getMeasuredWidth(); |
| lineHeight = Math.max(lineHeight, |
| child.getMeasuredHeight() + layoutParams.mVerticalSpacing); |
| |
| if (xPos + childWidth > width) { |
| xPos = getPaddingLeft(); |
| yPos += lineHeight; |
| } |
| xPos += childWidth + layoutParams.mHorizontalSpacing; |
| } |
| } |
| this.mLineHeight = lineHeight; |
| |
| if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) { |
| height = yPos + lineHeight; |
| } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { |
| if (yPos + lineHeight < height) { |
| height = yPos + lineHeight; |
| } |
| } |
| setMeasuredDimension(width, height); |
| } |
| |
| @Override |
| protected LayoutParams generateDefaultLayoutParams() { |
| int spacing = getHorizontalVerticalSpacing(); |
| return new LayoutParams(spacing, spacing); |
| } |
| |
| @Override |
| protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams layoutParams) { |
| int spacing = getHorizontalVerticalSpacing(); |
| return new LayoutParams(spacing, spacing, layoutParams); |
| } |
| |
| @Override |
| protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { |
| return (p instanceof LayoutParams); |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| int childCount = getChildCount(); |
| int fullRowWidth = r - l; |
| int xPos = isRTL() |
| ? fullRowWidth - getPaddingRight() |
| : getPaddingLeft(); |
| int yPos = getPaddingTop(); |
| int lastHorizontalSpacing = 0; |
| // The index of the child which starts the current row. |
| int rowStartIdx = 0; |
| |
| // Go through all the children. |
| for (int i = 0; i < childCount; i++) { |
| View currentChild = getChildAt(i); |
| if (currentChild.getVisibility() != GONE) { |
| int currentChildWidth = currentChild.getMeasuredWidth(); |
| LayoutParams lp = (LayoutParams) currentChild.getLayoutParams(); |
| |
| boolean childDoesNotFitOnRow = isRTL() |
| ? xPos - getPaddingLeft() - currentChildWidth < 0 |
| : xPos + currentChildWidth > fullRowWidth; |
| |
| if (childDoesNotFitOnRow) { |
| // Layout all the children on this row but the current one. |
| layoutChildrenOnRow(rowStartIdx, i, fullRowWidth, xPos, yPos, |
| lastHorizontalSpacing); |
| // Update the positions for starting on the new row. |
| xPos = isRTL() |
| ? fullRowWidth - getPaddingRight() |
| : getPaddingLeft(); |
| yPos += mLineHeight; |
| rowStartIdx = i; |
| } |
| |
| xPos = isRTL() |
| ? xPos - currentChildWidth - lp.mHorizontalSpacing |
| : xPos + currentChildWidth + lp.mHorizontalSpacing; |
| lastHorizontalSpacing = lp.mHorizontalSpacing; |
| } |
| } |
| |
| // Lay out the children on the last row. |
| if (rowStartIdx < childCount) { |
| layoutChildrenOnRow(rowStartIdx, childCount, fullRowWidth, xPos, yPos, |
| lastHorizontalSpacing); |
| } |
| } |
| |
| private int getHorizontalVerticalSpacing() { |
| DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); |
| return (int) TypedValue.applyDimension( |
| TypedValue.COMPLEX_UNIT_DIP, 4, displayMetrics); |
| } |
| |
| private void layoutChildrenOnRow(int startIndex, int endIndex, int fullRowWidth, int xPos, |
| int yPos, int lastHorizontalSpacing) { |
| if (!isRTL()) { |
| xPos = getPaddingLeft() + fullRowWidth - xPos + lastHorizontalSpacing; |
| } |
| |
| for (int j = startIndex; j < endIndex; ++j) { |
| View currentChild = getChildAt(j); |
| int currentChildWidth = currentChild.getMeasuredWidth(); |
| LayoutParams lp = (LayoutParams) currentChild.getLayoutParams(); |
| if (isRTL() && j == startIndex) { |
| xPos = fullRowWidth - xPos - getPaddingRight() - currentChildWidth |
| - lp.mHorizontalSpacing; |
| } |
| |
| currentChild.layout( |
| xPos, |
| yPos, |
| xPos + currentChildWidth, |
| yPos + currentChild.getMeasuredHeight()); |
| |
| if (isRTL()) { |
| int nextChildWidth = j < endIndex - 1 |
| ? getChildAt(j + 1).getMeasuredWidth() |
| : 0; |
| xPos -= nextChildWidth + lp.mHorizontalSpacing; |
| } else { |
| xPos += currentChildWidth + lp.mHorizontalSpacing; |
| } |
| } |
| } |
| |
| private boolean isRTL() { |
| return mContext.getResources().getConfiguration().getLayoutDirection() |
| == View.LAYOUT_DIRECTION_RTL; |
| } |
| |
| public static class LayoutParams extends ViewGroup.LayoutParams { |
| public final int mHorizontalSpacing; |
| public final int mVerticalSpacing; |
| |
| public LayoutParams(int horizontalSpacing, int verticalSpacing, |
| ViewGroup.LayoutParams viewGroupLayout) { |
| super(viewGroupLayout); |
| this.mHorizontalSpacing = horizontalSpacing; |
| this.mVerticalSpacing = verticalSpacing; |
| } |
| |
| public LayoutParams(int mHorizontalSpacing, int verticalSpacing) { |
| super(0, 0); |
| this.mHorizontalSpacing = mHorizontalSpacing; |
| this.mVerticalSpacing = verticalSpacing; |
| } |
| } |
| } |