New SecurityFooter design
Changes: * Footer appears below QSFooter in portrait, QSBH in landscape * In portrait, height is 48dp for one line of text, 88dp for two lines of text. Creates a new layout that inherits from LinearLayout (horizontal) and adjusts its height based on the number of lines of the containing text. Test: manual Test: atest QSSecurityFooterTest Fixes: 186033456 Change-Id: Ia4f9d5c9b4078d790f654dbd4b82d14670985f8d
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 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.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@android:color/system_neutral1_100" android:alpha="0.8" />
|
||||
</selector>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:insetTop="@dimen/qs_security_footer_background_inset"
|
||||
android:insetBottom="@dimen/qs_security_footer_background_inset"
|
||||
>
|
||||
<ripple
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@android:color/white"/>
|
||||
<corners android:radius="@dimen/qs_security_footer_corner_radius"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<stroke android:width="1dp"
|
||||
android:color="@color/qs_security_footer_background_stroke"/>
|
||||
<corners android:radius="@dimen/qs_security_footer_corner_radius"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
</inset>
|
||||
@@ -44,14 +44,6 @@
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<!-- Will hold security footer in landscape with media -->
|
||||
<FrameLayout
|
||||
android:id="@+id/header_text_container"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
||||
<include layout="@layout/qs_carrier_group"
|
||||
android:id="@+id/carrier_group"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -14,38 +14,39 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
<com.android.systemui.util.DualHeightHorizontalLinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/qs_security_footer_height"
|
||||
android:clickable="true"
|
||||
android:paddingBottom="@dimen/qs_tile_padding_top"
|
||||
android:paddingTop="@dimen/qs_tile_padding_top"
|
||||
android:paddingStart="@dimen/qs_footer_padding_start"
|
||||
android:paddingEnd="@dimen/qs_footer_padding_end"
|
||||
android:padding="@dimen/qs_footer_padding"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:background="@android:color/transparent">
|
||||
android:layout_marginVertical="@dimen/qs_security_footer_vertical_margin"
|
||||
android:background="@drawable/qs_security_footer_background"
|
||||
systemui:singleLineHeight="@dimen/qs_security_footer_single_line_height"
|
||||
systemui:textViewId="@id/footer_text"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/primary_footer_icon"
|
||||
android:layout_width="@dimen/qs_footer_icon_size"
|
||||
android:layout_height="@dimen/qs_footer_icon_size"
|
||||
android:gravity="start"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:contentDescription="@null"
|
||||
android:tint="?android:attr/textColorPrimary" />
|
||||
android:tint="?android:attr/textColorSecondary" />
|
||||
|
||||
<com.android.systemui.util.AutoMarqueeTextView
|
||||
<TextView
|
||||
android:id="@+id/footer_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:textAppearance="@style/TextAppearance.QS.TileLabel"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
android:maxLines="@integer/qs_security_footer_maxLines"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/TextAppearance.QS.SecurityFooter"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/footer_icon"
|
||||
@@ -53,7 +54,7 @@
|
||||
android:layout_height="@dimen/qs_footer_icon_size"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_info_outline"
|
||||
android:tint="?android:attr/textColorPrimary" />
|
||||
android:src="@*android:drawable/ic_chevron_end"
|
||||
android:tint="?android:attr/textColorSecondary" />
|
||||
|
||||
</com.android.systemui.util.NeverExactlyLinearLayout>
|
||||
</com.android.systemui.util.DualHeightHorizontalLinearLayout>
|
||||
@@ -55,6 +55,16 @@
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Will hold security footer in landscape with media -->
|
||||
<FrameLayout
|
||||
android:id="@+id/header_text_container"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
-->
|
||||
<dimen name="qs_customize_header_min_height">44dp</dimen>
|
||||
|
||||
<dimen name="qs_security_footer_single_line_height">@*android:dimen/quick_qs_offset_height</dimen>
|
||||
<dimen name="qs_footer_padding">14dp</dimen>
|
||||
<dimen name="qs_security_footer_vertical_margin">0dp</dimen>
|
||||
<dimen name="qs_security_footer_background_inset">12dp</dimen>
|
||||
<dimen name="qs_security_footer_corner_radius">28dp</dimen>
|
||||
|
||||
<dimen name="battery_detail_graph_space_top">9dp</dimen>
|
||||
<dimen name="battery_detail_graph_space_bottom">9dp</dimen>
|
||||
|
||||
|
||||
@@ -189,5 +189,11 @@
|
||||
<attr name="borderThickness" format="dimension" />
|
||||
<attr name="borderColor" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="DualHeightHorizontalLinearLayout">
|
||||
<attr name="singleLineHeight" format="dimension" />
|
||||
<attr name="singleLineVerticalPadding" format="dimension" />
|
||||
<attr name="textViewId" format="reference" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -605,13 +605,18 @@
|
||||
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
|
||||
<dimen name="qs_status_separator">32dp</dimen>
|
||||
<dimen name="qs_carrier_margin_width">4dp</dimen>
|
||||
<dimen name="qs_footer_padding_start">16dp</dimen>
|
||||
<dimen name="qs_footer_padding_end">16dp</dimen>
|
||||
<dimen name="qs_footer_icon_size">16dp</dimen>
|
||||
<dimen name="qs_footer_icon_size">20dp</dimen>
|
||||
<dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
|
||||
<dimen name="qs_header_top_padding">15dp</dimen>
|
||||
<dimen name="qs_header_bottom_padding">14dp</dimen>
|
||||
|
||||
<dimen name="qs_footer_padding">20dp</dimen>
|
||||
<dimen name="qs_security_footer_height">88dp</dimen>
|
||||
<dimen name="qs_security_footer_single_line_height">48dp</dimen>
|
||||
<dimen name="qs_security_footer_vertical_margin">8dp</dimen>
|
||||
<dimen name="qs_security_footer_background_inset">0dp</dimen>
|
||||
<dimen name="qs_security_footer_corner_radius">28dp</dimen>
|
||||
|
||||
<dimen name="qs_notif_collapsed_space">64dp</dimen>
|
||||
|
||||
<dimen name="qs_container_bottom_padding">24dp</dimen>
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<integer name="qs_footer_actions_width">0</integer>
|
||||
<integer name="qs_footer_actions_weight">1</integer>
|
||||
|
||||
<integer name="qs_security_footer_maxLines">2</integer>
|
||||
|
||||
<integer name="magnification_default_scale">2</integer>
|
||||
|
||||
<!-- The position of the volume dialog on the screen.
|
||||
|
||||
@@ -220,6 +220,11 @@
|
||||
<item name="android:textSize">@dimen/celltile_rat_type_size</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.SecurityFooter">
|
||||
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
|
||||
<item name="android:textSize">@dimen/qs_tile_text_size</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.Status" parent="TextAppearance.QS.TileLabel.Secondary">
|
||||
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
|
||||
<item name="android:textColor">@color/dark_mode_qs_icon_color_single_tone</item>
|
||||
|
||||
@@ -326,6 +326,7 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mOnConfigurationChangedListeners.forEach(
|
||||
listener -> listener.onConfigurationChange(newConfig));
|
||||
switchSecurityFooter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,19 +365,25 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
switchToParent((View) newLayout, parent, index);
|
||||
index++;
|
||||
|
||||
if (mSecurityFooter != null) {
|
||||
if (mUsingHorizontalLayout && mHeaderContainer != null) {
|
||||
// Adding the security view to the header, that enables us to avoid scrolling
|
||||
switchToParent(mSecurityFooter, mHeaderContainer, 0);
|
||||
} else {
|
||||
switchToParent(mSecurityFooter, parent, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mFooter != null) {
|
||||
// Then the footer with the settings
|
||||
switchToParent(mFooter, parent, index);
|
||||
index++;
|
||||
}
|
||||
|
||||
// The security footer is switched on orientation changes
|
||||
}
|
||||
|
||||
private void switchSecurityFooter() {
|
||||
if (mSecurityFooter != null) {
|
||||
if (mContext.getResources().getConfiguration().orientation
|
||||
== Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null
|
||||
&& !mSecurityFooter.getParent().equals(mHeaderContainer)) {
|
||||
// Adding the security view to the header, that enables us to avoid scrolling
|
||||
switchToParent(mSecurityFooter, mHeaderContainer, 0);
|
||||
} else {
|
||||
switchToParent(mSecurityFooter, this, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,6 +675,7 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
|
||||
public void setSecurityFooter(View view) {
|
||||
mSecurityFooter = view;
|
||||
switchSecurityFooter();
|
||||
}
|
||||
|
||||
void setUsingHorizontalLayout(boolean horizontal, ViewGroup mediaHostView, boolean force,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.android.systemui.qs;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW;
|
||||
|
||||
@@ -26,6 +28,8 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -68,7 +72,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
|
||||
private final View mRootView;
|
||||
private final TextView mFooterText;
|
||||
private final ImageView mFooterIcon;
|
||||
private final ImageView mPrimaryFooterIcon;
|
||||
private final Context mContext;
|
||||
private final Callback mCallback = new Callback();
|
||||
@@ -83,7 +86,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
|
||||
private boolean mIsVisible;
|
||||
private CharSequence mFooterTextContent = null;
|
||||
private int mFooterTextId;
|
||||
private int mFooterIconId;
|
||||
private Drawable mPrimaryFooterIconDrawable;
|
||||
|
||||
@@ -94,7 +96,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
mRootView = rootView;
|
||||
mRootView.setOnClickListener(this);
|
||||
mFooterText = mRootView.findViewById(R.id.footer_text);
|
||||
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
|
||||
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
|
||||
mFooterIconId = R.drawable.ic_info_outline;
|
||||
mContext = rootView.getContext();
|
||||
@@ -120,6 +121,23 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
|
||||
public void onConfigurationChanged() {
|
||||
FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
|
||||
|
||||
Resources r = mContext.getResources();
|
||||
|
||||
mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines));
|
||||
int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding);
|
||||
mRootView.setPaddingRelative(padding, padding, padding, padding);
|
||||
|
||||
int verticalMargin = r.getDimensionPixelSize(R.dimen.qs_security_footer_vertical_margin);
|
||||
ViewGroup.MarginLayoutParams lp =
|
||||
(ViewGroup.MarginLayoutParams) mRootView.getLayoutParams();
|
||||
lp.topMargin = verticalMargin;
|
||||
lp.bottomMargin = verticalMargin;
|
||||
lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
? MATCH_PARENT : WRAP_CONTENT;
|
||||
mRootView.setLayoutParams(lp);
|
||||
|
||||
mRootView.setBackground(mContext.getDrawable(R.drawable.qs_security_footer_background));
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
@@ -189,7 +207,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
}
|
||||
if (mFooterIconId != footerIconId) {
|
||||
mFooterIconId = footerIconId;
|
||||
mMainHandler.post(mUpdateIcon);
|
||||
}
|
||||
|
||||
// Update the primary icon
|
||||
@@ -315,7 +332,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
mDialog.setView(createDialogView());
|
||||
|
||||
mDialog.show();
|
||||
mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
mDialog.getWindow().setLayout(MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
@@ -575,19 +592,14 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
|
||||
== DEVICE_OWNER_TYPE_FINANCED;
|
||||
}
|
||||
|
||||
private final Runnable mUpdateIcon = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mFooterIcon.setImageResource(mFooterIconId);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mUpdatePrimaryIcon = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mPrimaryFooterIcon.setVisibility(mPrimaryFooterIconDrawable != null
|
||||
? View.VISIBLE : View.GONE);
|
||||
mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
|
||||
if (mPrimaryFooterIconDrawable != null) {
|
||||
mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
|
||||
} else {
|
||||
mPrimaryFooterIcon.setImageResource(mFooterIconId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public interface QSFragmentModule {
|
||||
@QSThemedContext LayoutInflater layoutInflater,
|
||||
QSPanel qsPanel
|
||||
) {
|
||||
return layoutInflater.inflate(R.layout.quick_settings_footer, qsPanel, false);
|
||||
return layoutInflater.inflate(R.layout.quick_settings_security_footer, qsPanel, false);
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.android.systemui.R
|
||||
|
||||
/**
|
||||
* Horizontal [LinearLayout] to contain some text.
|
||||
*
|
||||
* The height of this container can alternate between two different heights, depending on whether
|
||||
* the text takes one line or more.
|
||||
*
|
||||
* When the text takes multiple lines, it will use the values in the regular attributes (`padding`,
|
||||
* `layout_height`). The single line behavior must be set in XML.
|
||||
*
|
||||
* XML attributes for single line behavior:
|
||||
* * `systemui:textViewId`: set the id for the [TextView] that determines the height of the
|
||||
* container
|
||||
* * `systemui:singleLineHeight`: sets the height of the view when the text takes up only one line.
|
||||
* By default, it will use [getMinimumHeight].
|
||||
* * `systemui:singleLineVerticalPadding`: sets the padding (top and bottom) when then text takes up
|
||||
* only one line. By default, it is 0.
|
||||
*
|
||||
* All dimensions are updated when configuration changes.
|
||||
*/
|
||||
class DualHeightHorizontalLinearLayout @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttrs: Int = 0,
|
||||
defStyleRes: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
|
||||
|
||||
private val singleLineHeightValue: TypedValue?
|
||||
private var singleLineHeightPx = 0
|
||||
|
||||
private val singleLineVerticalPaddingValue: TypedValue?
|
||||
private var singleLineVerticalPaddingPx = 0
|
||||
|
||||
private val textViewId: Int
|
||||
private var textView: TextView? = null
|
||||
|
||||
private val displayMetrics: DisplayMetrics
|
||||
get() = context.resources.displayMetrics
|
||||
|
||||
private var initialPadding = mPaddingTop // All vertical padding is the same
|
||||
|
||||
init {
|
||||
if (orientation != HORIZONTAL) {
|
||||
throw IllegalStateException("This view should always have horizontal orientation")
|
||||
}
|
||||
|
||||
val ta = context.obtainStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.DualHeightHorizontalLinearLayout, defStyleAttrs, defStyleRes
|
||||
)
|
||||
|
||||
val tempHeight = TypedValue()
|
||||
singleLineHeightValue = if (
|
||||
ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight)
|
||||
) {
|
||||
ta.getValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight, tempHeight)
|
||||
tempHeight
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val tempPadding = TypedValue()
|
||||
singleLineVerticalPaddingValue = if (
|
||||
ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding)
|
||||
) {
|
||||
ta.getValue(
|
||||
R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding,
|
||||
tempPadding
|
||||
)
|
||||
tempPadding
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
textViewId = ta.getResourceId(R.styleable.DualHeightHorizontalLinearLayout_textViewId, 0)
|
||||
|
||||
ta.recycle()
|
||||
}
|
||||
|
||||
init {
|
||||
updateResources()
|
||||
}
|
||||
|
||||
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.setPadding(left, top, right, bottom)
|
||||
initialPadding = top
|
||||
}
|
||||
|
||||
override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
|
||||
super.setPaddingRelative(start, top, end, bottom)
|
||||
initialPadding = top
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
textView?.let { tv ->
|
||||
if (tv.lineCount < 2) {
|
||||
setMeasuredDimension(measuredWidth, singleLineHeightPx)
|
||||
mPaddingBottom = 0
|
||||
mPaddingTop = 0
|
||||
} else {
|
||||
mPaddingBottom = initialPadding
|
||||
mPaddingTop = initialPadding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
textView = findViewById(textViewId)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration?) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
updateResources()
|
||||
}
|
||||
|
||||
override fun setOrientation(orientation: Int) {
|
||||
if (orientation == VERTICAL) {
|
||||
throw IllegalStateException("This view should always have horizontal orientation")
|
||||
}
|
||||
super.setOrientation(orientation)
|
||||
}
|
||||
|
||||
private fun updateResources() {
|
||||
updateDimensionValue(singleLineHeightValue, minimumHeight, ::singleLineHeightPx::set)
|
||||
updateDimensionValue(singleLineVerticalPaddingValue, 0, ::singleLineVerticalPaddingPx::set)
|
||||
}
|
||||
|
||||
private inline fun updateDimensionValue(
|
||||
tv: TypedValue?,
|
||||
defaultValue: Int,
|
||||
propertySetter: (Int) -> Unit
|
||||
) {
|
||||
val value = tv?.let {
|
||||
if (it.resourceId != 0) {
|
||||
context.resources.getDimensionPixelSize(it.resourceId)
|
||||
} else {
|
||||
it.getDimension(displayMetrics).toInt()
|
||||
}
|
||||
} ?: defaultValue
|
||||
propertySetter(value)
|
||||
}
|
||||
}
|
||||
@@ -81,10 +81,10 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
private static final String PARENTAL_CONTROLS_LABEL = "Parental Control App";
|
||||
private static final ComponentName DEVICE_OWNER_COMPONENT =
|
||||
new ComponentName("TestDPC", "Test");
|
||||
private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline;
|
||||
|
||||
private ViewGroup mRootView;
|
||||
private TextView mFooterText;
|
||||
private TestableImageView mFooterIcon;
|
||||
private TestableImageView mPrimaryFooterIcon;
|
||||
private QSSecurityFooter mFooter;
|
||||
@Mock
|
||||
@@ -101,11 +101,10 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
|
||||
mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
|
||||
.replace("ImageView", TestableImageView.class)
|
||||
.build().inflate(R.layout.quick_settings_footer, null, false);
|
||||
.build().inflate(R.layout.quick_settings_security_footer, null, false);
|
||||
mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper),
|
||||
mActivityStarter, mSecurityController, looper);
|
||||
mFooterText = mRootView.findViewById(R.id.footer_text);
|
||||
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
|
||||
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
|
||||
mFooter.setHostEnvironment(null);
|
||||
|
||||
@@ -135,10 +134,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management),
|
||||
mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mRootView.getVisibility());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -153,10 +150,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
MANAGING_ORGANIZATION),
|
||||
mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mRootView.getVisibility());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,10 +169,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
R.string.quick_settings_financed_disclosure_named_management,
|
||||
MANAGING_ORGANIZATION), mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mRootView.getVisibility());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,10 +197,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
|
||||
mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
|
||||
// Same situation, but with organization name set
|
||||
when(mSecurityController.getDeviceOwnerOrganizationName())
|
||||
@@ -255,9 +246,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_named_vpn,
|
||||
VPN_PACKAGE),
|
||||
mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
|
||||
// Same situation, but with organization name set
|
||||
when(mSecurityController.getDeviceOwnerOrganizationName())
|
||||
@@ -282,9 +272,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
|
||||
mFooterText.getText());
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
|
||||
// Same situation, but with organization name set
|
||||
when(mSecurityController.getDeviceOwnerOrganizationName())
|
||||
@@ -306,9 +295,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
|
||||
mFooterText.getText());
|
||||
}
|
||||
@@ -320,8 +308,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(
|
||||
R.string.quick_settings_disclosure_managed_profile_monitoring),
|
||||
mFooterText.getText());
|
||||
@@ -345,8 +332,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
// -1 == never set.
|
||||
assertEquals(-1, mFooterIcon.getLastImageResource());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_monitoring),
|
||||
mFooterText.getText());
|
||||
}
|
||||
@@ -359,7 +345,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_vpns),
|
||||
mFooterText.getText());
|
||||
}
|
||||
@@ -371,7 +357,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(
|
||||
R.string.quick_settings_disclosure_managed_profile_named_vpn,
|
||||
VPN_PACKAGE_2),
|
||||
@@ -412,7 +398,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
mFooter.refreshState();
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
|
||||
assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
|
||||
assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_vpn,
|
||||
VPN_PACKAGE),
|
||||
mFooterText.getText());
|
||||
@@ -648,12 +634,12 @@ public class QSSecurityFooterTest extends SysuiTestCase {
|
||||
|
||||
assertEquals(testDrawable, mPrimaryFooterIcon.getDrawable());
|
||||
|
||||
// Ensure the primary icon is set to gone when parental controls is disabled.
|
||||
// Ensure the primary icon is back to default after parental controls are gone
|
||||
when(mSecurityController.isParentalControlsEnabled()).thenReturn(false);
|
||||
mFooter.refreshState();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
|
||||
assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
|
||||
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user