Merge "Make LegacyTypeTracker testable" into qt-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2906710..0e10de8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -510,7 +510,7 @@
* The absence of a connection type.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static final int TYPE_NONE = -1;
/**
@@ -627,7 +627,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static final int TYPE_MOBILE_FOTA = 10;
/**
@@ -645,7 +645,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static final int TYPE_MOBILE_CBS = 12;
/**
@@ -655,7 +655,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static final int TYPE_WIFI_P2P = 13;
/**
@@ -674,7 +674,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static final int TYPE_MOBILE_EMERGENCY = 15;
/**
@@ -775,7 +775,7 @@
*/
public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
/**
* A kludge to facilitate static access where a Context pointer isn't available, like in the
@@ -867,7 +867,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public static boolean isNetworkTypeMobile(int networkType) {
switch (networkType) {
case TYPE_MOBILE:
@@ -1304,7 +1304,7 @@
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public LinkProperties getLinkProperties(int networkType) {
try {
return mService.getLinkPropertiesForType(networkType);
@@ -3042,7 +3042,7 @@
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
public boolean isNetworkSupported(int networkType) {
try {
return mService.isNetworkSupported(networkType);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 4332d8a..1c6a484 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -25,6 +25,7 @@
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.media.MediaPlayer;
+import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.DataUnit;
@@ -169,7 +170,7 @@
private static INetworkStatsService sStatsService;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private synchronized static INetworkStatsService getStatsService() {
if (sStatsService == null) {
sStatsService = INetworkStatsService.Stub.asInterface(
@@ -979,7 +980,7 @@
* Interfaces are never removed from this list, so counters should always be
* monotonic.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private static String[] getMobileIfaces() {
try {
return getStatsService().getMobileIfaces();
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b3e94e3..21a8f4c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -572,6 +572,15 @@
<!-- Integer size limit, in KB, for a single WifiLogger ringbuffer, in verbose logging mode -->
<integer translatable="false" name="config_wifi_logger_ring_buffer_verbose_size_limit_kb">1024</integer>
+ <!-- Array indicating wifi fatal firmware alert error code list from driver -->
+ <integer-array translatable="false" name="config_wifi_fatal_firmware_alert_error_code_list">
+ <!-- Example:
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ -->
+ </integer-array>
+
<!-- Boolean indicating whether or not wifi should turn off when emergency call is made -->
<bool translatable="false" name="config_wifi_turn_off_during_emergency_call">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2f34c94..186b84c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -381,6 +381,7 @@
<java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
<java-symbol type="integer" name="config_wifi_logger_ring_buffer_default_size_limit_kb" />
<java-symbol type="integer" name="config_wifi_logger_ring_buffer_verbose_size_limit_kb" />
+ <java-symbol type="array" name="config_wifi_fatal_firmware_alert_error_code_list" />
<java-symbol type="bool" name="config_wifi_turn_off_during_emergency_call" />
<java-symbol type="bool" name="config_supportMicNearUltrasound" />
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index efebfc2..a7f8933 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.car;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.car.drivingstate.CarDrivingStateEvent;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.GestureDetector;
@@ -55,6 +59,7 @@
import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.car.hvac.HvacController;
import com.android.systemui.statusbar.car.hvac.TemperatureView;
@@ -74,6 +79,15 @@
public class CarStatusBar extends StatusBar implements
CarBatteryController.BatteryViewHandler {
private static final String TAG = "CarStatusBar";
+ // used to calculate how fast to open or close the window
+ private static final float DEFAULT_FLING_VELOCITY = 0;
+ // max time a fling animation takes
+ private static final float FLING_ANIMATION_MAX_TIME = 0.5f;
+ // acceleration rate for the fling animation
+ private static final float FLING_SPEED_UP_FACTOR = 0.6f;
+
+ private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
+ private float mClosingVelocity = DEFAULT_FLING_VELOCITY;
private TaskStackListenerImpl mTaskStackListener;
@@ -100,6 +114,7 @@
private boolean mDeviceIsProvisioned = true;
private HvacController mHvacController;
private DrivingStateHelper mDrivingStateHelper;
+ private static FlingAnimationUtils sFlingAnimationUtils;
private SwitchToGuestTimer mSwitchToGuestTimer;
// The container for the notifications.
@@ -113,6 +128,27 @@
// it's open.
private View.OnTouchListener mNavBarNotificationTouchListener;
+ // Percentage from top of the screen after which the notification shade will open. This value
+ // will be used while opening the notification shade.
+ private int mSettleOpenPercentage;
+ // Percentage from top of the screen below which the notification shade will close. This
+ // value will be used while closing the notification shade.
+ private int mSettleClosePercentage;
+ // Percentage of notification shade open from top of the screen.
+ private int mPercentageFromBottom;
+ // If notification shade is animation to close or to open.
+ private boolean mIsNotificationAnimating;
+
+ // Tracks when the notification shade is being scrolled. This refers to the glass pane being
+ // scrolled not the recycler view.
+ private boolean mIsTracking;
+ private float mFirstTouchDownOnGlassPane;
+
+ // If the notification card inside the recycler view is being swiped.
+ private boolean mIsNotificationCardSwiping;
+ // If notification shade is being swiped vertically to close.
+ private boolean mIsSwipingVerticallyToClose;
+
@Override
public void start() {
// get the provisioned state before calling the parent class since it's that flow that
@@ -125,6 +161,12 @@
mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener);
mNotificationPanel.setScrollingEnabled(true);
+ mSettleOpenPercentage = mContext.getResources().getInteger(
+ R.integer.notification_settle_open_percentage);
+ mSettleClosePercentage = mContext.getResources().getInteger(
+ R.integer.notification_settle_close_percentage);
+ sFlingAnimationUtils = new FlingAnimationUtils(mContext,
+ FLING_ANIMATION_MAX_TIME, FLING_SPEED_UP_FACTOR);
createBatteryController();
mCarBatteryController.startListening();
@@ -313,14 +355,46 @@
}
});
mNavBarNotificationTouchListener =
- (v, event) -> navBarCloseNotificationGestureDetector.onTouchEvent(event);
+ (v, event) -> {
+ boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event);
+ if (consumed) {
+ return true;
+ }
+ if (event.getActionMasked() == MotionEvent.ACTION_UP
+ && mNotificationView.getVisibility() == View.VISIBLE) {
+ if (mSettleClosePercentage < mPercentageFromBottom) {
+ animateNotificationPanel(
+ DEFAULT_FLING_VELOCITY, false);
+ } else {
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY,
+ true);
+ }
+ }
+ return true;
+ };
// The following are the ui elements that the user would call the status bar.
// This will set the status bar so it they can make call backs.
CarNavigationBarView topBar = mStatusBarWindow.findViewById(R.id.car_top_bar);
topBar.setStatusBar(this);
- topBar.setStatusBarWindowTouchListener((v1, event1) ->
- openGestureDetector.onTouchEvent(event1));
+ topBar.setStatusBarWindowTouchListener((v1, event1) -> {
+
+ boolean consumed = openGestureDetector.onTouchEvent(event1);
+ if (consumed) {
+ return true;
+ }
+ if (event1.getActionMasked() == MotionEvent.ACTION_UP
+ && mNotificationView.getVisibility() == View.VISIBLE) {
+ if (mSettleOpenPercentage > mPercentageFromBottom) {
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
+ } else {
+ animateNotificationPanel(
+ DEFAULT_FLING_VELOCITY, false);
+ }
+ }
+ return true;
+ }
+ );
NotificationClickHandlerFactory clickHandlerFactory = new NotificationClickHandlerFactory(
mBarService,
@@ -347,7 +421,10 @@
mNotificationListAtBottomAtTimeOfTouch = false;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mFirstTouchDownOnGlassPane = event.getRawX();
mNotificationListAtBottomAtTimeOfTouch = mNotificationListAtBottom;
+ // Reset the tracker when there is a touch down on the glass pane.
+ mIsTracking = false;
// Pass the down event to gesture detector so that it knows where the touch event
// started.
closeGestureDetector.onTouchEvent(event);
@@ -364,23 +441,56 @@
return;
}
mNotificationListAtBottom = false;
+ mIsSwipingVerticallyToClose = false;
mNotificationListAtBottomAtTimeOfTouch = false;
}
});
mNotificationList.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
+ mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX())
+ > SWIPE_MAX_OFF_PATH;
+ if (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom) {
+ // We need to save the state here as if notification card is swiping we will
+ // change the mNotificationListAtBottomAtTimeOfTouch. This is to protect
+ // closing the notification shade while the notification card is being swiped.
+ mIsSwipingVerticallyToClose = true;
+ }
+
+ // If the card is swiping we should not allow the notification shade to close.
+ // Hence setting mNotificationListAtBottomAtTimeOfTouch to false will stop that
+ // for us. We are also checking for mIsTracking because while swiping the
+ // notification shade to close if the user goes a bit horizontal while swiping
+ // upwards then also this should close.
+ if (mIsNotificationCardSwiping && !mIsTracking) {
+ mNotificationListAtBottomAtTimeOfTouch = false;
+ }
+
boolean handled = false;
if (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom) {
handled = closeGestureDetector.onTouchEvent(event);
}
+ boolean isTracking = mIsTracking;
+ Rect rect = mNotificationList.getClipBounds();
+ float clippedHeight = rect.bottom;
+ if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
+ && mIsSwipingVerticallyToClose) {
+ if (mSettleClosePercentage < mPercentageFromBottom && isTracking) {
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY, false);
+ } else if (clippedHeight != mNotificationView.getHeight() && isTracking) {
+ // this can be caused when user is at the end of the list and trying to
+ // fling to top of the list by scrolling down.
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
+ }
+ }
+
// Updating the mNotificationListAtBottomAtTimeOfTouch state has to be done after
// the event has been passed to the closeGestureDetector above, such that the
// closeGestureDetector sees the up event before the state has changed.
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
mNotificationListAtBottomAtTimeOfTouch = false;
}
- return handled;
+ return handled || isTracking;
}
});
@@ -401,7 +511,9 @@
mNotificationList.scrollToPosition(0);
mStatusBarWindowController.setPanelVisible(true);
mNotificationView.setVisibility(View.VISIBLE);
- // let the status bar know that the panel is open
+
+ animateNotificationPanel(mOpeningVelocity, false);
+
setPanelExpanded(true);
}
@@ -415,12 +527,66 @@
mStatusBarWindowController.setStatusBarFocusable(false);
mStatusBarWindow.cancelExpandHelper();
mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
- mStatusBarWindowController.setPanelVisible(false);
- mNotificationView.setVisibility(View.INVISIBLE);
- // let the status bar know that the panel is cloased
+
+ animateNotificationPanel(mClosingVelocity, true);
+
+ if (!mIsTracking) {
+ mStatusBarWindowController.setPanelVisible(false);
+ mNotificationView.setVisibility(View.INVISIBLE);
+ }
+
setPanelExpanded(false);
}
+ /**
+ * Animates the notification shade from one position to other. This is used to either open or
+ * close the notification shade completely with a velocity. If the animation is to close the
+ * notification shade this method also makes the view invisible after animation ends.
+ */
+ private void animateNotificationPanel(float velocity, boolean isClosing) {
+ Rect rect = mNotificationList.getClipBounds();
+ if (rect == null) {
+ return;
+ }
+ float from = rect.bottom;
+ float to = 0;
+ if (!isClosing) {
+ to = mNotificationView.getHeight();
+ }
+ if (mIsNotificationAnimating) {
+ return;
+ }
+ mIsNotificationAnimating = true;
+ mIsTracking = true;
+ ValueAnimator animator = ValueAnimator.ofFloat(from, to);
+ animator.addUpdateListener(
+ animation -> {
+ float animatedValue = (Float) animation.getAnimatedValue();
+ setNotificationViewClipBounds((int) animatedValue);
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mIsNotificationAnimating = false;
+ mIsTracking = false;
+ mOpeningVelocity = DEFAULT_FLING_VELOCITY;
+ mClosingVelocity = DEFAULT_FLING_VELOCITY;
+ if (isClosing) {
+ mStatusBarWindowController.setPanelVisible(false);
+ mNotificationView.setVisibility(View.INVISIBLE);
+ mNotificationList.setClipBounds(null);
+ // let the status bar know that the panel is closed
+ setPanelExpanded(false);
+ } else {
+ // let the status bar know that the panel is open
+ setPanelExpanded(true);
+ }
+ }
+ });
+ sFlingAnimationUtils.apply(animator, from, to, Math.abs(velocity));
+ animator.start();
+ }
@Override
protected QS createDefaultQSFragment() {
@@ -576,7 +742,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- //When executing dump() funciton simultaneously, we need to serialize them
+ //When executing dump() function simultaneously, we need to serialize them
//to get mStackScroller's position correctly.
synchronized (mQueueLock) {
pw.println(" mStackScroller: " + viewInfo(mStackScroller));
@@ -760,38 +926,80 @@
}
/** Returns true if the current user makes it through the setup wizard, false otherwise. */
- public boolean getIsUserSetup(){
+ private boolean getIsUserSetup() {
return mUserSetup;
}
+ private void setNotificationViewClipBounds(int height) {
+ Rect clipBounds = new Rect();
+ clipBounds.set(0, 0, mNotificationView.getWidth(), height);
+ // Sets the clip region on the notification list view.
+ mNotificationList.setClipBounds(clipBounds);
- // TODO: add settle down/up logic
+ if (mNotificationView.getHeight() > 0) {
+ // Calculates the alpha value for the background based on how much of the notification
+ // shade is visible to the user. When the notification shade is completely open then
+ // alpha value will be 1.
+ float alpha = (float) height / mNotificationView.getHeight();
+ Drawable background = mNotificationView.getBackground();
+
+ background.setAlpha((int) (alpha * 255));
+ }
+ }
+
+ private void calculatePercentageFromBottom(float height) {
+ if (mNotificationView.getHeight() > 0) {
+ mPercentageFromBottom = (int) Math.abs(
+ height / mNotificationView.getHeight() * 100);
+ }
+ }
+
private static final int SWIPE_UP_MIN_DISTANCE = 75;
private static final int SWIPE_DOWN_MIN_DISTANCE = 25;
private static final int SWIPE_MAX_OFF_PATH = 75;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
// Only responsible for open hooks. Since once the panel opens it covers all elements
// there is no need to merge with close.
private abstract class OpenNotificationGestureListener extends
GestureDetector.SimpleOnGestureListener {
@Override
+ public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
+ float distanceY) {
+
+ if (mNotificationView.getVisibility() == View.INVISIBLE) {
+ // when the on-scroll is called for the first time to open.
+ mNotificationList.scrollToPosition(0);
+ }
+ mStatusBarWindowController.setPanelVisible(true);
+ mNotificationView.setVisibility(View.VISIBLE);
+
+ // clips the view for the notification shade when the user scrolls to open.
+ setNotificationViewClipBounds((int) event2.getRawY());
+
+ // Initially the scroll starts with height being zero. This checks protects from divide
+ // by zero error.
+ calculatePercentageFromBottom(event2.getRawY());
+
+ mIsTracking = true;
+ return true;
+ }
+
+
+ @Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
- if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
- || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
- // swipe was not vertical or was not fast enough
- return false;
- }
- boolean isDown = velocityY > 0;
- float distanceDelta = Math.abs(event1.getY() - event2.getY());
- if (isDown && distanceDelta > SWIPE_DOWN_MIN_DISTANCE) {
+ if (velocityY > SWIPE_THRESHOLD_VELOCITY) {
+ mOpeningVelocity = velocityY;
openNotification();
return true;
}
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
return false;
}
+
protected abstract void openNotification();
}
@@ -800,35 +1008,84 @@
GestureDetector.SimpleOnGestureListener {
@Override
+ public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
+ float distanceY) {
+ if (!mNotificationListAtBottomAtTimeOfTouch) {
+ return false;
+ }
+ float actualNotificationHeight =
+ mNotificationView.getHeight() - (event1.getRawY() - event2.getRawY());
+ if (actualNotificationHeight > mNotificationView.getHeight()) {
+ actualNotificationHeight = mNotificationView.getHeight();
+ }
+ if (mNotificationView.getHeight() > 0) {
+ mPercentageFromBottom = (int) Math.abs(
+ actualNotificationHeight / mNotificationView.getHeight() * 100);
+ boolean isUp = distanceY > 0;
+
+ // This check is to figure out if onScroll was called while swiping the card at
+ // bottom of the list. At that time we should not allow notification shade to
+ // close. We are also checking for the upwards swipe gesture here because it is
+ // possible if a user is closing the notification shade and while swiping starts
+ // to open again but does not fling. At that time we should allow the
+ // notification shade to close fully or else it would stuck in between.
+ if (Math.abs(mNotificationView.getHeight() - actualNotificationHeight)
+ > SWIPE_DOWN_MIN_DISTANCE && isUp) {
+ setNotificationViewClipBounds((int) actualNotificationHeight);
+ mIsTracking = true;
+ } else if (!isUp) {
+ setNotificationViewClipBounds((int) actualNotificationHeight);
+ }
+ }
+ // if we return true the the items in RV won't be scrollable.
+ return false;
+ }
+
+
+ @Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
+
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
|| Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
// swipe was not vertical or was not fast enough
return false;
}
boolean isUp = velocityY < 0;
- float distanceDelta = Math.abs(event1.getY() - event2.getY());
- if (isUp && distanceDelta > SWIPE_UP_MIN_DISTANCE) {
+ if (isUp) {
close();
return true;
+ } else {
+ // we should close the shade
+ animateNotificationPanel(velocityY, false);
}
return false;
}
+
protected abstract void close();
}
- // to be installed on the nav bars
+ // To be installed on the nav bars.
private abstract class NavBarCloseNotificationGestureListener extends
CloseNotificationGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
+ mClosingVelocity = DEFAULT_FLING_VELOCITY;
close();
return super.onSingleTapUp(e);
}
@Override
+ public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
+ float distanceY) {
+ calculatePercentageFromBottom(event2.getRawY());
+ setNotificationViewClipBounds((int) event2.getRawY());
+ return true;
+ }
+
+ @Override
public void onLongPress(MotionEvent e) {
+ mClosingVelocity = DEFAULT_FLING_VELOCITY;
close();
super.onLongPress(e);
}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
similarity index 100%
rename from packages/DynamicSystemInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
similarity index 100%
rename from packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
similarity index 100%
rename from packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
similarity index 100%
rename from packages/DynamicSystemInstallationService/src/com/android/dynandroid/VerificationActivity.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 8226787..97e8186 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -35,6 +35,34 @@
// TODO: Refer to DeviceConfig definition.
public static final String NAMESPACE_CONNECTIVITY = "connectivity";
+ /**
+ * A list of captive portal detection specifications used in addition to the fallback URLs.
+ * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
+ * by "@@,@@".
+ */
+ public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
+ "captive_portal_fallback_probe_specs";
+
+ /**
+ * A comma separated list of URLs used for captive portal detection in addition to the
+ * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
+ */
+ public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
+ "captive_portal_other_fallback_urls";
+
+ /**
+ * Which User-Agent string to use in the header of the captive portal detection probes.
+ * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
+ */
+ public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+
+ /**
+ * Whether to use HTTPS for network validation. This is enabled by default and the setting
+ * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
+ * don't actually use HTTPS, but it's consistent with the other settings.
+ */
+ public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
+
static {
System.loadLibrary("networkstackutilsjni");
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 27d4203..093235e 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -43,6 +43,10 @@
import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USER_AGENT;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
import static android.net.util.NetworkStackUtils.isEmpty;
@@ -1171,7 +1175,8 @@
}
private boolean getUseHttpsValidation() {
- return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
}
private String getCaptivePortalServerHttpsUrl() {
@@ -1224,8 +1229,8 @@
final URL[] settingProviderUrls;
if (!TextUtils.isEmpty(firstUrl)) {
- final String otherUrls = mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+ final String otherUrls = mDependencies.getDeviceConfigProperty(
+ NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
// otherUrls may be empty, but .split() ignores trailing empty strings
final String separator = ",";
final String[] urls = (firstUrl + separator + otherUrls).split(separator);
@@ -1245,8 +1250,9 @@
private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
try {
- final String settingsValue = mDependencies.getSetting(
- mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+ final String settingsValue = mDependencies.getDeviceConfigProperty(
+ NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+
final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
? emptySpecs
@@ -1340,8 +1346,8 @@
}
private String getCaptivePortalUserAgent() {
- return mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+ return mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
+ CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
}
private URL nextFallbackUrl() {
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 910bdc7..594f2ca 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -26,6 +26,9 @@
import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -160,7 +163,7 @@
when(mDependencies.getRandom()).thenReturn(mRandom);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
.thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
+ when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
anyInt())).thenReturn(1);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
.thenReturn(TEST_HTTP_URL);
@@ -683,13 +686,13 @@
}
private void setOtherFallbackUrls(String urls) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
+ when(mDependencies.getDeviceConfigProperty(any(),
+ eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
}
private void setFallbackSpecs(String specs) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
+ when(mDependencies.getDeviceConfigProperty(any(),
+ eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
}
private void setCaptivePortalMode(int mode) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index 4e906bc..4673992 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -39,7 +39,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Predicate;
/**
* Build/Install/Run:
@@ -47,208 +46,222 @@
*/
@MediumTest
@Presubmit
-public class PersisterQueueTests implements PersisterQueue.Listener {
+public class PersisterQueueTests {
private static final long INTER_WRITE_DELAY_MS = 50;
private static final long PRE_TASK_DELAY_MS = 300;
- // We allow at most 1s more than the expected timeout.
- private static final long TIMEOUT_ALLOWANCE = 100;
-
- private static final Predicate<MatchingTestItem> TEST_ITEM_PREDICATE = item -> item.mMatching;
-
- private AtomicInteger mItemCount;
- private CountDownLatch mSetUpLatch;
- private volatile CountDownLatch mLatch;
- private List<Boolean> mProbablyDoneResults;
+ // We allow at most 0.2s more than the expected timeout.
+ private static final long TIMEOUT_ALLOWANCE = 200;
private final PersisterQueue mTarget =
new PersisterQueue(INTER_WRITE_DELAY_MS, PRE_TASK_DELAY_MS);
+ private TestPersisterQueueListener mListener;
+ private TestWriteQueueItemFactory mFactory;
+
@Before
public void setUp() throws Exception {
- mItemCount = new AtomicInteger(0);
- mProbablyDoneResults = new ArrayList<>();
- mSetUpLatch = new CountDownLatch(1);
+ mListener = new TestPersisterQueueListener();
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
+ mTarget.addListener(mListener);
- mTarget.addListener(this);
+ mFactory = new TestWriteQueueItemFactory();
+
mTarget.startPersisting();
assertTrue("Target didn't call callback on start up.",
- mSetUpLatch.await(TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
+ mListener.waitForAllExpectedCallbackDone(TIMEOUT_ALLOWANCE));
}
@After
public void tearDown() throws Exception {
mTarget.stopPersisting();
- mTarget.removeListener(this);
+ mTarget.removeListener(mListener);
}
@Test
public void testCallCallbackOnStartUp() {
// The onPreProcessItem() must be called on start up.
- assertEquals(1, mProbablyDoneResults.size());
+ assertEquals(1, mListener.mProbablyDoneResults.size());
// The last one must be called with probably done being true.
- assertTrue("The last probablyDone must be true.", mProbablyDoneResults.get(0));
+ assertTrue("The last probablyDone must be true.", mListener.mProbablyDoneResults.get(0));
}
@Test
public void testProcessOneItem() throws Exception {
- mLatch = new CountDownLatch(1);
+ mFactory.setExpectedProcessedItemNumber(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
final long dispatchTime = SystemClock.uptimeMillis();
- mTarget.addItem(new TestItem(), false);
- assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mTarget.addItem(mFactory.createItem(), false);
+ assertTrue("Target didn't process item enough times.",
+ mFactory.waitForAllExpectedItemsProcessed(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
final long processDuration = SystemClock.uptimeMillis() - dispatchTime;
assertTrue("Target didn't wait enough time before processing item. duration: "
+ processDuration + "ms pretask delay: " + PRE_TASK_DELAY_MS + "ms",
processDuration >= PRE_TASK_DELAY_MS);
+ assertTrue("Target didn't call callback enough times.",
+ mListener.waitForAllExpectedCallbackDone(TIMEOUT_ALLOWANCE));
// Once before processing this item, once after that.
- assertEquals(2, mProbablyDoneResults.size());
+ assertEquals(2, mListener.mProbablyDoneResults.size());
// The last one must be called with probably done being true.
- assertTrue("The last probablyDone must be true.", mProbablyDoneResults.get(1));
+ assertTrue("The last probablyDone must be true.", mListener.mProbablyDoneResults.get(1));
}
@Test
public void testProcessOneItem_Flush() throws Exception {
- mLatch = new CountDownLatch(1);
+ mFactory.setExpectedProcessedItemNumber(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
final long dispatchTime = SystemClock.uptimeMillis();
- mTarget.addItem(new TestItem(), true);
- assertTrue("Target didn't call callback enough times.",
- mLatch.await(TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mTarget.addItem(mFactory.createItem(), true);
+ assertTrue("Target didn't process item enough times.",
+ mFactory.waitForAllExpectedItemsProcessed(TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
final long processDuration = SystemClock.uptimeMillis() - dispatchTime;
assertTrue("Target didn't process item immediately when flushing. duration: "
+ processDuration + "ms pretask delay: "
+ PRE_TASK_DELAY_MS + "ms",
processDuration < PRE_TASK_DELAY_MS);
+ assertTrue("Target didn't call callback enough times.",
+ mFactory.waitForAllExpectedItemsProcessed(TIMEOUT_ALLOWANCE));
// Once before processing this item, once after that.
- assertEquals(2, mProbablyDoneResults.size());
+ assertEquals(2, mListener.mProbablyDoneResults.size());
// The last one must be called with probably done being true.
- assertTrue("The last probablyDone must be true.", mProbablyDoneResults.get(1));
+ assertTrue("The last probablyDone must be true.", mListener.mProbablyDoneResults.get(1));
}
@Test
public void testProcessTwoItems() throws Exception {
- mLatch = new CountDownLatch(2);
+ mFactory.setExpectedProcessedItemNumber(2);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(2);
final long dispatchTime = SystemClock.uptimeMillis();
- mTarget.addItem(new TestItem(), false);
- mTarget.addItem(new TestItem(), false);
+ mTarget.addItem(mFactory.createItem(), false);
+ mTarget.addItem(mFactory.createItem(), false);
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + INTER_WRITE_DELAY_MS + TIMEOUT_ALLOWANCE,
- TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process all items.", 2, mItemCount.get());
+ mFactory.waitForAllExpectedItemsProcessed(PRE_TASK_DELAY_MS + INTER_WRITE_DELAY_MS
+ + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process all items.", 2, mFactory.getTotalProcessedItemCount());
final long processDuration = SystemClock.uptimeMillis() - dispatchTime;
assertTrue("Target didn't wait enough time before processing item. duration: "
+ processDuration + "ms pretask delay: " + PRE_TASK_DELAY_MS
+ "ms inter write delay: " + INTER_WRITE_DELAY_MS + "ms",
processDuration >= PRE_TASK_DELAY_MS + INTER_WRITE_DELAY_MS);
-
+ assertTrue("Target didn't call the onPreProcess callback enough times",
+ mListener.waitForAllExpectedCallbackDone(TIMEOUT_ALLOWANCE));
// Once before processing this item, once after that.
- assertEquals(3, mProbablyDoneResults.size());
+ assertEquals(3, mListener.mProbablyDoneResults.size());
// The first one must be called with probably done being false.
- assertFalse("The first probablyDone must be false.", mProbablyDoneResults.get(1));
+ assertFalse("The first probablyDone must be false.", mListener.mProbablyDoneResults.get(1));
// The last one must be called with probably done being true.
- assertTrue("The last probablyDone must be true.", mProbablyDoneResults.get(2));
+ assertTrue("The last probablyDone must be true.", mListener.mProbablyDoneResults.get(2));
}
@Test
@FlakyTest(bugId = 128526085)
public void testProcessTwoItems_OneAfterAnother() throws Exception {
// First item
- mLatch = new CountDownLatch(1);
+ mFactory.setExpectedProcessedItemNumber(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
long dispatchTime = SystemClock.uptimeMillis();
- mTarget.addItem(new TestItem(), false);
- assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
+ mTarget.addItem(mFactory.createItem(), false);
+ assertTrue("Target didn't process item enough times.",
+ mFactory.waitForAllExpectedItemsProcessed(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
long processDuration = SystemClock.uptimeMillis() - dispatchTime;
assertTrue("Target didn't wait enough time before processing item."
+ processDuration + "ms pretask delay: "
+ PRE_TASK_DELAY_MS + "ms",
processDuration >= PRE_TASK_DELAY_MS);
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
+ assertTrue("Target didn't call callback enough times.",
+ mListener.waitForAllExpectedCallbackDone(TIMEOUT_ALLOWANCE));
// Second item
- mLatch = new CountDownLatch(1);
+ mFactory.setExpectedProcessedItemNumber(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
dispatchTime = SystemClock.uptimeMillis();
// Synchronize on the instance to make sure we schedule the item after it starts to wait for
// task indefinitely.
synchronized (mTarget) {
- mTarget.addItem(new TestItem(), false);
+ mTarget.addItem(mFactory.createItem(), false);
}
- assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process all items.", 2, mItemCount.get());
+ assertTrue("Target didn't process item enough times.",
+ mFactory.waitForAllExpectedItemsProcessed(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process all items.", 2, mFactory.getTotalProcessedItemCount());
processDuration = SystemClock.uptimeMillis() - dispatchTime;
assertTrue("Target didn't wait enough time before processing item. Process time: "
+ processDuration + "ms pre task delay: "
+ PRE_TASK_DELAY_MS + "ms",
processDuration >= PRE_TASK_DELAY_MS);
+ assertTrue("Target didn't call callback enough times.",
+ mListener.waitForAllExpectedCallbackDone(TIMEOUT_ALLOWANCE));
// Once before processing this item, once after that.
- assertEquals(3, mProbablyDoneResults.size());
+ assertEquals(3, mListener.mProbablyDoneResults.size());
// The last one must be called with probably done being true.
- assertTrue("The last probablyDone must be true.", mProbablyDoneResults.get(2));
+ assertTrue("The last probablyDone must be true.", mListener.mProbablyDoneResults.get(2));
}
@Test
public void testFindLastItemNotReturnDifferentType() {
synchronized (mTarget) {
- mTarget.addItem(new TestItem(), false);
- assertNull(mTarget.findLastItem(TEST_ITEM_PREDICATE, MatchingTestItem.class));
+ mTarget.addItem(mFactory.createItem(), false);
+ assertNull(mTarget.findLastItem(TestItem::shouldKeepOnFilter,
+ FilterableTestItem.class));
}
}
@Test
public void testFindLastItemNotReturnMismatchItem() {
synchronized (mTarget) {
- mTarget.addItem(new MatchingTestItem(false), false);
- assertNull(mTarget.findLastItem(TEST_ITEM_PREDICATE, MatchingTestItem.class));
+ mTarget.addItem(mFactory.createFilterableItem(false), false);
+ assertNull(mTarget.findLastItem(TestItem::shouldKeepOnFilter,
+ FilterableTestItem.class));
}
}
@Test
public void testFindLastItemReturnMatchedItem() {
synchronized (mTarget) {
- final MatchingTestItem item = new MatchingTestItem(true);
+ final FilterableTestItem item = mFactory.createFilterableItem(true);
mTarget.addItem(item, false);
- assertSame(item, mTarget.findLastItem(TEST_ITEM_PREDICATE, MatchingTestItem.class));
+ assertSame(item, mTarget.findLastItem(TestItem::shouldKeepOnFilter,
+ FilterableTestItem.class));
}
}
@Test
public void testRemoveItemsNotRemoveDifferentType() throws Exception {
- mLatch = new CountDownLatch(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
synchronized (mTarget) {
- mTarget.addItem(new TestItem(), false);
- mTarget.removeItems(TEST_ITEM_PREDICATE, MatchingTestItem.class);
+ mTarget.addItem(mFactory.createItem(), false);
+ mTarget.removeItems(TestItem::shouldKeepOnFilter, FilterableTestItem.class);
}
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mListener.waitForAllExpectedCallbackDone(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
}
@Test
public void testRemoveItemsNotRemoveMismatchedItem() throws Exception {
- mLatch = new CountDownLatch(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
synchronized (mTarget) {
- mTarget.addItem(new MatchingTestItem(false), false);
- mTarget.removeItems(TEST_ITEM_PREDICATE, MatchingTestItem.class);
+ mTarget.addItem(mFactory.createFilterableItem(false), false);
+ mTarget.removeItems(TestItem::shouldKeepOnFilter, FilterableTestItem.class);
}
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mListener.waitForAllExpectedCallbackDone(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
}
@Test
public void testUpdateLastOrAddItemUpdatesMatchedItem() throws Exception {
- mLatch = new CountDownLatch(1);
- final MatchingTestItem scheduledItem = new MatchingTestItem(true);
- final MatchingTestItem expected = new MatchingTestItem(true);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
+ final FilterableTestItem scheduledItem = mFactory.createFilterableItem(true);
+ final FilterableTestItem expected = mFactory.createFilterableItem(true);
synchronized (mTarget) {
mTarget.addItem(scheduledItem, false);
mTarget.updateLastOrAddItem(expected, false);
@@ -256,15 +269,15 @@
assertSame(expected, scheduledItem.mUpdateFromItem);
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mListener.waitForAllExpectedCallbackDone(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
}
@Test
public void testUpdateLastOrAddItemUpdatesAddItemWhenNoMatch() throws Exception {
- mLatch = new CountDownLatch(2);
- final MatchingTestItem scheduledItem = new MatchingTestItem(false);
- final MatchingTestItem expected = new MatchingTestItem(true);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(2);
+ final FilterableTestItem scheduledItem = mFactory.createFilterableItem(false);
+ final FilterableTestItem expected = mFactory.createFilterableItem(true);
synchronized (mTarget) {
mTarget.addItem(scheduledItem, false);
mTarget.updateLastOrAddItem(expected, false);
@@ -272,73 +285,132 @@
assertNull(scheduledItem.mUpdateFromItem);
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + INTER_WRITE_DELAY_MS + TIMEOUT_ALLOWANCE,
- TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 2, mItemCount.get());
+ mListener.waitForAllExpectedCallbackDone(PRE_TASK_DELAY_MS + INTER_WRITE_DELAY_MS
+ + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 2, mFactory.getTotalProcessedItemCount());
}
@Test
public void testRemoveItemsRemoveMatchedItem() throws Exception {
- mLatch = new CountDownLatch(1);
+ mListener.setExpectedOnPreProcessItemCallbackTimes(1);
synchronized (mTarget) {
- mTarget.addItem(new TestItem(), false);
- mTarget.addItem(new MatchingTestItem(true), false);
- mTarget.removeItems(TEST_ITEM_PREDICATE, MatchingTestItem.class);
+ mTarget.addItem(mFactory.createItem(), false);
+ mTarget.addItem(mFactory.createFilterableItem(true), false);
+ mTarget.removeItems(TestItem::shouldKeepOnFilter, FilterableTestItem.class);
}
assertTrue("Target didn't call callback enough times.",
- mLatch.await(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE, TimeUnit.MILLISECONDS));
- assertEquals("Target didn't process item.", 1, mItemCount.get());
+ mListener.waitForAllExpectedCallbackDone(PRE_TASK_DELAY_MS + TIMEOUT_ALLOWANCE));
+ assertEquals("Target didn't process item.", 1, mFactory.getTotalProcessedItemCount());
}
@Test
public void testFlushWaitSynchronously() {
final long dispatchTime = SystemClock.uptimeMillis();
- mTarget.addItem(new TestItem(), false);
- mTarget.addItem(new TestItem(), false);
+ mTarget.addItem(mFactory.createItem(), false);
+ mTarget.addItem(mFactory.createItem(), false);
mTarget.flush();
assertEquals("Flush should wait until all items are processed before return.",
- 2, mItemCount.get());
+ 2, mFactory.getTotalProcessedItemCount());
final long processTime = SystemClock.uptimeMillis() - dispatchTime;
assertWithMessage("Flush should trigger immediate flush without delays. processTime: "
+ processTime).that(processTime).isLessThan(TIMEOUT_ALLOWANCE);
}
- @Override
- public void onPreProcessItem(boolean queueEmpty) {
- mProbablyDoneResults.add(queueEmpty);
+ private static class TestWriteQueueItemFactory {
+ private final AtomicInteger mItemCount = new AtomicInteger(0);;
+ private CountDownLatch mLatch;
- final CountDownLatch latch = mLatch;
- if (latch != null) {
- latch.countDown();
+ int getTotalProcessedItemCount() {
+ return mItemCount.get();
}
- mSetUpLatch.countDown();
+ void setExpectedProcessedItemNumber(int countDown) {
+ mLatch = new CountDownLatch(countDown);
+ }
+
+ boolean waitForAllExpectedItemsProcessed(long timeoutInMilliseconds)
+ throws InterruptedException {
+ return mLatch.await(timeoutInMilliseconds, TimeUnit.MILLISECONDS);
+ }
+
+ TestItem createItem() {
+ return new TestItem(mItemCount, mLatch);
+ }
+
+ FilterableTestItem createFilterableItem(boolean shouldKeepOnFilter) {
+ return new FilterableTestItem(shouldKeepOnFilter, mItemCount, mLatch);
+ }
}
- private class TestItem<T extends TestItem<T>> implements PersisterQueue.WriteQueueItem<T> {
+ private static class TestItem<T extends TestItem<T>>
+ implements PersisterQueue.WriteQueueItem<T> {
+ private AtomicInteger mItemCount;
+ private CountDownLatch mLatch;
+
+ TestItem(AtomicInteger itemCount, CountDownLatch latch) {
+ mItemCount = itemCount;
+ mLatch = latch;
+ }
+
@Override
public void process() {
mItemCount.getAndIncrement();
+ if (mLatch != null) {
+ // Count down the latch at the last step is necessary, as it's a kind of lock to the
+ // next assert in many test cases.
+ mLatch.countDown();
+ }
+ }
+
+ boolean shouldKeepOnFilter() {
+ return true;
}
}
- private class MatchingTestItem extends TestItem<MatchingTestItem> {
- private boolean mMatching;
+ private static class FilterableTestItem extends TestItem<FilterableTestItem> {
+ private boolean mShouldKeepOnFilter;
- private MatchingTestItem mUpdateFromItem;
+ private FilterableTestItem mUpdateFromItem;
- private MatchingTestItem(boolean matching) {
- mMatching = matching;
+ private FilterableTestItem(boolean shouldKeepOnFilter, AtomicInteger mItemCount,
+ CountDownLatch mLatch) {
+ super(mItemCount, mLatch);
+ mShouldKeepOnFilter = shouldKeepOnFilter;
}
@Override
- public boolean matches(MatchingTestItem item) {
- return item.mMatching;
+ public boolean matches(FilterableTestItem item) {
+ return item.mShouldKeepOnFilter;
}
@Override
- public void updateFrom(MatchingTestItem item) {
+ public void updateFrom(FilterableTestItem item) {
mUpdateFromItem = item;
}
+
+ @Override
+ boolean shouldKeepOnFilter() {
+ return mShouldKeepOnFilter;
+ }
+ }
+
+ private class TestPersisterQueueListener implements PersisterQueue.Listener {
+ CountDownLatch mCallbackLatch;
+ final List<Boolean> mProbablyDoneResults = new ArrayList<>();
+
+ @Override
+ public void onPreProcessItem(boolean queueEmpty) {
+ mProbablyDoneResults.add(queueEmpty);
+ mCallbackLatch.countDown();
+ }
+
+ void setExpectedOnPreProcessItemCallbackTimes(int countDown) {
+ mCallbackLatch = new CountDownLatch(countDown);
+ }
+
+ boolean waitForAllExpectedCallbackDone(long timeoutInMilliseconds)
+ throws InterruptedException {
+ return mCallbackLatch.await(timeoutInMilliseconds, TimeUnit.MILLISECONDS);
+ }
}
}