Add AppHeaderPreference
Add a Preference widget for pages need to show big apps icon and name in the header of the page. BUG: 239779252 Test: add a simialr test like AppPreference Change-Id: I296b0ed7b9c7645f31a9080c29da490b843494b0
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2022 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.
|
||||
-->
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:antialias="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
style="@style/TextAppearance.EntityHeaderTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:gravity="center"
|
||||
android:ellipsize="marquee"
|
||||
android:textDirection="locale"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/install_type"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/install_type_instant"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:singleLine="false"
|
||||
android:textAlignment="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/second_summary"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:singleLine="false"
|
||||
android:maxLines="4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
22
packages/SettingsLib/AppPreference/res/values/strings.xml
Normal file
22
packages/SettingsLib/AppPreference/res/values/strings.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 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.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<!-- Added as the value of a header field indicating this is an instant app (as opposed to installed normally) -->
|
||||
<string name="install_type_instant">Instant app</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.settingslib.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
/**
|
||||
* The Preference for the pages need to show big apps icon and name in the header of the page.
|
||||
*/
|
||||
public class AppHeaderPreference extends Preference {
|
||||
|
||||
private boolean mIsInstantApp;
|
||||
private CharSequence mSecondSummary;
|
||||
|
||||
public AppHeaderPreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
public AppHeaderPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
public AppHeaderPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public AppHeaderPreference(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayoutResource(R.layout.app_header_preference);
|
||||
setSelectable(false);
|
||||
setIsInstantApp(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the installation type of this preference.
|
||||
*
|
||||
* @return whether the app is an instant app
|
||||
* @see #setIsInstantApp(boolean)
|
||||
*/
|
||||
public boolean getIsInstantApp() {
|
||||
return mIsInstantApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the installation type for this preference with a boolean.
|
||||
*
|
||||
* @param isInstantApp whether the app is an instant app
|
||||
*/
|
||||
public void setIsInstantApp(@NonNull boolean isInstantApp) {
|
||||
if (mIsInstantApp != isInstantApp) {
|
||||
mIsInstantApp = isInstantApp;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second summary of this preference.
|
||||
*
|
||||
* @return The second summary
|
||||
* @see #setSecondSummary(CharSequence)
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence getSecondSummary() {
|
||||
return mSecondSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the second summary for this preference with a CharSequence.
|
||||
*
|
||||
* @param secondSummary The second summary for the preference
|
||||
*/
|
||||
public void setSecondSummary(@Nullable CharSequence secondSummary) {
|
||||
if (!TextUtils.equals(mSecondSummary, secondSummary)) {
|
||||
mSecondSummary = secondSummary;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the second summary for this preference with a resource ID.
|
||||
*
|
||||
* @param secondSummaryResId The second summary as a resource
|
||||
* @see #setSecondSummary(CharSequence)
|
||||
*/
|
||||
public void setSecondSummary(@StringRes int secondSummaryResId) {
|
||||
setSecondSummary(getContext().getString(secondSummaryResId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
final TextView installTypeView = (TextView) holder.findViewById(R.id.install_type);
|
||||
if (installTypeView != null) {
|
||||
if (mIsInstantApp) {
|
||||
installTypeView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
installTypeView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
final TextView secondSummaryView = (TextView) holder.findViewById(R.id.second_summary);
|
||||
if (secondSummaryView != null) {
|
||||
if (!TextUtils.isEmpty(mSecondSummary)) {
|
||||
secondSummaryView.setText(mSecondSummary);
|
||||
secondSummaryView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
secondSummaryView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ android_library {
|
||||
|
||||
static_libs: [
|
||||
"androidx.preference_preference",
|
||||
"SettingsLibSettingsTheme",
|
||||
],
|
||||
|
||||
sdk_version: "system_current",
|
||||
|
||||
@@ -22,20 +22,6 @@
|
||||
<item name="android:paddingEnd">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EntityHeaderTitle"
|
||||
parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EntityHeaderSummary"
|
||||
parent="@android:style/TextAppearance.DeviceDefault">
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="CrossProfileEntityHeaderIcon">
|
||||
<item name="android:layout_width">48dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
|
||||
@@ -33,4 +33,18 @@
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EntityHeaderTitle"
|
||||
parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EntityHeaderSummary"
|
||||
parent="@android:style/TextAppearance.DeviceDefault">
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.settingslib.widget;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class AppHeaderPreferenceTest {
|
||||
|
||||
private Context mContext;
|
||||
private View mRootView;
|
||||
private AppHeaderPreference mPreference;
|
||||
private PreferenceViewHolder mHolder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mRootView = View.inflate(mContext, R.layout.app_header_preference, /* parent */ null);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
|
||||
mPreference = new AppHeaderPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNonSelectable_viewShouldNotBeSelectable() {
|
||||
mPreference.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mHolder.itemView.isClickable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInstallType_viewShouldNotBeVisible() {
|
||||
mPreference.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.install_type).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setIsInstantApp_shouldUpdateInstallType() {
|
||||
|
||||
mPreference.onBindViewHolder(mHolder);
|
||||
mPreference.setIsInstantApp(true);
|
||||
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.install_type)).getText().toString())
|
||||
.isEqualTo(mContext.getResources().getString(R.string.install_type_instant));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSecondSummary_shouldUpdateSecondSummary() {
|
||||
final String defaultTestText = "Test second summary";
|
||||
|
||||
mPreference.onBindViewHolder(mHolder);
|
||||
mPreference.setSecondSummary(defaultTestText);
|
||||
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.second_summary)).getText().toString())
|
||||
.isEqualTo(defaultTestText);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user