summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tyler Dewey <deweytyl@google.com> 2024-12-24 19:50:21 +0000
committer Tyler Dewey <deweytyl@google.com> 2025-01-03 04:17:07 +0000
commitaf4c722b3f8ea843223874d84f0e1130b370f21d (patch)
treebe9a375dbe028f6fa6def360416f6aff39941c98
parent21fee90b266b7d2f626fa7bdaa47553f9b13a618 (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
-rw-r--r--PermissionController/res/anim/text_switcher_fade_in.xml22
-rw-r--r--PermissionController/res/anim/text_switcher_fade_out.xml21
-rw-r--r--PermissionController/res/layout-v33/view_status_card.xml31
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt25
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