Merge "Add uwb to ApiDocs.bp"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index 1f0900d..8f7cda9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
@@ -499,7 +499,7 @@
mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now, stopReason);
}
rebatchIfNeeded(now);
- addEvent(job.getJob().isPeriodic() ? EVENT_STOP_JOB : EVENT_STOP_PERIODIC_JOB,
+ addEvent(job.getJob().isPeriodic() ? EVENT_STOP_PERIODIC_JOB : EVENT_STOP_JOB,
job.getSourceUid(), job.getBatteryName(), job.getJobId(), stopReason, debugReason);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5be85b0..30160c3 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -243,7 +243,8 @@
private static native void nativeRemoveJankDataListener(long nativeListener);
private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener);
private static native int nativeGetGPUContextPriority();
- private static native void nativeSetTransformHint(long nativeObject, int transformHint);
+ private static native void nativeSetTransformHint(long nativeObject,
+ @SurfaceControl.BufferTransform int transformHint);
private static native int nativeGetTransformHint(long nativeObject);
private static native int nativeGetLayerId(long nativeObject);
private static native void nativeAddTransactionCommittedListener(long nativeObject,
@@ -3753,7 +3754,7 @@
/**
* @hide
*/
- public int getTransformHint() {
+ public @SurfaceControl.BufferTransform int getTransformHint() {
checkNotReleased();
return nativeGetTransformHint(mNativeObject);
}
@@ -3767,7 +3768,7 @@
* with the same size.
* @hide
*/
- public void setTransformHint(@Surface.Rotation int transformHint) {
+ public void setTransformHint(@SurfaceControl.BufferTransform int transformHint) {
nativeSetTransformHint(mNativeObject, transformHint);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b5f108c..1c44f443 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -214,7 +214,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- int mTransformHint = 0;
+ @SurfaceControl.BufferTransform int mTransformHint = 0;
private boolean mGlobalListenersAdded;
private boolean mAttachedToWindow;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b9c216d..cddf9ee 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -314,7 +314,8 @@
private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
new ArrayList<>();
- private @Surface.Rotation int mPreviousTransformHint = Surface.ROTATION_0;
+ private @SurfaceControl.BufferTransform
+ int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
/**
* Callback for notifying about global configuration changes.
*/
@@ -7855,8 +7856,7 @@
int transformHint = mSurfaceControl.getTransformHint();
if (mPreviousTransformHint != transformHint) {
mPreviousTransformHint = transformHint;
- dispatchTransformHintChanged(
- SurfaceControl.rotationToBufferTransform(transformHint));
+ dispatchTransformHintChanged(transformHint);
}
} else {
destroySurface();
@@ -10464,7 +10464,7 @@
@Override
public @SurfaceControl.BufferTransform int getBufferTransformHint() {
- return SurfaceControl.rotationToBufferTransform(mSurfaceControl.getTransformHint());
+ return mSurfaceControl.getTransformHint();
}
@Override
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 5950e9f..aec910b 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -136,6 +136,11 @@
/** @hide */
public static final int TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN = 0x00000020;
/**
+ * The parameter which indicates if the activity has finished drawing.
+ * @hide
+ */
+ public static final int TYPE_PARAMETER_ACTIVITY_DRAWN = 0x00000040;
+ /**
* Application is allowed to use the legacy splash screen
* @hide
*/
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index dae844f..3bc3336 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1870,16 +1870,12 @@
if (surface == nullptr) {
return;
}
- surface->setTransformHint(
- ui::Transform::toRotationFlags(static_cast<ui::Rotation>(transformHint)));
+ surface->setTransformHint(transformHint);
}
static jint nativeGetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) {
sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl));
- ui::Transform::RotationFlags transformHintRotationFlags =
- static_cast<ui::Transform::RotationFlags>(surface->getTransformHint());
-
- return toRotationInt(ui::Transform::toRotation((transformHintRotationFlags)));
+ return surface->getTransformHint();
}
static jint nativeGetLayerId(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2680c31..2eb32b0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4065,7 +4065,7 @@
<string translatable="false" name="config_inCallNotificationSound">/product/media/audio/ui/InCallNotification.ogg</string>
<!-- URI for default ringtone sound file to be used for silent ringer vibration -->
- <string translatable="false" name="config_defaultRingtoneVibrationSound">/product/media/audio/ui/AttentionalHaptics.ogg</string>
+ <string translatable="false" name="config_defaultRingtoneVibrationSound"></string>
<!-- Default number of notifications from the same app before they are automatically grouped by the OS -->
<integer translatable="false" name="config_autoGroupAtCount">4</integer>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index bde2b5f..05ba74a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -23,6 +23,7 @@
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
@@ -41,7 +42,7 @@
/**
* Algorithm for determining the type of a new starting window on handheld devices.
- * At the moment also used on Android Auto.
+ * At the moment also used on Android Auto and Wear OS.
*/
public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm {
private static final String TAG = PhoneStartingWindowTypeAlgorithm.class.getSimpleName();
@@ -58,6 +59,7 @@
(parameter & TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN) != 0;
final boolean legacySplashScreen =
((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0);
+ final boolean activityDrawn = (parameter & TYPE_PARAMETER_ACTIVITY_DRAWN) != 0;
final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME;
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
@@ -68,11 +70,14 @@
+ " activityCreated:" + activityCreated
+ " useEmptySplashScreen:" + useEmptySplashScreen
+ " legacySplashScreen:" + legacySplashScreen
+ + " activityDrawn:" + activityDrawn
+ " topIsHome:" + topIsHome);
}
if (!topIsHome) {
- if (!processRunning || newTask || (taskSwitch && !activityCreated)) {
+ if (!processRunning
+ || newTask
+ || (taskSwitch && (!activityCreated || !activityDrawn))) {
return useEmptySplashScreen
? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
: legacySplashScreen
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 28c6166..87a9825 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -51,7 +51,7 @@
android:id="@+id/lockscreen_clock_view_large"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/keyguard_status_area"
+ android:layout_below="@id/keyguard_slice_view"
android:visibility="gone">
<com.android.keyguard.AnimatableClockView
android:id="@+id/animatable_clock_view_large"
@@ -68,19 +68,28 @@
lockScreenWeight="400"
/>
</FrameLayout>
- <include layout="@layout/keyguard_status_area"
+
+ <!-- Not quite optimal but needed to translate these items as a group. The
+ NotificationIconContainer has its own logic for translation. -->
+ <LinearLayout
android:id="@+id/keyguard_status_area"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:layout_below="@id/lockscreen_clock_view" />
+ android:layout_below="@id/lockscreen_clock_view">
- <com.android.systemui.statusbar.phone.NotificationIconContainer
- android:id="@+id/left_aligned_notification_icon_container"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_shelf_height"
- android:layout_below="@id/keyguard_status_area"
- android:paddingStart="@dimen/below_clock_padding_start_icons"
- android:visibility="invisible"
- />
+ <include layout="@layout/keyguard_slice_view"
+ android:id="@+id/keyguard_slice_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <com.android.systemui.statusbar.phone.NotificationIconContainer
+ android:id="@+id/left_aligned_notification_icon_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_shelf_height"
+ android:paddingStart="@dimen/below_clock_padding_start_icons"
+ android:visibility="invisible"
+ />
+ </LinearLayout>
</com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml
similarity index 89%
rename from packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
rename to packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml
index 95eb5c1..1863d11 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml
@@ -22,11 +22,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
+ android:layout_gravity="start"
android:clipToPadding="false"
android:orientation="vertical"
- android:paddingStart="@dimen/below_clock_padding_start"
- android:layout_centerHorizontal="true">
+ android:paddingStart="@dimen/below_clock_padding_start">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
@@ -42,6 +41,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:gravity="center"
+ android:gravity="start"
/>
</com.android.keyguard.KeyguardSliceView>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 14bf436..db7a0ec 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -24,9 +24,6 @@
<bool name="flag_monet">true</bool>
- <!-- AOD/Lockscreen alternate layout -->
- <bool name="flag_keyguard_layout">true</bool>
-
<!-- People Tile flag -->
<bool name="flag_conversations">false</bool>
@@ -51,7 +48,7 @@
<bool name="flag_ongoing_call_status_bar_chip">true</bool>
- <bool name="flag_ongoing_call_in_immersive">false</bool>
+ <bool name="flag_ongoing_call_in_immersive">true</bool>
<bool name="flag_ongoing_call_in_immersive_chip_tap">true</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index f81f0b9..6fd0c82 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -41,7 +41,7 @@
private static final long CLOCK_OUT_MILLIS = 150;
private static final long CLOCK_IN_MILLIS = 200;
- private static final long SMARTSPACE_MOVE_MILLIS = 350;
+ private static final long STATUS_AREA_MOVE_MILLIS = 350;
@IntDef({LARGE, SMALL})
@Retention(RetentionPolicy.SOURCE)
@@ -63,13 +63,7 @@
private AnimatableClockView mClockView;
private AnimatableClockView mLargeClockView;
- /**
- * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
- * show it below the alternate clock.
- */
- private View mKeyguardStatusArea;
- /** Mutually exclusive with mKeyguardStatusArea */
- private View mSmartspaceView;
+ private View mStatusArea;
private int mSmartspaceTopOffset;
/**
@@ -85,7 +79,7 @@
@VisibleForTesting AnimatorSet mClockInAnim = null;
@VisibleForTesting AnimatorSet mClockOutAnim = null;
- private ObjectAnimator mSmartspaceAnim = null;
+ private ObjectAnimator mStatusAreaAnim = null;
/**
* If the Keyguard Slice has a header (big center-aligned text.)
@@ -131,7 +125,7 @@
mClockView = findViewById(R.id.animatable_clock_view);
mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
mLargeClockView = findViewById(R.id.animatable_clock_view_large);
- mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
+ mStatusArea = findViewById(R.id.keyguard_status_area);
onDensityOrFontScaleChanged();
}
@@ -200,22 +194,22 @@
private void animateClockChange(boolean useLargeClock) {
if (mClockInAnim != null) mClockInAnim.cancel();
if (mClockOutAnim != null) mClockOutAnim.cancel();
- if (mSmartspaceAnim != null) mSmartspaceAnim.cancel();
+ if (mStatusAreaAnim != null) mStatusAreaAnim.cancel();
View in, out;
int direction = 1;
- float smartspaceYTranslation;
+ float statusAreaYTranslation;
if (useLargeClock) {
out = mClockFrame;
in = mLargeClockFrame;
if (indexOfChild(in) == -1) addView(in);
direction = -1;
- smartspaceYTranslation = mSmartspaceView == null ? 0
- : mClockFrame.getTop() - mSmartspaceView.getTop() + mSmartspaceTopOffset;
+ statusAreaYTranslation = mClockFrame.getTop() - mStatusArea.getTop()
+ + mSmartspaceTopOffset;
} else {
in = mClockFrame;
out = mLargeClockFrame;
- smartspaceYTranslation = 0f;
+ statusAreaYTranslation = 0f;
// Must remove in order for notifications to appear in the proper place
removeView(out);
@@ -251,18 +245,16 @@
mClockInAnim.start();
mClockOutAnim.start();
- if (mSmartspaceView != null) {
- mSmartspaceAnim = ObjectAnimator.ofFloat(mSmartspaceView, View.TRANSLATION_Y,
- smartspaceYTranslation);
- mSmartspaceAnim.setDuration(SMARTSPACE_MOVE_MILLIS);
- mSmartspaceAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mSmartspaceAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- mSmartspaceAnim = null;
- }
- });
- mSmartspaceAnim.start();
- }
+ mStatusAreaAnim = ObjectAnimator.ofFloat(mStatusArea, View.TRANSLATION_Y,
+ statusAreaYTranslation);
+ mStatusAreaAnim.setDuration(STATUS_AREA_MOVE_MILLIS);
+ mStatusAreaAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mStatusAreaAnim = null;
+ }
+ });
+ mStatusAreaAnim.start();
}
/**
@@ -352,10 +344,6 @@
}
}
- void setSmartspaceView(View smartspaceView) {
- mSmartspaceView = smartspaceView;
- }
-
void updateColors(ColorExtractor.GradientColors colors) {
mSupportsDarkText = colors.supportsDarkText();
mColorPalette = colors.getColorPalette();
@@ -369,8 +357,7 @@
pw.println(" mClockPlugin: " + mClockPlugin);
pw.println(" mClockFrame: " + mClockFrame);
pw.println(" mLargeClockFrame: " + mLargeClockFrame);
- pw.println(" mKeyguardStatusArea: " + mKeyguardStatusArea);
- pw.println(" mSmartspaceView: " + mSmartspaceView);
+ pw.println(" mStatusArea: " + mStatusArea);
pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mSupportsDarkText: " + mSupportsDarkText);
pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 4111020..01976b4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -25,7 +25,9 @@
import android.content.res.Resources;
import android.text.TextUtils;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
@@ -99,7 +101,8 @@
private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
- // If set, will replace keyguard_status_area
+ private ViewGroup mStatusArea;
+ // If set will replace keyguard_slice_view
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -191,8 +194,8 @@
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
if (mOnlyClock) {
- View ksa = mView.findViewById(R.id.keyguard_status_area);
- ksa.setVisibility(View.GONE);
+ View ksv = mView.findViewById(R.id.keyguard_slice_view);
+ ksv.setVisibility(View.GONE);
View nic = mView.findViewById(
R.id.left_aligned_notification_icon_container);
@@ -201,19 +204,18 @@
}
updateAodIcons();
+ mStatusArea = mView.findViewById(R.id.keyguard_status_area);
+
if (mSmartspaceController.isEnabled()) {
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
+ View ksv = mView.findViewById(R.id.keyguard_slice_view);
+ int ksvIndex = mStatusArea.indexOfChild(ksv);
+ ksv.setVisibility(View.GONE);
- View ksa = mView.findViewById(R.id.keyguard_status_area);
- int ksaIndex = mView.indexOfChild(ksa);
- ksa.setVisibility(View.GONE);
-
- // Place smartspace view below normal clock...
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
- lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
- mView.addView(mSmartspaceView, ksaIndex, lp);
+ mStatusArea.addView(mSmartspaceView, ksvIndex, lp);
int startPadding = getContext().getResources()
.getDimensionPixelSize(R.dimen.below_clock_padding_start);
int endPadding = getContext().getResources()
@@ -221,14 +223,6 @@
mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
updateClockLayout();
-
- View nic = mView.findViewById(
- R.id.left_aligned_notification_icon_container);
- lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
- lp.addRule(RelativeLayout.BELOW, mSmartspaceView.getId());
- nic.setLayoutParams(lp);
-
- mView.setSmartspaceView(mSmartspaceView);
mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
}
}
@@ -244,8 +238,6 @@
}
mColorExtractor.removeOnColorsChangedListener(mColorsListener);
mView.setClockPlugin(null, mStatusBarStateController.getState());
-
- mSmartspaceController.disconnect();
}
/**
@@ -328,8 +320,8 @@
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
scale, props, animate);
- if (mSmartspaceView != null) {
- PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
+ if (mStatusArea != null) {
+ PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
x, props, animate);
// If we're unlocking with the SmartSpace shared element transition, let the controller
@@ -340,7 +332,6 @@
}
mKeyguardSliceViewController.updatePosition(x, props, animate);
- mNotificationIconAreaController.updatePosition(x, props, animate);
}
/** Sets an alpha value on every child view except for the smartspace. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 428006e..9b76bab 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -33,12 +33,10 @@
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
-import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.slice.SliceItem;
@@ -85,8 +83,6 @@
private boolean mHasHeader;
private View.OnClickListener mOnClickListener;
- private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
-
public KeyguardSliceView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -136,35 +132,6 @@
}
}
- /**
- * Updates the lockscreen mode which may change the layout of the keyguard slice view.
- */
- public void updateLockScreenMode(int mode) {
- mLockScreenMode = mode;
- if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- mTitle.setPaddingRelative(0, 0, 0, 0);
- mTitle.setGravity(Gravity.START);
- setGravity(Gravity.START);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
- lp.removeRule(RelativeLayout.CENTER_HORIZONTAL);
- setLayoutParams(lp);
- } else {
- final int horizontalPaddingDpValue = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 44,
- getResources().getDisplayMetrics()
- );
- mTitle.setPaddingRelative(horizontalPaddingDpValue, 0, horizontalPaddingDpValue, 0);
- mTitle.setGravity(Gravity.CENTER_HORIZONTAL);
- setGravity(Gravity.CENTER_HORIZONTAL);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
- lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
- setLayoutParams(lp);
- }
- mRow.setLockscreenMode(mode);
- requestLayout();
- }
-
Map<View, PendingIntent> showSlice(RowContent header, List<SliceContent> subItems) {
Trace.beginSection("KeyguardSliceView#showSlice");
mHasHeader = header != null;
@@ -189,8 +156,7 @@
final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
LinearLayout.LayoutParams layoutParams = (LayoutParams) mRow.getLayoutParams();
- layoutParams.gravity = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL
- ? Gravity.START : Gravity.CENTER;
+ layoutParams.gravity = Gravity.START;
mRow.setLayoutParams(layoutParams);
for (int i = startIndex; i < subItemsCount; i++) {
@@ -224,8 +190,7 @@
final int iconSize = mHasHeader ? mIconSizeWithHeader : mIconSize;
iconDrawable = icon.getIcon().loadDrawable(mContext);
if (iconDrawable != null) {
- if ((iconDrawable instanceof InsetDrawable)
- && mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ if (iconDrawable instanceof InsetDrawable) {
// System icons (DnD) use insets which are fine for centered slice content
// but will cause a slight indent for left/right-aligned slice views
iconDrawable = ((InsetDrawable) iconDrawable).getDrawable();
@@ -321,7 +286,6 @@
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mHasHeader: " + mHasHeader);
- pw.println(" mLockScreenMode: " + mLockScreenMode);
}
@Override
@@ -332,7 +296,6 @@
public static class Row extends LinearLayout {
private Set<KeyguardSliceTextView> mKeyguardSliceTextViewSet = new HashSet();
- private int mLockScreenModeRow = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
/**
* This view is visible in AOD, which means that the device will sleep if we
@@ -407,11 +370,7 @@
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof KeyguardSliceTextView) {
- if (mLockScreenModeRow == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- ((KeyguardSliceTextView) child).setMaxWidth(Integer.MAX_VALUE);
- } else {
- ((KeyguardSliceTextView) child).setMaxWidth(width / 3);
- }
+ ((KeyguardSliceTextView) child).setMaxWidth(Integer.MAX_VALUE);
}
}
@@ -443,7 +402,6 @@
super.addView(view, index);
if (view instanceof KeyguardSliceTextView) {
- ((KeyguardSliceTextView) view).setLockScreenMode(mLockScreenModeRow);
mKeyguardSliceTextViewSet.add((KeyguardSliceTextView) view);
}
}
@@ -455,24 +413,6 @@
mKeyguardSliceTextViewSet.remove((KeyguardSliceTextView) view);
}
}
-
- /**
- * Updates the lockscreen mode which may change the layout of this view.
- */
- public void setLockscreenMode(int mode) {
- mLockScreenModeRow = mode;
- if (mLockScreenModeRow == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- setOrientation(LinearLayout.VERTICAL);
- setGravity(Gravity.START);
- } else {
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.CENTER);
- }
-
- for (KeyguardSliceTextView textView : mKeyguardSliceTextViewSet) {
- textView.setLockScreenMode(mLockScreenModeRow);
- }
- }
}
/**
@@ -480,7 +420,6 @@
*/
@VisibleForTesting
static class KeyguardSliceTextView extends TextView {
- private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@StyleRes
private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary;
@@ -509,13 +448,8 @@
boolean hasText = !TextUtils.isEmpty(getText());
int padding = (int) getContext().getResources()
.getDimension(R.dimen.widget_horizontal_padding) / 2;
- if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- // orientation is vertical, so add padding to top & bottom
- setPadding(0, padding, 0, hasText ? padding : 0);
- } else {
- // orientation is horizontal, so add padding to left & right
- setPadding(padding, 0, padding * (hasText ? 1 : -1), 0);
- }
+ // orientation is vertical, so add padding to top & bottom
+ setPadding(0, padding, 0, hasText ? padding : 0);
setCompoundDrawablePadding((int) mContext.getResources()
.getDimension(R.dimen.widget_icon_padding));
@@ -543,18 +477,5 @@
}
}
}
-
- /**
- * Updates the lockscreen mode which may change the layout of this view.
- */
- public void setLockScreenMode(int mode) {
- mLockScreenMode = mode;
- if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- } else {
- setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
- }
- updatePadding();
- }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 4a56773..d05cc4e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -73,7 +73,6 @@
private Uri mKeyguardSliceUri;
private Slice mSlice;
private Map<View, PendingIntent> mClickActions;
- private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);
@@ -137,7 +136,6 @@
TAG + "@" + Integer.toHexString(
KeyguardSliceViewController.this.hashCode()),
KeyguardSliceViewController.this);
- mView.updateLockScreenMode(mLockScreenMode);
}
@Override
@@ -160,14 +158,6 @@
}
/**
- * Updates the lockscreen mode which may change the layout of the keyguard slice view.
- */
- public void updateLockScreenMode(int mode) {
- mLockScreenMode = mode;
- mView.updateLockScreenMode(mLockScreenMode);
- }
-
- /**
* Sets the slice provider Uri.
*/
public void setupUri(String uriString) {
@@ -249,6 +239,5 @@
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mSlice: " + mSlice);
pw.println(" mClickActions: " + mClickActions);
- pw.println(" mLockScreenMode: " + mLockScreenMode);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 2362a1a..a72a050e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -88,7 +88,7 @@
mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
}
- mKeyguardSlice = findViewById(R.id.keyguard_status_area);
+ mKeyguardSlice = findViewById(R.id.keyguard_slice_view);
mTextColor = mClockView.getCurrentTextColor();
mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 682b217..60af66ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -252,11 +252,6 @@
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@Override
- public void onLockScreenModeChanged(int mode) {
- mKeyguardSliceViewController.updateLockScreenMode(mode);
- }
-
- @Override
public void onTimeChanged() {
refreshTime();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e9d0575..5707fa7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -188,9 +188,6 @@
private static final int MSG_TIME_FORMAT_UPDATE = 344;
private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
- public static final int LOCK_SCREEN_MODE_NORMAL = 0;
- public static final int LOCK_SCREEN_MODE_LAYOUT_1 = 1;
-
/** Biometric authentication state: Not listening. */
private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -1867,9 +1864,6 @@
case MSG_KEYGUARD_GOING_AWAY:
handleKeyguardGoingAway((boolean) msg.obj);
break;
- case MSG_LOCK_SCREEN_MODE:
- handleLockScreenMode();
- break;
case MSG_TIME_FORMAT_UPDATE:
handleTimeFormatUpdate((String) msg.obj);
break;
@@ -2011,8 +2005,6 @@
}
}
- updateLockScreenMode(featureFlags.isKeyguardLayoutEnabled());
-
mTimeFormatChangeObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -2028,14 +2020,6 @@
false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
}
- private void updateLockScreenMode(boolean isEnabled) {
- final int newMode = isEnabled ? LOCK_SCREEN_MODE_LAYOUT_1 : LOCK_SCREEN_MODE_NORMAL;
- if (newMode != mLockScreenMode) {
- mLockScreenMode = newMode;
- mHandler.sendEmptyMessage(MSG_LOCK_SCREEN_MODE);
- }
- }
-
private void updateUdfpsEnrolled(int userId) {
mIsUdfpsEnrolled = mAuthController.isUdfpsEnrolled(userId);
}
@@ -2666,20 +2650,6 @@
}
/**
- * Handle {@link #MSG_LOCK_SCREEN_MODE}
- */
- private void handleLockScreenMode() {
- Assert.isMainThread();
- if (DEBUG) Log.d(TAG, "handleLockScreenMode(" + mLockScreenMode + ")");
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onLockScreenModeChanged(mLockScreenMode);
- }
- }
- }
-
- /**
* Handle (@line #MSG_TIMEZONE_UPDATE}
*/
private void handleTimeZoneUpdate(String timeZone) {
@@ -3057,7 +3027,6 @@
callback.onKeyguardOccludedChanged(mKeyguardOccluded);
callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
callback.onTelephonyCapable(mTelephonyCapable);
- callback.onLockScreenModeChanged(mLockScreenMode);
for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
final SimData state = data.getValue();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index e970a86..12431984 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -325,11 +325,6 @@
public void onSecondaryLockscreenRequirementChanged(int userId) { }
/**
- * Called to switch lock screen layout/clock layouts
- */
- public void onLockScreenModeChanged(int mode) { }
-
- /**
* Called when notifying user to unlock in order to use NFC.
*/
public void onRequireUnlockForNfc() { }
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
index 1d51e59..b8841ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
@@ -34,6 +34,6 @@
@Provides
static KeyguardSliceView getKeyguardSliceView(KeyguardClockSwitch keyguardClockSwitch) {
- return keyguardClockSwitch.findViewById(R.id.keyguard_status_area);
+ return keyguardClockSwitch.findViewById(R.id.keyguard_slice_view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index 5b9ccd6..2e30e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -94,10 +94,6 @@
return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
}
- public boolean isKeyguardLayoutEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
- }
-
/** */
public boolean useNewLockscreenAnimations() {
return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 84c5a57..72601e9 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -111,6 +111,17 @@
return factory.create("CollapsedSbFragmentLog", 20);
}
+ /**
+ * Provides a logging buffer for logs related to swiping away the status bar while in immersive
+ * mode. See {@link com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureLogger}.
+ */
+ @Provides
+ @SysUISingleton
+ @SwipeStatusBarAwayLog
+ public static LogBuffer provideSwipeAwayGestureLogBuffer(LogBufferFactory factory) {
+ return factory.create("SwipeStatusBarAwayLog", 30);
+ }
+
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java
new file mode 100644
index 0000000..dd68375
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link LogBuffer} for
+ * {@link com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureLogger}.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface SwipeStatusBarAwayLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 4f932a3..9ba846d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -147,7 +147,6 @@
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
private String mMessageToShowOnScreenOn;
- protected int mLockScreenMode;
private boolean mInited;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -863,11 +862,6 @@
public static final int HIDE_DELAY_MS = 5000;
@Override
- public void onLockScreenModeChanged(int mode) {
- mLockScreenMode = mode;
- }
-
- @Override
public void onRefreshBatteryInfo(BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 5758ba4..d297d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.commandline.CommandRegistry;
+import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -69,7 +70,6 @@
import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
-import com.android.systemui.statusbar.phone.ongoingcall.SwipeStatusBarAwayGestureHandler;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index c97cf14..80577ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone.ongoingcall
+package com.android.systemui.statusbar.gesture
import android.content.Context
import android.os.Looper
-import android.util.Log
import android.view.Choreographer
import android.view.Display
import android.view.InputEvent
@@ -38,6 +37,7 @@
open class SwipeStatusBarAwayGestureHandler @Inject constructor(
context: Context,
private val statusBarWindowController: StatusBarWindowController,
+ private val logger: SwipeStatusBarAwayGestureLogger
) {
/**
@@ -53,7 +53,6 @@
private var inputMonitor: InputMonitorCompat? = null
private var inputReceiver: InputChannelCompat.InputEventReceiver? = null
- // TODO(b/195839150): Update this threshold when the config changes?
private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
com.android.internal.R.dimen.system_gestures_start_threshold
)
@@ -84,12 +83,10 @@
ACTION_DOWN -> {
if (
// Gesture starts just below the status bar
- // TODO(b/195839150): Is [statusBarHeight] the correct dimension to use for
- // determining which down touches are valid?
ev.y >= statusBarWindowController.statusBarHeight
&& ev.y <= 3 * statusBarWindowController.statusBarHeight
) {
- Log.d(TAG, "Beginning gesture detection, y=${ev.y}")
+ logger.logGestureDetectionStarted(ev.y.toInt())
startY = ev.y
startTime = ev.eventTime
monitoringCurrentTouch = true
@@ -109,12 +106,15 @@
// Gesture completed quickly enough
&& (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
) {
- Log.i(TAG, "Gesture detected; notifying callbacks")
- callbacks.values.forEach { it.invoke() }
monitoringCurrentTouch = false
+ logger.logGestureDetected(ev.y.toInt())
+ callbacks.values.forEach { it.invoke() }
}
}
ACTION_CANCEL, ACTION_UP -> {
+ if (monitoringCurrentTouch) {
+ logger.logGestureDetectionEndedWithoutTriggering(ev.y.toInt())
+ }
monitoringCurrentTouch = false
}
}
@@ -124,7 +124,7 @@
private fun startGestureListening() {
stopGestureListening()
- if (DEBUG) { Log.d(TAG, "Input listening started") }
+ logger.logInputListeningStarted()
inputMonitor = InputMonitorCompat(TAG, Display.DEFAULT_DISPLAY).also {
inputReceiver = it.getInputReceiver(
Looper.getMainLooper(),
@@ -137,7 +137,7 @@
/** Stop listening for the swipe gesture. */
private fun stopGestureListening() {
inputMonitor?.let {
- if (DEBUG) { Log.d(TAG, "Input listening stopped") }
+ logger.logInputListeningStopped()
inputMonitor = null
it.dispose()
}
@@ -150,4 +150,3 @@
private const val SWIPE_TIMEOUT_MS: Long = 500
private val TAG = SwipeStatusBarAwayGestureHandler::class.simpleName
-private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt
new file mode 100644
index 0000000..17feaa8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.gesture
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.SwipeStatusBarAwayLog
+import javax.inject.Inject
+
+/** Log messages for [SwipeStatusBarAwayGestureHandler]. */
+class SwipeStatusBarAwayGestureLogger @Inject constructor(
+ @SwipeStatusBarAwayLog private val buffer: LogBuffer
+) {
+ fun logGestureDetectionStarted(y: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = y },
+ { "Beginning gesture detection. y=$int1" }
+ )
+ }
+
+ fun logGestureDetectionEndedWithoutTriggering(y: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = y },
+ { "Gesture finished; no swipe up gesture detected. Final y=$int1" }
+ )
+ }
+
+ fun logGestureDetected(y: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { int1 = y },
+ { "Gesture detected; notifying callbacks. y=$int1" }
+ )
+ }
+
+ fun logInputListeningStarted() {
+ buffer.log(TAG, LogLevel.VERBOSE, {}, { "Input listening started "})
+ }
+
+ fun logInputListeningStopped() {
+ buffer.log(TAG, LogLevel.VERBOSE, {}, { "Input listening stopped "})
+ }
+}
+
+private const val TAG = "SwipeStatusBarAwayGestureHandler"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 83c98d5..26f6460 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -30,6 +30,7 @@
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
+import android.util.Log
import android.view.View
import android.view.ViewGroup
import com.android.settingslib.Utils
@@ -74,6 +75,10 @@
@Main private val handler: Handler,
optionalPlugin: Optional<BcSmartspaceDataPlugin>
) {
+ companion object {
+ private const val TAG = "LockscreenSmartspaceController"
+ }
+
private var session: SmartspaceSession? = null
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
@@ -211,6 +216,7 @@
val newSession = smartspaceManager.createSmartspaceSession(
SmartspaceConfig.Builder(context, "lockscreen").build())
+ Log.d(TAG, "Starting smartspace session for lockscreen")
newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
this.session = newSession
@@ -232,6 +238,8 @@
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
*/
fun disconnect() {
+ if (!smartspaceViews.isEmpty()) return
+
execution.assertIsMainThread()
if (session == null) {
@@ -249,6 +257,7 @@
session = null
plugin?.onTargetsAvailable(emptyList())
+ Log.d(TAG, "Ending smartspace session for lockscreen")
}
fun addListener(listener: SmartspaceTargetListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 7d476bf..3806d9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -35,6 +35,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -200,11 +201,8 @@
statusBarWindowController.ifPresent {
it.setOngoingProcessRequiresStatusBarVisible(true)
}
- // TODO(b/195839150): Only listen for the gesture when in immersive mode.
- swipeStatusBarAwayGestureHandler.ifPresent {
- it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected)
- }
}
+ updateGestureListening()
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
} else {
// If we failed to update the chip, don't store the call info. Then [hasOngoingCall]
@@ -292,6 +290,18 @@
return procState <= ActivityManager.PROCESS_STATE_TOP
}
+ private fun updateGestureListening() {
+ if (callNotificationInfo == null
+ || callNotificationInfo?.statusBarSwipedAway == true
+ || !isFullscreen) {
+ swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) }
+ } else {
+ swipeStatusBarAwayGestureHandler.ifPresent {
+ it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected)
+ }
+ }
+ }
+
private fun removeChip() {
callNotificationInfo = null
tearDownChipView()
@@ -334,6 +344,7 @@
override fun onFullscreenStateChanged(isFullscreen: Boolean) {
this@OngoingCallController.isFullscreen = isFullscreen
updateChipClickListener()
+ updateGestureListening()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 5c7885f..fe0a2a4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -30,6 +29,7 @@
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.test.filters.SmallTest;
@@ -108,7 +108,7 @@
private final View mFakeSmartspaceView = new View(mContext);
private KeyguardClockSwitchController mController;
- private View mStatusArea;
+ private View mSliceView;
@Before
public void setup() {
@@ -149,8 +149,10 @@
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
- mStatusArea = new View(getContext());
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+ mSliceView = new View(getContext());
+ when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(
+ new LinearLayout(getContext()));
}
@Test
@@ -215,7 +217,7 @@
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mController.init();
- assertEquals(View.GONE, mStatusArea.getVisibility());
+ assertEquals(View.GONE, mSliceView.getVisibility());
}
@Test
@@ -223,22 +225,7 @@
when(mSmartspaceController.isEnabled()).thenReturn(false);
mController.init();
- assertEquals(View.VISIBLE, mStatusArea.getVisibility());
- }
-
- @Test
- public void testDetachDisconnectsSmartspace() {
- when(mSmartspaceController.isEnabled()).thenReturn(true);
- when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
- mController.init();
- verify(mView).addView(eq(mFakeSmartspaceView), anyInt(), any());
-
- ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
- ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
- verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
-
- listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
- verify(mSmartspaceController).disconnect();
+ assertEquals(View.VISIBLE, mSliceView.getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 1ab08c2..77302ce 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -54,7 +54,7 @@
MockitoAnnotations.initMocks(this);
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
mKeyguardSliceView = (KeyguardSliceView) layoutInflater
- .inflate(R.layout.keyguard_status_area, null);
+ .inflate(R.layout.keyguard_slice_view, null);
mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST)));
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index b95a33b..3edfd03 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -239,8 +239,6 @@
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
- when(mFeatureFlags.isKeyguardLayoutEnabled()).thenReturn(false);
-
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(SubscriptionManager.class).startMocking();
ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 5d50485..b13c4d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -246,6 +246,7 @@
clearInvocations(plugin)
// WHEN the session is closed
+ controller.stateChangeListener.onViewDetachedFromWindow(smartspaceView as View)
controller.disconnect()
// THEN the listener receives an empty list of targets
@@ -417,6 +418,7 @@
connectSession()
// WHEN we are told to cleanup
+ controller.stateChangeListener.onViewDetachedFromWindow(smartspaceView as View)
controller.disconnect()
// THEN we disconnect from the session and unregister any listeners
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index ca6e1ee..3d2ff47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -37,6 +37,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -149,14 +150,6 @@
}
@Test
- fun onEntryUpdated_isOngoingCallNotif_swipeGestureCallbackAdded() {
- notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
-
- verify(mockSwipeStatusBarAwayGestureHandler)
- .addOnGestureDetectedCallback(anyString(), any())
- }
-
- @Test
fun onEntryUpdated_notOngoingCallNotif_listenerNotNotified() {
notifCollectionListener.onEntryUpdated(createNotCallNotifEntry())
@@ -257,17 +250,6 @@
verify(mockStatusBarWindowController).setOngoingProcessRequiresStatusBarVisible(false)
}
- @Test
- fun onEntryUpdated_callNotifAddedThenRemoved_swipeGestureCallbackRemoved() {
- val ongoingCallNotifEntry = createOngoingCallNotifEntry()
- notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
-
- notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
-
- verify(mockSwipeStatusBarAwayGestureHandler)
- .removeOnGestureDetectedCallback(anyString())
- }
-
/** Regression test for b/188491504. */
@Test
fun onEntryRemoved_removedNotifHasSameKeyAsAddedNotif_listenerNotified() {
@@ -508,6 +490,70 @@
assertThat(chipView.hasOnClickListeners()).isTrue()
}
+ // Swipe gesture tests
+
+ @Test
+ fun callStartedInImmersiveMode_swipeGestureCallbackAdded() {
+ getStateListener().onFullscreenStateChanged(true)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .addOnGestureDetectedCallback(anyString(), any())
+ }
+
+ @Test
+ fun callStartedNotInImmersiveMode_swipeGestureCallbackNotAdded() {
+ getStateListener().onFullscreenStateChanged(false)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockSwipeStatusBarAwayGestureHandler, never())
+ .addOnGestureDetectedCallback(anyString(), any())
+ }
+
+ @Test
+ fun transitionToImmersiveMode_swipeGestureCallbackAdded() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ getStateListener().onFullscreenStateChanged(true)
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .addOnGestureDetectedCallback(anyString(), any())
+ }
+
+ @Test
+ fun transitionOutOfImmersiveMode_swipeGestureCallbackRemoved() {
+ getStateListener().onFullscreenStateChanged(true)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ reset(mockSwipeStatusBarAwayGestureHandler)
+
+ getStateListener().onFullscreenStateChanged(false)
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .removeOnGestureDetectedCallback(anyString())
+ }
+
+ @Test
+ fun callEndedWhileInImmersiveMode_swipeGestureCallbackRemoved() {
+ getStateListener().onFullscreenStateChanged(true)
+ val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+ notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
+ reset(mockSwipeStatusBarAwayGestureHandler)
+
+ notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .removeOnGestureDetectedCallback(anyString())
+ }
+
+ // TODO(b/195839150): Add test
+ // swipeGesturedTriggeredPreviously_entersImmersiveModeAgain_callbackNotAdded(). That's
+ // difficult to add now because we have no way to trigger [SwipeStatusBarAwayGestureHandler]'s
+ // callbacks in test.
+
+ // END swipe gesture tests
+
private fun createOngoingCallNotifEntry() = createCallNotifEntry(ongoingCallStyle)
private fun createScreeningCallNotifEntry() = createCallNotifEntry(screeningCallStyle)
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 1050835..7d7f3a9 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -65,6 +65,7 @@
private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
private static final int TYPE_SET_NOTIFICATION_POLICY = 16;
private static final int TYPE_SET_CONSOLIDATED_ZEN_POLICY = 17;
+ private static final int TYPE_MATCHES_CALL_FILTER = 18;
private static int sNext;
private static int sSize;
@@ -166,6 +167,13 @@
+ hintsToString(newHints) + ",listeners=" + listenerCount);
}
+ /*
+ * Trace calls to matchesCallFilter with the result of the call and the reason for the result.
+ */
+ public static void traceMatchesCallFilter(boolean result, String reason) {
+ append(TYPE_MATCHES_CALL_FILTER, "result=" + result + ", reason=" + reason);
+ }
+
private static String subscribeResult(IConditionProvider provider, RemoteException e) {
return provider == null ? "no provider" : e != null ? e.getMessage() : "ok";
}
@@ -189,6 +197,7 @@
case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy";
case TYPE_SET_CONSOLIDATED_ZEN_POLICY: return "set_consolidated_policy";
+ case TYPE_MATCHES_CALL_FILTER: return "matches_call_filter";
default: return "unknown";
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 0f526d4..b186f61 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -89,20 +89,34 @@
public static boolean matchesCallFilter(Context context, int zen, NotificationManager.Policy
consolidatedPolicy, UserHandle userHandle, Bundle extras,
ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
- if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
- if (zen == Global.ZEN_MODE_ALARMS) return false; // not an alarm
+ if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+ ZenLog.traceMatchesCallFilter(false, "no interruptions");
+ return false; // nothing gets through
+ }
+ if (zen == Global.ZEN_MODE_ALARMS) {
+ ZenLog.traceMatchesCallFilter(false, "alarms only");
+ return false; // not an alarm
+ }
if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
if (consolidatedPolicy.allowRepeatCallers()
&& REPEAT_CALLERS.isRepeat(context, extras)) {
+ ZenLog.traceMatchesCallFilter(true, "repeat caller");
return true;
}
- if (!consolidatedPolicy.allowCalls()) return false; // no other calls get through
+ if (!consolidatedPolicy.allowCalls()) {
+ ZenLog.traceMatchesCallFilter(false, "calls not allowed");
+ return false; // no other calls get through
+ }
if (validator != null) {
final float contactAffinity = validator.getContactAffinity(userHandle, extras,
contactsTimeoutMs, timeoutAffinity);
- return audienceMatches(consolidatedPolicy.allowCallsFrom(), contactAffinity);
+ boolean match =
+ audienceMatches(consolidatedPolicy.allowCallsFrom(), contactAffinity);
+ ZenLog.traceMatchesCallFilter(match, "contact affinity " + contactAffinity);
+ return match;
}
}
+ ZenLog.traceMatchesCallFilter(true, "no restrictions");
return true;
}
diff --git a/services/core/java/com/android/server/vibrator/RampDownAdapter.java b/services/core/java/com/android/server/vibrator/RampDownAdapter.java
index d5cd344..e97ed4c 100644
--- a/services/core/java/com/android/server/vibrator/RampDownAdapter.java
+++ b/services/core/java/com/android/server/vibrator/RampDownAdapter.java
@@ -77,9 +77,8 @@
*/
private int addRampDownToZeroAmplitudeSegments(List<VibrationEffectSegment> segments,
int repeatIndex) {
- int newRepeatIndex = repeatIndex;
- int newSegmentCount = segments.size();
- for (int i = 1; i < newSegmentCount; i++) {
+ int segmentCount = segments.size();
+ for (int i = 1; i < segmentCount; i++) {
VibrationEffectSegment previousSegment = segments.get(i - 1);
if (!isOffSegment(segments.get(i))
|| !endsWithNonZeroAmplitude(previousSegment)) {
@@ -116,16 +115,23 @@
if (replacementSegments != null) {
int segmentsAdded = replacementSegments.size() - 1;
- segments.remove(i);
+ VibrationEffectSegment originalOffSegment = segments.remove(i);
segments.addAll(i, replacementSegments);
- if (repeatIndex > i) {
- newRepeatIndex += segmentsAdded;
+ if (repeatIndex >= i) {
+ if (repeatIndex == i) {
+ // This effect is repeating to the removed off segment: add it back at the
+ // end of the vibration so the loop timings are preserved, and skip it.
+ segments.add(originalOffSegment);
+ repeatIndex++;
+ segmentCount++;
+ }
+ repeatIndex += segmentsAdded;
}
i += segmentsAdded;
- newSegmentCount += segmentsAdded;
+ segmentCount += segmentsAdded;
}
}
- return newRepeatIndex;
+ return repeatIndex;
}
/**
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 25321c1..a327382 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -1077,7 +1077,7 @@
newSegments.remove(segmentIndex);
newSegments.addAll(segmentIndex, fallback.getSegments());
if (segmentIndex < effect.getRepeatIndex()) {
- newRepeatIndex += fallback.getSegments().size();
+ newRepeatIndex += fallback.getSegments().size() - 1;
}
return new VibrationEffect.Composed(newSegments, newRepeatIndex);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8ef973d..98397b8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2039,7 +2039,8 @@
boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty) {
+ boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty,
+ boolean activityAllDrawn) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
if (!okToDisplay()) {
@@ -2060,7 +2061,7 @@
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated, snapshot);
+ allowTaskSnapshot, activityCreated, activityAllDrawn, snapshot);
//TODO(191787740) Remove for T
final boolean useLegacy = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN
@@ -2074,7 +2075,7 @@
final int typeParameter = mWmService.mStartingSurfaceController
.makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated, useEmpty, useLegacy);
+ allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
if (isActivityTypeHome()) {
@@ -2209,10 +2210,10 @@
private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated,
+ boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn,
TaskSnapshot snapshot) {
- if ((newTask || !processRunning || (taskSwitch && !activityCreated))
- && !isActivityTypeHome()) {
+ if ((newTask || !processRunning || (taskSwitch && !activityCreated)
+ || (taskSwitch && !activityAllDrawn)) && !isActivityTypeHome()) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
if (isSnapshotCompatible(snapshot)) {
@@ -6629,7 +6630,7 @@
final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(),
- allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
+ allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty, allDrawn);
if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
Slog.d(TAG, "Scheduled starting window for " + this);
}
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 26f0384..8b2a425 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
@@ -86,7 +87,7 @@
int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated,
- boolean useEmpty, boolean useLegacy) {
+ boolean useEmpty, boolean useLegacy, boolean activityDrawn) {
int parameter = 0;
if (newTask) {
parameter |= TYPE_PARAMETER_NEW_TASK;
@@ -109,6 +110,9 @@
if (useLegacy) {
parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
}
+ if (activityDrawn) {
+ parameter |= TYPE_PARAMETER_ACTIVITY_DRAWN;
+ }
return parameter;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f11fa16..80f74f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2473,7 +2473,8 @@
if (isPrimaryDisplay) {
transformHint = (transformHint + mPrimaryDisplayOrientation) % 4;
}
- outSurfaceControl.setTransformHint(transformHint);
+ outSurfaceControl.setTransformHint(
+ SurfaceControl.rotationToBufferTransform(transformHint));
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Passing transform hint %d for window %s%s",
transformHint, win,
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/RampDownAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/RampDownAdapterTest.java
index b90df21..4c3312c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/RampDownAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/RampDownAdapterTest.java
@@ -103,21 +103,18 @@
public void testStepSegments_withShortZeroSegment_replaceWithStepsDown() {
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
- new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10),
- new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100)));
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10)));
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
- new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5),
- new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5));
- assertEquals(1, mAdapter.apply(segments, 1, TEST_VIBRATOR_INFO));
-
+ assertEquals(-1, mAdapter.apply(segments, -1, TEST_VIBRATOR_INFO));
assertEquals(expectedSegments, segments);
}
@Test
- public void testStepSegments_withLongZeroSegment_replaceWithStepsDown() {
+ public void testStepSegments_withLongZeroSegment_replaceWithStepsDownWithRemainingOffSegment() {
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
@@ -131,9 +128,67 @@
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 35),
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
+ assertEquals(-1, mAdapter.apply(segments, -1, TEST_VIBRATOR_INFO));
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withZeroSegmentBeforeRepeat_fixesRepeat() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 50),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.75f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.25f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 35),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
+
// Repeat index fixed after intermediate steps added
assertEquals(5, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
+ assertEquals(expectedSegments, segments);
+ }
+ @Test
+ public void testStepSegments_withZeroSegmentAfterRepeat_preservesRepeat() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
+
+ assertEquals(3, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withZeroSegmentAtRepeat_fixesRepeatAndAppendOriginalToListEnd() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 50),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 100)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.75f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.25f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 35),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 100),
+ // Original zero segment appended to the end of new looping vibration,
+ // then converted to ramp down as well.
+ new StepSegment(/* amplitude= */ 0.75f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.25f, /* frequency= */ 0, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 35));
+
+ // Repeat index fixed after intermediate steps added
+ assertEquals(5, mAdapter.apply(segments, 1, TEST_VIBRATOR_INFO));
assertEquals(expectedSegments, segments);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 65733d7..5504f06 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2463,7 +2463,7 @@
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
activity.removeStartingWindow();
@@ -2476,7 +2476,7 @@
activity.mTargetSdk = targetSdk;
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN,
@@ -2514,11 +2514,11 @@
.setVisible(false).build();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
- true, true, false, true, false, false);
+ true, true, false, true, false, false, false);
waitUntilHandlersIdle();
assertFalse(mDisplayContent.mSkipAppTransitionAnimation);
assertNoStartingWindow(activity1);
@@ -2536,11 +2536,11 @@
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
activity1, true, true, false,
- true, false, false);
+ true, false, false, false);
});
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -2553,11 +2553,11 @@
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
- true, true, false, true, false, false);
+ true, true, false, true, false, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -2599,7 +2599,7 @@
"Test", 0 /* labelRes */, 0 /* icon */, 0 /* logo */, 0 /* windowFlags */,
null /* transferFrom */, true /* newTask */, true /* taskSwitch */,
false /* processRunning */, false /* allowTaskSnapshot */,
- false /* activityCreate */, false /* suggestEmpty */);
+ false /* activityCreate */, false /* suggestEmpty */, false /* activityAllDrawn */);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
@@ -2647,7 +2647,7 @@
task.positionChildAt(topActivity, POSITION_TOP);
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
// Make activities to have different rotation from it display and set fixed rotation
@@ -2664,7 +2664,7 @@
// on activity2.
topActivity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity,
- false, false, false, true, false, false);
+ false, false, false, true, false, false, false);
waitUntilHandlersIdle();
assertTrue(topActivity.hasFixedRotationTransform());
}
@@ -2680,7 +2680,7 @@
// Add a starting window.
activityTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false, false, false);
waitUntilHandlersIdle();
// Make the top one invisible, and try transferring the starting window from the top to the
diff --git a/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java b/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java
deleted file mode 100644
index a3a2abe..0000000
--- a/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.HandlerThread;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-/**
- * Provides a one-way communication mechanism using a Parcelable as a payload, via broadcasts.
- *
- * Use {@link #send(Context, String, Parcelable)} to send a message.
- * USe {@link Receiver} to receive a message.
- *
- * Pick a unique "suffix" for your test, and use it with both the sender and receiver, in order
- * to avoid "cross-talks" between different tests. (if they ever run at the same time.)
- *
- * TODO: Move it to compatibility-device-util-axt.
- */
-public final class BroadcastMessenger {
- private static final String TAG = "BroadcastMessenger";
-
- private static final String ACTION_MESSAGE =
- "com.android.compatibility.common.util.BroadcastMessenger.ACTION_MESSAGE_";
- private static final String ACTION_PING =
- "com.android.compatibility.common.util.BroadcastMessenger.ACTION_PING_";
- private static final String EXTRA_MESSAGE =
- "com.android.compatibility.common.util.BroadcastMessenger.EXTRA_MESSAGE";
-
- /**
- * We need to drop messages that were sent before the receiver was created. We keep
- * track of the message send time in this extra.
- */
- private static final String EXTRA_SENT_TIME =
- "com.android.compatibility.common.util.BroadcastMessenger.EXTRA_SENT_TIME";
-
- public static final int DEFAULT_TIMEOUT_MS = 10_000;
-
- private static long getCurrentTime() {
- return SystemClock.uptimeMillis();
- }
-
- private static void sendBroadcast(@NonNull Intent i, @NonNull Context context,
- @NonNull String broadcastSuffix, @Nullable String receiverPackage) {
- i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- i.setPackage(receiverPackage);
- i.putExtra(EXTRA_SENT_TIME, getCurrentTime());
-
- context.sendBroadcast(i);
- }
-
- /** Send a message to the {@link Receiver} expecting a given "suffix". */
- public static <T extends Parcelable> void send(@NonNull Context context,
- @NonNull String broadcastSuffix, @NonNull T message) {
- final Intent i = new Intent(ACTION_MESSAGE + Objects.requireNonNull(broadcastSuffix));
- i.putExtra(EXTRA_MESSAGE, Objects.requireNonNull(message));
-
- Log.i(TAG, "Sending: " + message);
- sendBroadcast(i, context, broadcastSuffix, /*receiverPackage=*/ null);
- }
-
- private static void sendPing(@NonNull Context context,@NonNull String broadcastSuffix,
- @NonNull String receiverPackage) {
- final Intent i = new Intent(ACTION_PING + Objects.requireNonNull(broadcastSuffix));
-
- Log.i(TAG, "Sending a ping");
- sendBroadcast(i, context, broadcastSuffix, receiverPackage);
- }
-
- /**
- * Receive messages sent with {@link #send}. Note it'll ignore all the messages that were
- * sent before instantiated.
- */
- public static final class Receiver<T extends Parcelable> implements AutoCloseable {
- private final Context mContext;
- private final String mBroadcastSuffix;
- private final HandlerThread mReceiverThread = new HandlerThread(TAG);
-
- // @GuardedBy("mMessages")
- private final ArrayList<T> mMessages = new ArrayList<>();
- private final long mCreatedTime = getCurrentTime();
- private boolean mRegistered;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Log.d(TAG, "Received intent: " + intent);
- if (intent.getAction().equals(ACTION_MESSAGE + mBroadcastSuffix)
- || intent.getAction().equals(ACTION_PING + mBroadcastSuffix)) {
- // OK
- } else {
- throw new RuntimeException("Unknown broadcast received: " + intent);
- }
- if (intent.getLongExtra(EXTRA_SENT_TIME, 0) < mCreatedTime) {
- Log.i(TAG, "Dropping stale broadcast: " + intent);
- return;
- }
-
- // Note for a PING, the message will be null.
- final T message = intent.getParcelableExtra(EXTRA_MESSAGE);
- if (message != null) {
- Log.i(TAG, "Received: " + message);
- }
-
- synchronized (mMessages) {
- mMessages.add(message);
- mMessages.notifyAll();
- }
- }
- };
-
- /**
- * Constructor.
- */
- public Receiver(@NonNull Context context, @NonNull String broadcastSuffix) {
- mContext = context;
- mBroadcastSuffix = Objects.requireNonNull(broadcastSuffix);
-
- mReceiverThread.start();
-
- final IntentFilter fi = new IntentFilter(ACTION_MESSAGE + mBroadcastSuffix);
- fi.addAction(ACTION_PING + mBroadcastSuffix);
-
- context.registerReceiver(mReceiver, fi, /* permission=*/ null,
- mReceiverThread.getThreadHandler(), Context.RECEIVER_EXPORTED);
- mRegistered = true;
- }
-
- @Override
- public void close() {
- if (mRegistered) {
- mContext.unregisterReceiver(mReceiver);
- mReceiverThread.quit();
- mRegistered = false;
- }
- }
-
- /**
- * Receive the next message with a 60 second timeout.
- */
- @NonNull
- public T waitForNextMessage() {
- return waitForNextMessage(DEFAULT_TIMEOUT_MS);
- }
-
- /**
- * Receive the next message.
- */
- @NonNull
- public T waitForNextMessage(long timeoutMillis) {
- synchronized (mMessages) {
- final long timeout = System.currentTimeMillis() + timeoutMillis;
- while (mMessages.size() == 0) {
- final long wait = timeout - System.currentTimeMillis();
- if (wait <= 0) {
- throw new RuntimeException("Timeout waiting for the next message");
- }
- try {
- mMessages.wait(wait);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- return mMessages.remove(0);
- }
- }
-
- /**
- * Ensure that no further messages have been received.
- *
- * Call it before {@link #close()}.
- */
- public void ensureNoMoreMessages() {
- // Send a ping to myself.
- sendPing(mContext, mBroadcastSuffix, mContext.getPackageName());
-
- final T m = waitForNextMessage();
- if (m == null) {
- return; // Okay. Ping will deliver a null message.
- }
- throw new RuntimeException("No more messages expected, but received: " + m);
- }
- }
-}