diff options
author | 2024-12-24 19:50:21 +0000 | |
---|---|---|
committer | 2025-01-03 04:17:07 +0000 | |
commit | af4c722b3f8ea843223874d84f0e1130b370f21d (patch) | |
tree | be9a375dbe028f6fa6def360416f6aff39941c98 | |
parent | 21fee90b266b7d2f626fa7bdaa47553f9b13a618 (diff) |
Use TextSwitcher for animating status card text changes.
The transition animation fails occasionally and gets stuck. Have not
been able to track down exactly why or how.
Bug: 283953501
Test: Manual testing and atest SafetyCenterFunctionalTestCases
SafetyCenterActivityFunctionalTestCases
Relnote: Visual bugfix for Safety Center
Flag: EXEMPT bugfix
Change-Id: I7a3abebc36932dd52aef97230b983fae5e986c93
5 files changed, 93 insertions, 62 deletions
diff --git a/PermissionController/res/anim/text_switcher_fade_in.xml b/PermissionController/res/anim/text_switcher_fade_in.xml new file mode 100644 index 000000000..b9e2812aa --- /dev/null +++ b/PermissionController/res/anim/text_switcher_fade_in.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/linear_interpolator" + android:fromAlpha="0.0" android:toAlpha="1.0" + android:startOffset="@android:integer/config_shortAnimTime" + android:duration="@android:integer/config_shortAnimTime" />
\ No newline at end of file diff --git a/PermissionController/res/anim/text_switcher_fade_out.xml b/PermissionController/res/anim/text_switcher_fade_out.xml new file mode 100644 index 000000000..4b7274707 --- /dev/null +++ b/PermissionController/res/anim/text_switcher_fade_out.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/linear_interpolator" + android:fromAlpha="1.0" android:toAlpha="0.0" + android:duration="@android:integer/config_shortAnimTime" />
\ No newline at end of file diff --git a/PermissionController/res/layout-v33/view_status_card.xml b/PermissionController/res/layout-v33/view_status_card.xml index 4915347be..d8ca8b7ea 100644 --- a/PermissionController/res/layout-v33/view_status_card.xml +++ b/PermissionController/res/layout-v33/view_status_card.xml @@ -30,15 +30,34 @@ android:id="@+id/status_title_and_summary" style="?attr/scStatusTitleAndSummaryContainerStyle"> - <TextView + <TextSwitcher android:id="@+id/status_title" - android:text="@string/summary_placeholder" - style="@style/SafetyCenterStatusTitle" /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inAnimation="@anim/text_switcher_fade_in" + android:outAnimation="@anim/text_switcher_fade_out"> + <TextView + android:text="@string/summary_placeholder" + style="@style/SafetyCenterStatusTitle" /> + <TextView + android:text="@string/summary_placeholder" + style="@style/SafetyCenterStatusTitle" /> + </TextSwitcher> - <TextView + + <TextSwitcher android:id="@+id/status_summary" - android:text="@string/summary_placeholder" - style="@style/SafetyCenterStatusSummary" /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inAnimation="@anim/text_switcher_fade_in" + android:outAnimation="@anim/text_switcher_fade_out"> + <TextView + android:text="@string/summary_placeholder" + style="@style/SafetyCenterStatusSummary" /> + <TextView + android:text="@string/summary_placeholder" + style="@style/SafetyCenterStatusSummary" /> + </TextSwitcher> </LinearLayout> <androidx.constraintlayout.widget.Barrier diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java index abf159955..0bef71b3e 100644 --- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java @@ -29,7 +29,6 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; -import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -42,9 +41,6 @@ import com.android.permissioncontroller.safetycenter.ui.model.StatusUiData; import com.android.permissioncontroller.safetycenter.ui.view.StatusCardView; import com.android.settingslib.widget.GroupSectionDividerMixin; -import kotlin.Pair; - -import java.util.List; import java.util.Objects; /** Preference which displays a visual representation of {@link SafetyCenterStatus}. */ @@ -54,25 +50,16 @@ public class SafetyStatusPreference extends Preference private static final String TAG = "SafetyStatusPreference"; + private final SafetyStatusAnimationSequencer mSequencer = new SafetyStatusAnimationSequencer(); + @Nullable private StatusUiData mStatus; @Nullable private SafetyCenterViewModel mViewModel; - private final TextFadeAnimator mTitleTextAnimator = new TextFadeAnimator(R.id.status_title); - - private final TextFadeAnimator mSummaryTextAnimator = new TextFadeAnimator(R.id.status_summary); - - private final TextFadeAnimator mAllTextAnimator = - new TextFadeAnimator(List.of(R.id.status_title, R.id.status_summary)); - - private boolean mFirstBind = true; - public SafetyStatusPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.preference_safety_status); } - private boolean mIsTextChangeAnimationRunning; - private final SafetyStatusAnimationSequencer mSequencer = new SafetyStatusAnimationSequencer(); @Override public void onBindViewHolder(PreferenceViewHolder holder) { @@ -93,9 +80,7 @@ public class SafetyStatusPreference extends Preference updateStatusIcon(statusCardView); - updateStatusText(statusCardView.getTitleView(), statusCardView.getSummaryView()); - - mFirstBind = false; + statusCardView.showText(mStatus); } private void configureButtons(Context context, StatusCardView statusCardView) { @@ -125,14 +110,6 @@ public class SafetyStatusPreference extends Preference statusCardView.showButtons(mStatus); } - private void updateStatusText(TextView title, TextView summary) { - if (mFirstBind) { - title.setText(mStatus.getTitle()); - summary.setText(mStatus.getSummary(getContext())); - } - runTextAnimationIfNeeded(title, summary); - } - private void updateStatusIcon(StatusCardView statusCardView) { int severityLevel = mStatus.getSeverityLevel(); boolean isRefreshing = mStatus.isRefreshInProgress(); @@ -143,33 +120,6 @@ public class SafetyStatusPreference extends Preference /* scanningAnimation= */ null); } - private void runTextAnimationIfNeeded(TextView titleView, TextView summaryView) { - if (mIsTextChangeAnimationRunning) { - return; - } - Log.v(TAG, "Starting status text animation"); - String titleText = mStatus.getTitle().toString(); - String summaryText = mStatus.getSummary(getContext()).toString(); - boolean titleEquals = titleView.getText().toString().equals(titleText); - boolean summaryEquals = summaryView.getText().toString().equals(summaryText); - Runnable onFinish = - () -> { - Log.v(TAG, "Finishing status text animation"); - mIsTextChangeAnimationRunning = false; - runTextAnimationIfNeeded(titleView, summaryView); - }; - mIsTextChangeAnimationRunning = !titleEquals || !summaryEquals; - if (!titleEquals && !summaryEquals) { - Pair<TextView, String> titleChange = new Pair<>(titleView, titleText); - Pair<TextView, String> summaryChange = new Pair<>(summaryView, summaryText); - mAllTextAnimator.animateChangeText(List.of(titleChange, summaryChange), onFinish); - } else if (!titleEquals) { - mTitleTextAnimator.animateChangeText(titleView, titleText, onFinish); - } else if (!summaryEquals) { - mSummaryTextAnimator.animateChangeText(summaryView, summaryText, onFinish); - } - } - private void startScanningAnimation(StatusCardView statusCardView) { mSequencer.onStartScanningAnimationStart(); ImageView statusImage = statusCardView.getStatusImageView(); diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt index 6a415c563..bb417104d 100644 --- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt @@ -21,6 +21,7 @@ import android.os.Build import android.util.AttributeSet import android.widget.ImageView import android.widget.LinearLayout +import android.widget.TextSwitcher import android.widget.TextView import androidx.annotation.RequiresApi import androidx.constraintlayout.widget.ConstraintLayout @@ -35,7 +36,7 @@ constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, - defStyleRes: Int = 0 + defStyleRes: Int = 0, ) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) { init { @@ -44,11 +45,29 @@ constructor( val statusImageView: ImageView by lazyView(R.id.status_image) val titleAndSummaryContainerView: LinearLayout by lazyView(R.id.status_title_and_summary) - val titleView: TextView by lazyView(R.id.status_title) - val summaryView: TextView by lazyView(R.id.status_summary) + private val titleView: TextSwitcher by lazyView(R.id.status_title) + private val summaryView: TextSwitcher by lazyView(R.id.status_summary) val reviewSettingsButton: MaterialButton by lazyView(R.id.review_settings_button) val rescanButton: MaterialButton by lazyView(R.id.rescan_button) + fun showText(statusUiData: StatusUiData) { + titleView.updateText(statusUiData.title) + summaryView.updateText(statusUiData.getSummary(context)) + } + + private fun TextSwitcher.updateText(newText: CharSequence) { + val currentText: CharSequence? = (currentView as TextView).text + if (currentText == newText) { + return + } + + if (currentText.isNullOrBlank()) { + setCurrentText(newText) + } else { + setText(newText) + } + } + fun showButtons(statusUiData: StatusUiData) { rescanButton.isEnabled = !statusUiData.isRefreshInProgress |