Commit ce95f0d4 authored by Boris Sazonov's avatar Boris Sazonov Committed by Commit Bot

[Unity][Android] Reimplement ExpandablePreferenceGroup

This CL reimplements ExpandablePreferenceGroup to make it usable in
other contexts by decoupling it from SingleCategoryPreferences. It also
reimplements expand/collapse arrow and adds transition animations to it.

Bug: 814728
Change-Id: I126bd08c1841d282f889dfde1ff71b35fe0a2262
Reviewed-on: https://chromium-review.googlesource.com/1106144
Commit-Queue: Boris Sazonov <bsazonov@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568963}
parent 6e6d049f
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:aapt="http://schemas.android.com/aapt"
tools:targetApi="21">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:name="arrow"
android:fillColor="#000000"
android:pathData="M12,8L6,14L7.41,15.41L12,10.83L16.59,15.41L18,14z"/>
</vector>
</aapt:attr>
<target android:name="arrow">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="250"
android:propertyName="pathData"
android:valueFrom="M12,8L6,14L7.41,15.41L12,10.83L16.59,15.41L18,14z"
android:valueTo="M12,13.17L7.41,8.59L6,10L12,16L18,10L16.59,8.59z"
android:valueType="pathType"/>
</aapt:attr>
</target>
</animated-vector>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:aapt="http://schemas.android.com/aapt"
tools:targetApi="21">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:name="arrow"
android:fillColor="#000000"
android:pathData="M12,8L6,14L7.41,15.41L12,10.83L16.59,15.41L18,14z"/>
</vector>
</aapt:attr>
<target android:name="arrow">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="250"
android:propertyName="pathData"
android:valueFrom="M12,13.17L7.41,8.59L6,10L12,16L18,10L16.59,8.59z"
android:valueTo="M12,8L6,14L7.41,15.41L12,10.83L16.59,15.41L18,14z"
android:valueType="pathType"/>
</aapt:attr>
</target>
</animated-vector>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
<!-- Copyright 2018 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/expando"
<org.chromium.ui.widget.CheckableImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/checkable_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null" />
\ No newline at end of file
android:layout_height="wrap_content"/>
......@@ -6,75 +6,69 @@ package org.chromium.chrome.browser.preferences;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.PreferenceGroup;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.content.res.AppCompatResources;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import java.util.Locale;
import org.chromium.ui.drawable.StateListDrawableBuilder;
import org.chromium.ui.widget.CheckableImageView;
/**
* A preference category that accepts clicks for toggling on/off.
* A preference category that can be in either expanded or collapsed state. It shows expand/collapse
* arrow and changes content description for a11y according to the current state. Use
* {@link #setExpanded} to toggle collapsed/expanded state. Please note that this preference group
* won't modify the set of children preferences on expanded state change.
*/
public class ExpandablePreferenceGroup extends PreferenceGroup {
private boolean mExpanded = true;
private Drawable mDrawable;
private ImageView mImageView;
// Whether the PreferenceGroup is in an expanded or collapsed state.
private boolean mExpanded;
public ExpandablePreferenceGroup(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.preferenceStyle);
setWidgetLayoutResource(R.layout.site_list_expandable_header);
}
/**
* Set the title for the preference group.
* @param resourceId The resource id of the text to use.
* @param count The number of entries the preference group contains.
*/
public void setGroupTitle(int resourceId, int count) {
SpannableStringBuilder spannable =
new SpannableStringBuilder(getContext().getResources().getString(resourceId));
String prefCount = String.format(Locale.getDefault(), " - %d", count);
spannable.append(prefCount);
setWidgetLayoutResource(R.layout.checkable_image_view_widget);
// Color the first part of the title blue.
ForegroundColorSpan blueSpan = new ForegroundColorSpan(ApiCompatibilityUtils.getColor(
getContext().getResources(), R.color.google_blue_700));
spannable.setSpan(blueSpan, 0, spannable.length() - prefCount.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Fix animations. Background: setWidgetLayout resource call above disables view
// recycling, thus breaking animations. Views recycling is safe in this case, as this
// Preference doesn't change view types on the fly.
setRecycleEnabled(true);
}
}
// Gray out the total count of items.
int gray =
ApiCompatibilityUtils.getColor(getContext().getResources(), R.color.black_alpha_54);
spannable.setSpan(new ForegroundColorSpan(gray),
spannable.length() - prefCount.length(),
spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
setTitle(spannable);
/** Returns whether the preference group is expanded. */
public boolean isExpanded() {
return mExpanded;
}
public void setExpanded(boolean expanded) {
/**
* Set the expanded/collapsed state for the preference group.
* @param expanded The new expanded state.
*/
public final void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
onExpandedChanged(expanded);
notifyChanged();
}
@Override
public void setIcon(Drawable drawable) {
mDrawable = drawable;
if (mImageView != null) mImageView.setImageDrawable(mDrawable);
}
/** Subclasses may override this method to handle changes to the expanded/collapsed state. */
protected void onExpandedChanged(boolean expanded) {}
@Override
protected void onBindView(View view) {
super.onBindView(view);
mImageView = (ImageView) view.findViewById(R.id.expando);
if (mDrawable != null) mImageView.setImageDrawable(mDrawable);
if (mDrawable == null) {
mDrawable = createDrawable(getContext());
}
CheckableImageView imageView =
(CheckableImageView) view.findViewById(R.id.checkable_image_view);
imageView.setImageDrawable(mDrawable);
imageView.setChecked(mExpanded);
// For accessibility, read out the whole title and whether the group is collapsed/expanded.
String description = getTitle() + getContext().getResources().getString(mExpanded
......@@ -82,4 +76,21 @@ public class ExpandablePreferenceGroup extends PreferenceGroup {
: R.string.accessibility_collapsed_group);
view.setContentDescription(description);
}
private static Drawable createDrawable(Context context) {
StateListDrawableBuilder builder = new StateListDrawableBuilder(context);
StateListDrawableBuilder.State checked = builder.addState(
R.drawable.ic_expand_less_black_24dp, android.R.attr.state_checked);
StateListDrawableBuilder.State unchecked =
builder.addState(R.drawable.ic_expand_more_black_24dp);
builder.addTransition(
checked, unchecked, R.drawable.transition_expand_less_expand_more_black_24dp);
builder.addTransition(
unchecked, checked, R.drawable.transition_expand_more_expand_less_black_24dp);
Drawable tintableDrawable = DrawableCompat.wrap(builder.build());
DrawableCompat.setTintList(tintableDrawable,
AppCompatResources.getColorStateList(context, R.color.dark_mode_tint));
return tintableDrawable;
}
}
......@@ -17,7 +17,10 @@ import android.preference.PreferenceScreen;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.format.Formatter;
import android.text.style.ForegroundColorSpan;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.Menu;
......@@ -30,6 +33,7 @@ import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.help.HelpAndFeedback;
......@@ -47,7 +51,6 @@ import org.chromium.chrome.browser.preferences.PreferenceUtils;
import org.chromium.chrome.browser.preferences.ProtectedContentResetCredentialConfirmDialogFragment;
import org.chromium.chrome.browser.preferences.website.Website.StoredDataClearedCallback;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.widget.TintedDrawable;
import org.chromium.ui.widget.Toast;
import java.util.ArrayList;
......@@ -55,6 +58,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
......@@ -209,14 +213,8 @@ public class SingleCategoryPreferences extends PreferenceFragment
int resourceId = toggleValue
? R.string.website_settings_allowed_group_heading
: R.string.website_settings_exceptions_group_heading;
// Set the title and arrow icons for the header.
allowedGroup.setGroupTitle(resourceId, numAllowed);
TintedDrawable icon = TintedDrawable.constructTintedDrawable(getActivity(),
mAllowListExpanded ? R.drawable.ic_expand_more_black_24dp
: R.drawable.ic_expand_less_black_24dp);
allowedGroup.setTitle(getHeaderTitle(resourceId, numAllowed));
allowedGroup.setExpanded(mAllowListExpanded);
allowedGroup.setIcon(icon);
}
private void updateBlockedHeader(int numBlocked) {
......@@ -232,12 +230,27 @@ public class SingleCategoryPreferences extends PreferenceFragment
int resourceId = mCategory.showSoundSites()
? R.string.website_settings_blocked_group_heading_sound
: R.string.website_settings_blocked_group_heading;
blockedGroup.setGroupTitle(resourceId, numBlocked);
TintedDrawable icon = TintedDrawable.constructTintedDrawable(getActivity(),
mBlockListExpanded ? R.drawable.ic_expand_more_black_24dp
: R.drawable.ic_expand_less_black_24dp);
blockedGroup.setTitle(getHeaderTitle(resourceId, numBlocked));
blockedGroup.setExpanded(mBlockListExpanded);
blockedGroup.setIcon(icon);
}
private CharSequence getHeaderTitle(int resourceId, int count) {
SpannableStringBuilder spannable =
new SpannableStringBuilder(getResources().getString(resourceId));
String prefCount = String.format(Locale.getDefault(), " - %d", count);
spannable.append(prefCount);
// Color the first part of the title blue.
ForegroundColorSpan blueSpan = new ForegroundColorSpan(
ApiCompatibilityUtils.getColor(getResources(), R.color.google_blue_700));
spannable.setSpan(blueSpan, 0, spannable.length() - prefCount.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Gray out the total count of items.
int gray = ApiCompatibilityUtils.getColor(getResources(), R.color.black_alpha_54);
spannable.setSpan(new ForegroundColorSpan(gray), spannable.length() - prefCount.length(),
spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
@Override
......
......@@ -33,6 +33,7 @@ public class CheckableImageView extends AppCompatImageView implements Checkable
@Override
public void setImageDrawable(@Nullable Drawable drawable) {
if (drawable == getDrawable()) return;
super.setImageDrawable(drawable);
refreshDrawableState();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment