Merge "Migrate WindowContext#onConfigurationChanged to ClientTransaction (7/n)" into main
diff --git a/core/java/android/os/CombinedVibration.java b/core/java/android/os/CombinedVibration.java
index db1a741..f32a1f8 100644
--- a/core/java/android/os/CombinedVibration.java
+++ b/core/java/android/os/CombinedVibration.java
@@ -24,7 +24,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* A CombinedVibration describes a combination of haptic effects to be performed by one or more
@@ -151,6 +153,13 @@
public abstract boolean hasVibrator(int vibratorId);
/**
+ * Returns a compact version of the {@link #toString()} result for debugging purposes.
+ *
+ * @hide
+ */
+ public abstract String toDebugString();
+
+ /**
* Adapts a {@link VibrationEffect} to a specific device vibrator using the ID.
*
* <p>This can be used for adapting effects to the capabilities of the specific device vibrator
@@ -437,6 +446,13 @@
return "Mono{mEffect=" + mEffect + '}';
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ // Simplify vibration string, use the single effect to represent it.
+ return mEffect.toDebugString();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -619,6 +635,17 @@
return "Stereo{mEffects=" + mEffects + '}';
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ StringJoiner sj = new StringJoiner(",", "Stereo{", "}");
+ for (int i = 0; i < mEffects.size(); i++) {
+ sj.add(String.format(Locale.ROOT, "vibrator(id=%d): %s",
+ mEffects.keyAt(i), mEffects.valueAt(i).toDebugString()));
+ }
+ return sj.toString();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -833,6 +860,17 @@
return "Sequential{mEffects=" + mEffects + ", mDelays=" + mDelays + '}';
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ StringJoiner sj = new StringJoiner(",", "Sequential{", "}");
+ for (int i = 0; i < mEffects.size(); i++) {
+ sj.add(String.format(Locale.ROOT, "delayMs=%d, effect=%s",
+ mDelays.get(i), mEffects.get(i).toDebugString()));
+ }
+ return sj.toString();
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index b2d62eb..98f9dff 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -336,10 +336,11 @@
@Override
public String toString() {
- return "VibrationAttributes:"
- + " Usage=" + usageToString()
- + " Audio Usage= " + AudioAttributes.usageToString(mOriginalAudioUsage)
- + " Flags=" + mFlags;
+ return "VibrationAttributes{"
+ + "mUsage=" + usageToString()
+ + ", mAudioUsage= " + AudioAttributes.usageToString(mOriginalAudioUsage)
+ + ", mFlags=" + mFlags
+ + '}';
}
/** @hide */
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index c3d7540..b24b45d 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -44,7 +44,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* A VibrationEffect describes a haptic effect to be performed by a {@link Vibrator}.
@@ -629,6 +631,13 @@
return MathUtils.constrain(a * fx, 0f, 1f);
}
+ /**
+ * Returns a compact version of the {@link #toString()} result for debugging purposes.
+ *
+ * @hide
+ */
+ public abstract String toDebugString();
+
/** @hide */
public static String effectIdToString(int effectId) {
switch (effectId) {
@@ -925,6 +934,23 @@
+ "}";
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ if (mSegments.size() == 1 && mRepeatIndex < 0) {
+ // Simplify effect string, use the single segment to represent it.
+ return mSegments.get(0).toDebugString();
+ }
+ StringJoiner sj = new StringJoiner(",", "[", "]");
+ for (int i = 0; i < mSegments.size(); i++) {
+ sj.add(mSegments.get(i).toDebugString());
+ }
+ if (mRepeatIndex >= 0) {
+ return String.format(Locale.ROOT, "%s, repeat=%d", sj, mRepeatIndex);
+ }
+ return sj.toString();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1250,23 +1276,23 @@
public static String primitiveToString(@PrimitiveType int id) {
switch (id) {
case PRIMITIVE_NOOP:
- return "PRIMITIVE_NOOP";
+ return "NOOP";
case PRIMITIVE_CLICK:
- return "PRIMITIVE_CLICK";
+ return "CLICK";
case PRIMITIVE_THUD:
- return "PRIMITIVE_THUD";
+ return "THUD";
case PRIMITIVE_SPIN:
- return "PRIMITIVE_SPIN";
+ return "SPIN";
case PRIMITIVE_QUICK_RISE:
- return "PRIMITIVE_QUICK_RISE";
+ return "QUICK_RISE";
case PRIMITIVE_SLOW_RISE:
- return "PRIMITIVE_SLOW_RISE";
+ return "SLOW_RISE";
case PRIMITIVE_QUICK_FALL:
- return "PRIMITIVE_QUICK_FALL";
+ return "QUICK_FALL";
case PRIMITIVE_TICK:
- return "PRIMITIVE_TICK";
+ return "TICK";
case PRIMITIVE_LOW_TICK:
- return "PRIMITIVE_LOW_TICK";
+ return "LOW_TICK";
default:
return Integer.toString(id);
}
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 71ec096..02e6856 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.hardware.vibrator.Braking;
import android.hardware.vibrator.IVibrator;
+import android.util.IndentingPrintWriter;
import android.util.MathUtils;
import android.util.Range;
import android.util.SparseBooleanArray;
@@ -207,6 +208,25 @@
+ '}';
}
+ /** @hide */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("VibratorInfo:");
+ pw.increaseIndent();
+ pw.println("id = " + mId);
+ pw.println("capabilities = " + Arrays.toString(getCapabilitiesNames()));
+ pw.println("capabilitiesFlags = " + Long.toBinaryString(mCapabilities));
+ pw.println("supportedEffects = " + Arrays.toString(getSupportedEffectsNames()));
+ pw.println("supportedPrimitives = " + Arrays.toString(getSupportedPrimitivesNames()));
+ pw.println("supportedBraking = " + Arrays.toString(getSupportedBrakingNames()));
+ pw.println("primitiveDelayMax = " + mPrimitiveDelayMax);
+ pw.println("compositionSizeMax = " + mCompositionSizeMax);
+ pw.println("pwlePrimitiveDurationMax = " + mPwlePrimitiveDurationMax);
+ pw.println("pwleSizeMax = " + mPwleSizeMax);
+ pw.println("q-factor = " + mQFactor);
+ pw.println("frequencyProfile = " + mFrequencyProfile);
+ pw.decreaseIndent();
+ }
+
/** Return the id of this vibrator. */
public int getId() {
return mId;
@@ -370,7 +390,7 @@
* Gets the resonant frequency of the vibrator.
*
* @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or
- * this vibrator is a composite of multiple physical devices.
+ * this vibrator is a composite of multiple physical devices.
*/
public float getResonantFrequencyHz() {
return mFrequencyProfile.mResonantFrequencyHz;
@@ -380,7 +400,7 @@
* Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator.
*
* @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or
- * this vibrator is a composite of multiple physical devices.
+ * this vibrator is a composite of multiple physical devices.
*/
public float getQFactor() {
return mQFactor;
diff --git a/core/java/android/os/vibrator/PrebakedSegment.java b/core/java/android/os/vibrator/PrebakedSegment.java
index 462e5ad..42b6c2da 100644
--- a/core/java/android/os/vibrator/PrebakedSegment.java
+++ b/core/java/android/os/vibrator/PrebakedSegment.java
@@ -203,6 +203,15 @@
+ "}";
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ return String.format("Prebaked=%s(%s, %s fallback)",
+ VibrationEffect.effectIdToString(mEffectId),
+ VibrationEffect.effectStrengthToString(mEffectStrength),
+ mFallback ? "with" : "no");
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java
index 815a1dc..c52a09c 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -140,6 +140,13 @@
+ '}';
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ return String.format("Primitive=%s(scale=%.2f, delay=%dms)",
+ VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale, mDelay);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
diff --git a/core/java/android/os/vibrator/RampSegment.java b/core/java/android/os/vibrator/RampSegment.java
index a5dee6c..e997bcd 100644
--- a/core/java/android/os/vibrator/RampSegment.java
+++ b/core/java/android/os/vibrator/RampSegment.java
@@ -179,6 +179,17 @@
+ "}";
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ return String.format("Ramp=%dms(amplitude=%.2f%s to %.2f%s)",
+ mDuration,
+ mStartAmplitude,
+ Float.compare(mStartFrequencyHz, 0) == 0 ? "" : " @ " + mStartFrequencyHz + "Hz",
+ mEndAmplitude,
+ Float.compare(mEndFrequencyHz, 0) == 0 ? "" : " @ " + mEndFrequencyHz + "Hz");
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/os/vibrator/StepSegment.java b/core/java/android/os/vibrator/StepSegment.java
index 54a44a8..a585aa8 100644
--- a/core/java/android/os/vibrator/StepSegment.java
+++ b/core/java/android/os/vibrator/StepSegment.java
@@ -161,6 +161,13 @@
+ "}";
}
+ /** @hide */
+ @Override
+ public String toDebugString() {
+ return String.format("Step=%dms(amplitude=%.2f%s)", mDuration, mAmplitude,
+ Float.compare(mFrequencyHz, 0) == 0 ? "" : " @ " + mFrequencyHz + "Hz");
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index 4790d81..bde334a 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -32,6 +32,9 @@
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.os.Vibrator.VibrationIntensity;
+import android.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
/**
* List of device-specific internal vibration configuration loaded from platform config.xml.
@@ -191,4 +194,18 @@
+ ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
+ "}";
}
+
+ /**
+ * Write current settings into given {@link PrintWriter}, skipping the default settings.
+ *
+ * @hide
+ */
+ public void dumpWithoutDefaultSettings(IndentingPrintWriter pw) {
+ pw.println("VibrationConfig:");
+ pw.increaseIndent();
+ pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
+ pw.println("rampStepDurationMs = " + mRampStepDurationMs);
+ pw.println("rampDownDurationMs = " + mRampDownDurationMs);
+ pw.decreaseIndent();
+ }
}
diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java
index 9a19ed4..3b286a7 100644
--- a/core/java/android/os/vibrator/VibrationEffectSegment.java
+++ b/core/java/android/os/vibrator/VibrationEffectSegment.java
@@ -116,6 +116,13 @@
public abstract <T extends VibrationEffectSegment> T applyEffectStrength(int effectStrength);
/**
+ * Returns a compact version of the {@link #toString()} result for debugging purposes.
+ *
+ * @hide
+ */
+ public abstract String toDebugString();
+
+ /**
* Checks the given frequency argument is valid to represent a vibration effect frequency in
* hertz, i.e. a finite non-negative value.
*
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 54dff08..64be87b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3938,8 +3938,14 @@
<!-- Flag indicating device support for EAP SIM, AKA, AKA' -->
<bool name="config_eap_sim_based_auth_supported">true</bool>
+ <!-- How long history of recent vibrations should be kept for the dumpsys. -->
+ <integer name="config_recentVibrationsDumpSizeLimit">20</integer>
+
<!-- How long history of previous vibrations should be kept for the dumpsys. -->
- <integer name="config_previousVibrationsDumpLimit">50</integer>
+ <integer name="config_previousVibrationsDumpSizeLimit">50</integer>
+
+ <!-- How close vibration request should be when they're aggregated for dumpsys, in ms. -->
+ <integer name="config_previousVibrationsDumpAggregationTimeMillisLimit">1000</integer>
<!-- The default vibration strength, must be between 1 and 255 inclusive. -->
<integer name="config_defaultVibrationAmplitude">255</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9da0f17..3aae3ca 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2038,7 +2038,9 @@
<java-symbol type="integer" name="config_notificationsBatteryNearlyFullLevel" />
<java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="dimen" name="config_rotaryEncoderAxisScrollTickInterval" />
- <java-symbol type="integer" name="config_previousVibrationsDumpLimit" />
+ <java-symbol type="integer" name="config_recentVibrationsDumpSizeLimit" />
+ <java-symbol type="integer" name="config_previousVibrationsDumpSizeLimit" />
+ <java-symbol type="integer" name="config_previousVibrationsDumpAggregationTimeMillisLimit" />
<java-symbol type="integer" name="config_defaultVibrationAmplitude" />
<java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
<java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 851391d..10dceba 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -16,9 +16,13 @@
package com.android.wm.shell.flicker.splitscreen
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
@@ -57,6 +61,21 @@
}
@Test
+ @FlakyTest(bugId = 293578017)
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ // TODO(b/293578017) remove once that bug is resolve
+ @Test
+ @Presubmit
+ fun visibleLayersShownMoreThanOneConsecutiveEntry_withoutWallpaper() =
+ flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + listOf(
+ WALLPAPER_BBQ_WRAPPER
+ )
+ ) }
+
+ @Test
fun splitScreenDividerIsVisibleAtEnd() {
flicker.assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
index e5c124c..f1cb37e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
@@ -265,6 +265,7 @@
val dividerRegion =
layer(SPLIT_SCREEN_DIVIDER_COMPONENT)?.visibleRegion?.region
?: error("$SPLIT_SCREEN_DIVIDER_COMPONENT component not found")
+ visibleRegion(component).isNotEmpty()
visibleRegion(component)
.coversAtMost(
if (displayBounds.width > displayBounds.height) {
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index bba926d..0f1f168 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -89,7 +89,6 @@
tracyzhou@google.com
tsuji@google.com
twickham@google.com
-vadimt@google.com
victortulias@google.com
winsonc@google.com
wleshner@google.com
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index f88fc21..d84e676 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -20,7 +20,6 @@
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -28,9 +27,9 @@
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyListScope
+import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -39,6 +38,7 @@
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
@@ -134,10 +134,11 @@
)
}
- LazyColumn(
- Modifier.fillMaxWidth().sysuiResTag("scroll_view"),
- contentPadding =
- PaddingValues(
+ Column(
+ Modifier.fillMaxWidth()
+ .sysuiResTag("scroll_view")
+ .verticalScroll(rememberScrollState())
+ .padding(
top = 16.dp,
bottom = PeopleSpacePadding,
start = 8.dp,
@@ -151,7 +152,7 @@
if (recentTiles.isNotEmpty()) {
if (hasPriorityConversations) {
- item { Spacer(Modifier.height(35.dp)) }
+ Spacer(Modifier.height(35.dp))
}
ConversationList(R.string.recent_conversations, recentTiles, onTileClicked)
@@ -160,33 +161,30 @@
}
}
-private fun LazyListScope.ConversationList(
+@Composable
+private fun ConversationList(
@StringRes headerTextResource: Int,
tiles: List<PeopleTileViewModel>,
onTileClicked: (PeopleTileViewModel) -> Unit
) {
- item {
- Text(
- stringResource(headerTextResource),
- Modifier.padding(start = 16.dp),
- style = MaterialTheme.typography.labelLarge,
- color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
- )
+ Text(
+ stringResource(headerTextResource),
+ Modifier.padding(start = 16.dp),
+ style = MaterialTheme.typography.labelLarge,
+ color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
+ )
- Spacer(Modifier.height(10.dp))
- }
+ Spacer(Modifier.height(10.dp))
tiles.forEachIndexed { index, tile ->
if (index > 0) {
- item {
- Divider(
- color = LocalAndroidColorScheme.current.deprecated.colorBackground,
- thickness = 2.dp,
- )
- }
+ Divider(
+ color = LocalAndroidColorScheme.current.deprecated.colorBackground,
+ thickness = 2.dp,
+ )
}
- item(tile.key.toString()) {
+ key(tile.key.toString()) {
Tile(
tile,
onTileClicked,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 1eba667..83bec66 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -124,8 +124,7 @@
}
private fun updateServices(newServices: List<ControlsServiceInfo>) {
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS) &&
- activityTaskManagerProxy.supportsMultiWindow(context)) {
+ if (activityTaskManagerProxy.supportsMultiWindow(context)) {
val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
newServices.forEach {
it.resolvePanelActivity(allowAllApps) }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 3713811..a7e9efd8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -34,12 +34,9 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
-import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.ControlsSettingsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -60,8 +57,6 @@
private val controlsMetricsLogger: ControlsMetricsLogger,
private val vibrator: VibratorHelper,
private val controlsSettingsRepository: ControlsSettingsRepository,
- private val controlsSettingsDialogManager: ControlsSettingsDialogManager,
- private val featureFlags: FeatureFlags,
) : ControlActionCoordinator {
private var dialog: Dialog? = null
private var pendingAction: Action? = null
@@ -77,9 +72,6 @@
}
override fun closeDialogs() {
- if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- controlsSettingsDialogManager.closeDialog()
- }
val isActivityFinishing =
(activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
if (isActivityFinishing == true) {
@@ -169,7 +161,6 @@
override fun runPendingAction(controlId: String) {
if (isLocked) return
if (pendingAction?.controlId == controlId) {
- showSettingsDialogIfNeeded(pendingAction!!)
pendingAction?.invoke()
pendingAction = null
}
@@ -208,7 +199,6 @@
true
}, { pendingAction = null }, true /* afterKeyguardGone */)
} else {
- showSettingsDialogIfNeeded(action)
action.invoke()
}
}
@@ -243,15 +233,6 @@
}
}
- private fun showSettingsDialogIfNeeded(action: Action) {
- if (action.authIsRequired) {
- return
- }
- if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- controlsSettingsDialogManager.maybeShowDialog(activityContext) {}
- }
- }
-
@VisibleForTesting
fun createAction(
controlId: String,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 557dcf4..8341964 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -36,7 +36,6 @@
import com.android.systemui.controls.management.ControlsAnimations
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
@@ -66,9 +65,7 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lastConfiguration.setTo(resources.configuration)
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
- }
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
setContentView(R.layout.controls_fullscreen)
@@ -77,7 +74,7 @@
requireViewById(R.id.control_detail_root),
window,
intent,
- !featureFlags.isEnabled(Flags.USE_APP_PANELS)
+ false
)
)
@@ -114,7 +111,7 @@
parent = requireViewById(R.id.control_detail_root)
parent.alpha = 0f
- if (featureFlags.isEnabled(Flags.USE_APP_PANELS) && !keyguardStateController.isUnlocked) {
+ if (!keyguardStateController.isUnlocked) {
controlsSettingsDialogManager.maybeShowDialog(this) {
uiController.show(parent, { finishOrReturnToDream() }, this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b0dfee2..40a90fb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -62,11 +62,12 @@
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
/**
- * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
- * enable it on release builds.
+ * This flag controls whether we register a listener for StatsD notification memory reports.
+ * For statsd to actually call the listener however, a server-side toggle needs to be
+ * enabled as well.
*/
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
- unreleasedFlag(119, "notification_memory_logging_enabled")
+ releasedFlag(119, "notification_memory_logging_enabled")
// TODO(b/260335638): Tracking Bug
@JvmField
@@ -616,8 +617,6 @@
@JvmField val NOTE_TASKS = releasedFlag(1900, "keycode_flag")
// 2000 - device controls
- @Keep @JvmField val USE_APP_PANELS = releasedFlag(2000, "use_app_panels")
-
@JvmField val APP_PANELS_ALL_APPS_ALLOWED = releasedFlag(2001, "app_panels_all_apps_allowed")
@JvmField
@@ -734,4 +733,12 @@
// TODO(b/290213663): Tracking Bug
@JvmField
val ONE_WAY_HAPTICS_API_MIGRATION = unreleasedFlag(3100, "oneway_haptics_api_migration")
+
+ /** Enable the Compose implementation of the PeopleSpaceActivity. */
+ @JvmField
+ val COMPOSE_PEOPLE_SPACE = unreleasedFlag(293570761, "compose_people_space")
+
+ /** Enable the Compose implementation of the Quick Settings footer actions. */
+ @JvmField
+ val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag(293569320, "compose_qs_footer_actions")
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 7f0f894..d1d3e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -28,6 +28,8 @@
import androidx.lifecycle.ViewModelProvider;
import com.android.systemui.compose.ComposeFacade;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.people.ui.view.PeopleViewBinder;
import com.android.systemui.people.ui.viewmodel.PeopleViewModel;
@@ -43,11 +45,14 @@
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
private final PeopleViewModel.Factory mViewModelFactory;
+ private final FeatureFlags mFeatureFlags;
@Inject
- public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory) {
+ public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory,
+ FeatureFlags featureFlags) {
super();
mViewModelFactory = viewModelFactory;
+ mFeatureFlags = featureFlags;
}
@Override
@@ -67,7 +72,8 @@
return null;
};
- if (ComposeFacade.INSTANCE.isComposeAvailable()) {
+ if (mFeatureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE)
+ && ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Using the Compose implementation of the PeopleSpaceActivity");
ComposeFacade.INSTANCE.setPeopleSpaceActivityContent(this, viewModel, onResult);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index a2b2a89..d801faa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -52,6 +52,7 @@
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.ui.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSContainerController;
@@ -285,7 +286,8 @@
private void bindFooterActionsView(View root) {
LinearLayout footerActionsView = root.findViewById(R.id.qs_footer_actions);
- if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
+ if (!mFeatureFlags.isEnabled(Flags.COMPOSE_QS_FOOTER_ACTIONS)
+ || !ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Binding the View implementation of the QS footer actions");
mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
mListeningAndVisibilityLifecycleOwner);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt
new file mode 100644
index 0000000..92e9765
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.dagger
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface NotificationMemoryModule {
+
+ /** Binds memory monitor into startable map. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationMemoryMonitor::class)
+ fun bindsNotificationMemoryMonitorStartable(monitor: NotificationMemoryMonitor): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index f7bd177..106d11f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -39,7 +39,6 @@
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
import com.android.systemui.statusbar.notification.logging.NotificationLogger
-import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.wm.shell.bubbles.Bubbles
@@ -72,7 +71,6 @@
private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
private val bubblesOptional: Optional<Bubbles>,
private val fgsNotifListener: ForegroundServiceNotificationListener,
- private val memoryMonitor: Lazy<NotificationMemoryMonitor>,
private val featureFlags: FeatureFlags
) : NotificationsController {
@@ -108,7 +106,6 @@
notificationLogger.setUpWithContainer(listContainer)
peopleSpaceWidgetManager.attach(notificationListener)
fgsNotifListener.init()
- memoryMonitor.get().init()
}
// TODO: Convert all functions below this line into listeners instead of public methods
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
index f38c1e5..0fdf681 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.logging
import android.util.Log
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -32,13 +33,13 @@
private val featureFlags: FeatureFlags,
private val notificationMemoryDumper: NotificationMemoryDumper,
private val notificationMemoryLogger: Lazy<NotificationMemoryLogger>,
-) {
+) : CoreStartable {
companion object {
private const val TAG = "NotificationMemory"
}
- fun init() {
+ override fun start() {
Log.d(TAG, "NotificationMemoryMonitor initialized.")
notificationMemoryDumper.init()
if (featureFlags.isEnabled(Flags.NOTIFICATION_MEMORY_LOGGING_ENABLED)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
index 06cc96e..d696979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
@@ -46,6 +46,7 @@
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
+ setClipChildren(false);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index 38372a3..692d794 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -24,7 +24,6 @@
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -36,7 +35,6 @@
import org.mockito.Answers
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
@@ -44,6 +42,7 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import java.util.Optional
@@ -102,14 +101,11 @@
metricsLogger,
vibratorHelper,
controlsSettingsRepository,
- controlsSettingsDialogManager,
- featureFlags
))
coordinator.activityContext = mContext
`when`(cvh.cws.ci.controlId).thenReturn(ID)
`when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
- `when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(false)
action = spy(coordinator.Action(ID, {}, false, true))
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
@@ -155,13 +151,11 @@
coordinator.toggle(cvh, "", true)
verify(coordinator).bouncerOrRun(action)
- verify(controlsSettingsDialogManager).maybeShowDialog(any(), any())
verify(action).invoke()
}
@Test
fun testToggleWhenLockedDoesNotTriggerDialog_featureFlagEnabled() {
- `when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(true)
action = spy(coordinator.Action(ID, {}, false, false))
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index ee213f7..b1061ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -37,7 +37,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.APP_PANELS_ALL_APPS_ALLOWED
-import com.android.systemui.flags.Flags.USE_APP_PANELS
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.ActivityTaskManagerProxy
import com.android.systemui.util.concurrency.FakeExecutor
@@ -124,8 +123,6 @@
arrayOf(componentName.packageName)
)
- // Return true by default, we'll test the false path
- `when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(true)
// Return false by default, we'll test the true path
`when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(false)
@@ -445,34 +442,6 @@
}
@Test
- fun testActivityDefaultEnabled_flagDisabled_nullPanel() {
- `when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(false)
- val serviceInfo = ServiceInfo(
- componentName,
- activityName,
- )
-
- `when`(packageManager.getComponentEnabledSetting(eq(activityName)))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
-
- setUpQueryResult(listOf(
- ActivityInfo(
- activityName,
- enabled = true,
- exported = true,
- permission = Manifest.permission.BIND_CONTROLS
- )
- ))
-
- val list = listOf(serviceInfo)
- serviceListingCallbackCaptor.value.onServicesReloaded(list)
-
- executor.runAllReady()
-
- assertNull(controller.getCurrentServices()[0].panelActivity)
- }
-
- @Test
fun testActivityDifferentPackage_nullPanel() {
val serviceInfo = ServiceInfo(
componentName,
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 4f7f13e..fed6e7e 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.media.AudioAttributes;
import android.os.CombinedVibration;
import android.os.IBinder;
import android.os.VibrationAttributes;
@@ -27,8 +28,10 @@
import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
+import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;
+import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@@ -39,7 +42,9 @@
* The base class for all vibrations.
*/
abstract class Vibration {
- private static final SimpleDateFormat DEBUG_DATE_FORMAT =
+ private static final SimpleDateFormat DEBUG_TIME_FORMAT =
+ new SimpleDateFormat("HH:mm:ss.SSS");
+ private static final SimpleDateFormat DEBUG_DATE_TIME_FORMAT =
new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
// Used to generate globally unique vibration ids.
private static final AtomicInteger sNextVibrationId = new AtomicInteger(1); // 0 = no callback
@@ -146,10 +151,10 @@
@Override
public String toString() {
return "CallerInfo{"
- + " attrs=" + attrs
- + ", uid=" + uid
- + ", displayId=" + displayId
+ + " uid=" + uid
+ ", opPkg=" + opPkg
+ + ", displayId=" + displayId
+ + ", attrs=" + attrs
+ ", reason=" + reason
+ '}';
}
@@ -203,14 +208,17 @@
* potentially expensive or resource-linked objects, such as {@link IBinder}.
*/
static final class DebugInfo {
- private final long mCreateTime;
+ final long mCreateTime;
+ final CallerInfo mCallerInfo;
+ @Nullable
+ final CombinedVibration mPlayedEffect;
+
private final long mStartTime;
private final long mEndTime;
private final long mDurationMs;
- @Nullable private final CombinedVibration mOriginalEffect;
- @Nullable private final CombinedVibration mPlayedEffect;
+ @Nullable
+ private final CombinedVibration mOriginalEffect;
private final float mScale;
- private final CallerInfo mCallerInfo;
private final Status mStatus;
DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration playedEffect,
@@ -230,10 +238,10 @@
@Override
public String toString() {
- return "createTime: " + DEBUG_DATE_FORMAT.format(new Date(mCreateTime))
- + ", startTime: " + DEBUG_DATE_FORMAT.format(new Date(mStartTime))
+ return "createTime: " + DEBUG_DATE_TIME_FORMAT.format(new Date(mCreateTime))
+ + ", startTime: " + DEBUG_DATE_TIME_FORMAT.format(new Date(mStartTime))
+ ", endTime: "
- + (mEndTime == 0 ? null : DEBUG_DATE_FORMAT.format(new Date(mEndTime)))
+ + (mEndTime == 0 ? null : DEBUG_DATE_TIME_FORMAT.format(new Date(mEndTime)))
+ ", durationMs: " + mDurationMs
+ ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
+ ", playedEffect: " + mPlayedEffect
@@ -242,8 +250,56 @@
+ ", callerInfo: " + mCallerInfo;
}
+ /**
+ * Write this info in a compact way into given {@link PrintWriter}.
+ *
+ * <p>This is used by dumpsys to log multiple vibration records in single lines that are
+ * easy to skim through by the sorted created time.
+ */
+ void dumpCompact(IndentingPrintWriter pw) {
+ boolean isExternalVibration = mPlayedEffect == null;
+ String timingsStr = String.format(Locale.ROOT,
+ "%s | %8s | %20s | duration: %5dms | start: %12s | end: %10s",
+ DEBUG_DATE_TIME_FORMAT.format(new Date(mCreateTime)),
+ isExternalVibration ? "external" : "effect",
+ mStatus.name().toLowerCase(Locale.ROOT),
+ mDurationMs,
+ mStartTime == 0 ? "" : DEBUG_TIME_FORMAT.format(new Date(mStartTime)),
+ mEndTime == 0 ? "" : DEBUG_TIME_FORMAT.format(new Date(mEndTime)));
+ String callerInfoStr = String.format(Locale.ROOT,
+ " | %s (uid=%d, displayId=%d) | usage: %s (audio=%s) | flags: %s | reason: %s",
+ mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.displayId,
+ mCallerInfo.attrs.usageToString(),
+ AudioAttributes.usageToString(mCallerInfo.attrs.getAudioUsage()),
+ Long.toBinaryString(mCallerInfo.attrs.getFlags()),
+ mCallerInfo.reason);
+ String effectStr = String.format(Locale.ROOT,
+ " | played: %s | original: %s | scale: %.2f",
+ mPlayedEffect == null ? null : mPlayedEffect.toDebugString(),
+ mOriginalEffect == null ? null : mOriginalEffect.toDebugString(),
+ mScale);
+ pw.println(timingsStr + callerInfoStr + effectStr);
+ }
+
+ /** Write this info into given {@link PrintWriter}. */
+ void dump(IndentingPrintWriter pw) {
+ pw.println("Vibration:");
+ pw.increaseIndent();
+ pw.println("status = " + mStatus.name().toLowerCase(Locale.ROOT));
+ pw.println("durationMs = " + mDurationMs);
+ pw.println("createTime = " + DEBUG_DATE_TIME_FORMAT.format(new Date(mCreateTime)));
+ pw.println("startTime = " + DEBUG_DATE_TIME_FORMAT.format(new Date(mStartTime)));
+ pw.println("endTime = "
+ + (mEndTime == 0 ? null : DEBUG_DATE_TIME_FORMAT.format(new Date(mEndTime))));
+ pw.println("playedEffect = " + mPlayedEffect);
+ pw.println("originalEffect = " + mOriginalEffect);
+ pw.println("scale = " + String.format(Locale.ROOT, "%.2f", mScale));
+ pw.println("callerInfo = " + mCallerInfo);
+ pw.decreaseIndent();
+ }
+
/** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
- public void dumpProto(ProtoOutputStream proto, long fieldId) {
+ void dump(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(VibrationProto.START_TIME, mStartTime);
proto.write(VibrationProto.END_TIME, mEndTime);
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index dbd6bf4..db8a9ae 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -54,6 +54,7 @@
import android.os.Vibrator.VibrationIntensity;
import android.os.vibrator.VibrationConfig;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -65,6 +66,7 @@
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -601,8 +603,32 @@
}
}
+ /** Write current settings into given {@link PrintWriter}. */
+ void dump(IndentingPrintWriter pw) {
+ pw.println("VibrationSettings:");
+ pw.increaseIndent();
+ pw.println("vibrateOn = " + mVibrateOn);
+ pw.println("vibrateInputDevices = " + mVibrateInputDevices);
+ pw.println("batterySaverMode = " + mBatterySaverMode);
+ pw.println("VibrationIntensities:");
+
+ pw.increaseIndent();
+ for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) {
+ int usage = mCurrentVibrationIntensities.keyAt(i);
+ int intensity = mCurrentVibrationIntensities.valueAt(i);
+ pw.println(VibrationAttributes.usageToString(usage) + " = "
+ + intensityToString(intensity)
+ + ", default: " + intensityToString(getDefaultIntensity(usage)));
+ }
+ pw.decreaseIndent();
+
+ mVibrationConfig.dumpWithoutDefaultSettings(pw);
+ pw.println("processStateCache = " + mUidObserver.mProcStatesCache);
+ pw.decreaseIndent();
+ }
+
/** Write current settings into given {@link ProtoOutputStream}. */
- public void dumpProto(ProtoOutputStream proto) {
+ void dump(ProtoOutputStream proto) {
synchronized (mLock) {
proto.write(VibratorManagerServiceDumpProto.VIBRATE_ON, mVibrateOn);
proto.write(VibratorManagerServiceDumpProto.LOW_POWER_MODE, mBatterySaverMode);
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 47b3e1a..f5d4d1e 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -17,6 +17,7 @@
package com.android.server.vibrator;
import android.annotation.Nullable;
+import android.annotation.Nullable;
import android.hardware.vibrator.IVibrator;
import android.os.Binder;
import android.os.IVibratorStateListener;
@@ -26,6 +27,7 @@
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.RampSegment;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -351,6 +353,19 @@
+ '}';
}
+ void dump(IndentingPrintWriter pw) {
+ pw.println("VibratorController:");
+ pw.increaseIndent();
+ pw.println("isVibrating = " + mIsVibrating);
+ pw.println("isUnderExternalControl = " + mIsUnderExternalControl);
+ pw.println("currentAmplitude = " + mCurrentAmplitude);
+ pw.println("vibratorInfoLoadSuccessful = " + mVibratorInfoLoadSuccessful);
+ pw.println("vibratorStateListenerCount = "
+ + mVibratorStateListeners.getRegisteredCallbackCount());
+ mVibratorInfo.dump(pw);
+ pw.decreaseIndent();
+ }
+
@GuardedBy("mLock")
private void notifyListenerOnVibrating(boolean isVibrating) {
if (mIsVibrating != isVibrating) {
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 6fdb1db..270f7f0c 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -56,6 +56,7 @@
import android.os.vibrator.VibrationEffectSegment;
import android.os.vibrator.persistence.VibrationXmlParser;
import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
@@ -80,6 +81,7 @@
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -204,9 +206,15 @@
mNativeWrapper = injector.getNativeWrapper();
mNativeWrapper.init(listener);
- int dumpLimit = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_previousVibrationsDumpLimit);
- mVibratorManagerRecords = new VibratorManagerRecords(dumpLimit);
+ int recentDumpSizeLimit = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_recentVibrationsDumpSizeLimit);
+ int dumpSizeLimit = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_previousVibrationsDumpSizeLimit);
+ int dumpAggregationTimeLimit = mContext.getResources().getInteger(
+ com.android.internal.R.integer
+ .config_previousVibrationsDumpAggregationTimeMillisLimit);
+ mVibratorManagerRecords = new VibratorManagerRecords(
+ recentDumpSizeLimit, dumpSizeLimit, dumpAggregationTimeLimit);
mBatteryStatsService = injector.getBatteryStatsService();
mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler);
@@ -544,49 +552,74 @@
}
}
- private void dumpText(PrintWriter pw) {
+ private void dumpText(PrintWriter w) {
if (DEBUG) {
Slog.d(TAG, "Dumping vibrator manager service to text...");
}
+ IndentingPrintWriter pw = new IndentingPrintWriter(w, /* singleIndent= */ " ");
synchronized (mLock) {
pw.println("Vibrator Manager Service:");
- pw.println(" mVibrationSettings:");
- pw.println(" " + mVibrationSettings);
+ pw.increaseIndent();
+
+ mVibrationSettings.dump(pw);
pw.println();
- pw.println(" mVibratorControllers:");
+
+ pw.println("VibratorControllers:");
+ pw.increaseIndent();
for (int i = 0; i < mVibrators.size(); i++) {
- pw.println(" " + mVibrators.valueAt(i));
+ mVibrators.valueAt(i).dump(pw);
}
+ pw.decreaseIndent();
pw.println();
- pw.println(" mCurrentVibration:");
- pw.println(" " + (mCurrentVibration == null
- ? null : mCurrentVibration.getVibration().getDebugInfo()));
+
+ pw.println("CurrentVibration:");
+ pw.increaseIndent();
+ if (mCurrentVibration != null) {
+ mCurrentVibration.getVibration().getDebugInfo().dump(pw);
+ } else {
+ pw.println("null");
+ }
+ pw.decreaseIndent();
pw.println();
- pw.println(" mNextVibration:");
- pw.println(" " + (mNextVibration == null
- ? null : mNextVibration.getVibration().getDebugInfo()));
+
+ pw.println("NextVibration:");
+ pw.increaseIndent();
+ if (mNextVibration != null) {
+ mNextVibration.getVibration().getDebugInfo().dump(pw);
+ } else {
+ pw.println("null");
+ }
+ pw.decreaseIndent();
pw.println();
- pw.println(" mCurrentExternalVibration:");
- pw.println(" " + (mCurrentExternalVibration == null
- ? null : mCurrentExternalVibration.getDebugInfo()));
- pw.println();
+
+ pw.println("CurrentExternalVibration:");
+ pw.increaseIndent();
+ if (mCurrentExternalVibration != null) {
+ mCurrentExternalVibration.getDebugInfo().dump(pw);
+ } else {
+ pw.println("null");
+ }
+ pw.decreaseIndent();
}
- mVibratorManagerRecords.dumpText(pw);
+
+ pw.println();
+ pw.println();
+ mVibratorManagerRecords.dump(pw);
}
- synchronized void dumpProto(FileDescriptor fd) {
+ private void dumpProto(FileDescriptor fd) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
if (DEBUG) {
Slog.d(TAG, "Dumping vibrator manager service to proto...");
}
synchronized (mLock) {
- mVibrationSettings.dumpProto(proto);
+ mVibrationSettings.dump(proto);
if (mCurrentVibration != null) {
- mCurrentVibration.getVibration().getDebugInfo().dumpProto(proto,
+ mCurrentVibration.getVibration().getDebugInfo().dump(proto,
VibratorManagerServiceDumpProto.CURRENT_VIBRATION);
}
if (mCurrentExternalVibration != null) {
- mCurrentExternalVibration.getDebugInfo().dumpProto(proto,
+ mCurrentExternalVibration.getDebugInfo().dump(proto,
VibratorManagerServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
}
@@ -601,7 +634,7 @@
proto.write(VibratorManagerServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
isUnderExternalControl);
}
- mVibratorManagerRecords.dumpProto(proto);
+ mVibratorManagerRecords.dump(proto);
proto.flush();
}
@@ -1581,64 +1614,105 @@
/** Keep records of vibrations played and provide debug information for this service. */
private static final class VibratorManagerRecords {
- private final SparseArray<LinkedList<Vibration.DebugInfo>> mPreviousVibrations =
- new SparseArray<>();
- private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations =
- new LinkedList<>();
- private final int mPreviousVibrationsLimit;
+ private final VibrationRecords mAggregatedVibrationHistory;
+ private final VibrationRecords mRecentVibrations;
- VibratorManagerRecords(int limit) {
- mPreviousVibrationsLimit = limit;
+ VibratorManagerRecords(int recentVibrationSizeLimit, int aggregationSizeLimit,
+ int aggregationTimeLimit) {
+ mAggregatedVibrationHistory =
+ new VibrationRecords(aggregationSizeLimit, aggregationTimeLimit);
+ mRecentVibrations = new VibrationRecords(
+ recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0);
}
synchronized void record(HalVibration vib) {
- int usage = vib.callerInfo.attrs.getUsage();
- if (!mPreviousVibrations.contains(usage)) {
- mPreviousVibrations.put(usage, new LinkedList<>());
- }
- record(mPreviousVibrations.get(usage), vib.getDebugInfo());
+ record(vib.getDebugInfo());
}
synchronized void record(ExternalVibrationHolder vib) {
- record(mPreviousExternalVibrations, vib.getDebugInfo());
+ record(vib.getDebugInfo());
}
- synchronized void record(LinkedList<Vibration.DebugInfo> records,
- Vibration.DebugInfo info) {
- if (records.size() > mPreviousVibrationsLimit) {
- records.removeFirst();
+ private synchronized void record(Vibration.DebugInfo info) {
+ AggregatedVibrationRecord removedRecord = mRecentVibrations.record(info);
+ if (removedRecord != null) {
+ mAggregatedVibrationHistory.record(removedRecord.mLatestVibration);
}
- records.addLast(info);
}
- synchronized void dumpText(PrintWriter pw) {
- for (int i = 0; i < mPreviousVibrations.size(); i++) {
- pw.println();
- pw.print(" Previous vibrations for usage ");
- pw.print(VibrationAttributes.usageToString(mPreviousVibrations.keyAt(i)));
- pw.println(":");
- for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
- pw.println(" " + info);
+ synchronized void dump(IndentingPrintWriter pw) {
+ pw.println("Recent vibrations:");
+ pw.increaseIndent();
+ mRecentVibrations.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+ pw.println();
+
+ pw.println("Aggregated vibration history:");
+ pw.increaseIndent();
+ mAggregatedVibrationHistory.dump(pw);
+ pw.decreaseIndent();
+ }
+
+ synchronized void dump(ProtoOutputStream proto) {
+ mRecentVibrations.dump(proto);
+ }
+ }
+
+ /** Keep records of vibrations played and provide debug information for this service. */
+ private static final class VibrationRecords {
+ private final SparseArray<LinkedList<AggregatedVibrationRecord>> mVibrations =
+ new SparseArray<>();
+ private final int mSizeLimit;
+ private final int mAggregationTimeLimit;
+
+ VibrationRecords(int sizeLimit, int aggregationTimeLimit) {
+ mSizeLimit = sizeLimit;
+ mAggregationTimeLimit = aggregationTimeLimit;
+ }
+
+ synchronized AggregatedVibrationRecord record(Vibration.DebugInfo info) {
+ int usage = info.mCallerInfo.attrs.getUsage();
+ if (!mVibrations.contains(usage)) {
+ mVibrations.put(usage, new LinkedList<>());
+ }
+ LinkedList<AggregatedVibrationRecord> records = mVibrations.get(usage);
+ if (mAggregationTimeLimit > 0 && !records.isEmpty()) {
+ AggregatedVibrationRecord lastRecord = records.getLast();
+ if (lastRecord.mayAggregate(info, mAggregationTimeLimit)) {
+ lastRecord.record(info);
+ return null;
}
}
+ AggregatedVibrationRecord removedRecord = null;
+ if (records.size() > mSizeLimit) {
+ removedRecord = records.removeFirst();
+ }
+ records.addLast(new AggregatedVibrationRecord(info));
+ return removedRecord;
+ }
- pw.println();
- pw.println(" Previous external vibrations:");
- for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
- pw.println(" " + info);
+ synchronized void dump(IndentingPrintWriter pw) {
+ for (int i = 0; i < mVibrations.size(); i++) {
+ pw.println(VibrationAttributes.usageToString(mVibrations.keyAt(i)) + ":");
+ pw.increaseIndent();
+ for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
+ info.dump(pw);
+ }
+ pw.decreaseIndent();
+ pw.println();
}
}
- synchronized void dumpProto(ProtoOutputStream proto) {
- for (int i = 0; i < mPreviousVibrations.size(); i++) {
+ synchronized void dump(ProtoOutputStream proto) {
+ for (int i = 0; i < mVibrations.size(); i++) {
long fieldId;
- switch (mPreviousVibrations.keyAt(i)) {
+ switch (mVibrations.keyAt(i)) {
case VibrationAttributes.USAGE_RINGTONE:
fieldId = VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS;
break;
case VibrationAttributes.USAGE_NOTIFICATION:
- fieldId = VibratorManagerServiceDumpProto
- .PREVIOUS_NOTIFICATION_VIBRATIONS;
+ fieldId = VibratorManagerServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS;
break;
case VibrationAttributes.USAGE_ALARM:
fieldId = VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS;
@@ -1646,18 +1720,70 @@
default:
fieldId = VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS;
}
- for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
- info.dumpProto(proto, fieldId);
+ for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
+ if (info.mLatestVibration.mPlayedEffect == null) {
+ // External vibrations are reported separately in the dump proto
+ info.dump(proto,
+ VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
+ } else {
+ info.dump(proto, fieldId);
+ }
}
}
+ }
- for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
- info.dumpProto(proto,
- VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
+ synchronized void dumpOnSingleField(ProtoOutputStream proto, long fieldId) {
+ for (int i = 0; i < mVibrations.size(); i++) {
+ for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
+ info.dump(proto, fieldId);
+ }
}
}
}
+ /**
+ * Record that keeps the last {@link Vibration.DebugInfo} played, aggregating close vibrations
+ * from the same uid that have the same {@link VibrationAttributes} and {@link VibrationEffect}.
+ */
+ private static final class AggregatedVibrationRecord {
+ private final Vibration.DebugInfo mFirstVibration;
+ private Vibration.DebugInfo mLatestVibration;
+ private int mVibrationCount;
+
+ AggregatedVibrationRecord(Vibration.DebugInfo info) {
+ mLatestVibration = mFirstVibration = info;
+ mVibrationCount = 1;
+ }
+
+ synchronized boolean mayAggregate(Vibration.DebugInfo info, long timeLimit) {
+ return Objects.equals(mLatestVibration.mCallerInfo.uid, info.mCallerInfo.uid)
+ && Objects.equals(mLatestVibration.mCallerInfo.attrs, info.mCallerInfo.attrs)
+ && Objects.equals(mLatestVibration.mPlayedEffect, info.mPlayedEffect)
+ && Math.abs(mLatestVibration.mCreateTime - info.mCreateTime) < timeLimit;
+ }
+
+ synchronized void record(Vibration.DebugInfo vib) {
+ mLatestVibration = vib;
+ mVibrationCount++;
+ }
+
+ synchronized void dump(IndentingPrintWriter pw) {
+ mFirstVibration.dumpCompact(pw);
+ if (mVibrationCount == 1) {
+ return;
+ }
+ if (mVibrationCount > 2) {
+ pw.println(
+ "-> Skipping " + (mVibrationCount - 2) + " aggregated vibrations, latest:");
+ }
+ mLatestVibration.dumpCompact(pw);
+ }
+
+ synchronized void dump(ProtoOutputStream proto, long fieldId) {
+ mLatestVibration.dump(proto, fieldId);
+ }
+ }
+
/** Clears mNextVibration if set, ending it cleanly */
@GuardedBy("mLock")
private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
@@ -1676,7 +1802,7 @@
/**
* Ends the external vibration, and clears related service state.
*
- * @param vibrationEndInfo the status and related info to end the associated Vibration with
+ * @param vibrationEndInfo the status and related info to end the associated Vibration
* @param continueExternalControl indicates whether external control will continue. If not, the
* HAL will have external control turned off.
*/
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index e739033..54995fb 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -1005,6 +1005,7 @@
mVibratorProviders.get(3).getEffectSegments(vibrationId));
}
+ @FlakyTest
@Test
public void vibrate_multipleSyncedCallbackTriggered_finishSteps() throws Exception {
int[] vibratorIds = new int[]{1, 2};
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 063e2c3..e0fb751 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -93,7 +93,7 @@
* Checks that the [ComponentNameMatcher.NAV_BAR] starts the transition invisible, then becomes
* visible during the unlocking animation and remains visible at the end of the transition
*/
- @Presubmit
+ @FlakyTest(bugId = 293581770)
@Test
fun navBarWindowsVisibilityChanges() {
Assume.assumeFalse(flicker.scenario.isTablet)