Merge "Fix Tapl drag to folder issue on S5 and R3" into tm-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index c559988..84892f1 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -156,6 +156,12 @@
ALL_APPS_SEARCH_RESULT_LEGACY_SHORTCUT = 30;
ALL_APPS_SEARCH_RESULT_ASSISTANT_MEMORY = 31;
+ // Suggestion Type provided by AGA
+ ONE_SEARCH_WEB_QUERY = 32;
+ ONE_SEARCH_WEB_TRENDING = 33;
+ ONE_SEARCH_WEB_ENTITY = 34;
+ ONE_SEARCH_WEB_ANSWER = 35;
+
WIDGETS_BOTTOM_TRAY = 28;
WIDGETS_TRAY_PREDICTION = 29;
}
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index ff050ea..a1566f0 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -42,5 +42,18 @@
// True if the item's title/content is a direct match to the search query, false otherwise.
optional bool direct_match = 2;
+
+ // Entry point for this on-device search session
+ optional EntryState entry_state = 3;
+
+ enum EntryState{
+ ENTRY_STATE_UNKNOWN = 0;
+
+ // User entered using swipe-up gesture from homescreen and searchbox in AllApps drawer.
+ ALL_APPS = 1;
+
+ // User entered by tapping on QSB bar on homescreen.
+ QSB = 2;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index cb6094b..7083180 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
+import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -344,6 +345,7 @@
getSystemService(SensorManager.class),
getMainThreadHandler(),
getMainExecutor(),
+ /* backgroundExecutor= */ THREAD_POOL_EXECUTOR,
/* tracingTagPrefix= */ "launcher"
);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 24c5d0e..af98b7f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -55,20 +56,20 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Collections;
/**
* Handles long click on Taskbar items to start a system drag and drop operation.
@@ -422,23 +423,18 @@
ItemInfo item = (ItemInfo) tag;
TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
if (item.container == CONTAINER_ALL_APPS) {
- // Since all apps closes when the drag starts, target the all apps button instead
+ // Since all apps closes when the drag starts, target the all apps button instead.
target = taskbarViewController.getAllAppsButtonView();
} else if (item.container >= 0) {
- // Since folders close when the drag starts, target the folder icon instead
- LauncherBindableItemsContainer.ItemOperator op = (info, v) -> {
- if (info instanceof FolderInfo && v instanceof FolderIcon) {
- FolderInfo fi = (FolderInfo) info;
- for (WorkspaceItemInfo si : fi.contents) {
- if (si.id == item.id) {
- // Found the parent
- return true;
- }
- }
- }
- return false;
- };
- target = taskbarViewController.mapOverItems(op);
+ // Since folders close when the drag starts, target the folder icon instead.
+ ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
+ ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
+ target = taskbarViewController.getFirstIconMatch(matcher);
+ } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
+ // Find first icon with same package/user as the deep shortcut.
+ ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
+ Collections.singleton(item.getTargetPackage()), item.user);
+ target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index d083602..6bc4c0a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -29,10 +29,12 @@
import android.content.SharedPreferences;
import android.view.ViewConfiguration;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import java.io.PrintWriter;
import java.util.StringJoiner;
@@ -68,7 +70,8 @@
/**
* How long to stash/unstash when manually invoked via long press.
*/
- public static final long TASKBAR_STASH_DURATION = 300;
+ public static final long TASKBAR_STASH_DURATION =
+ WindowManagerWrapper.ANIMATION_DURATION_RESIZE;
/**
* How long to stash/unstash when keyboard is appearing/disappearing.
@@ -255,6 +258,13 @@
*/
public int getContentHeightToReportToApps() {
if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
+ DeviceProfile dp = mActivity.getDeviceProfile();
+ if (hasAnyFlag(FLAG_STASHED_IN_APP_SETUP) && dp.isTaskbarPresent && !dp.isLandscape) {
+ // We always show the back button in SUW but in portrait the SUW layout may not
+ // be wide enough to support overlapping the nav bar with its content. For now,
+ // just inset by the bar height.
+ return mUnstashedHeight;
+ }
boolean isAnimating = mAnimator != null && mAnimator.isStarted();
return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
? mStashedHeight : 0;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index ade58a9..0b537e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -39,6 +39,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.AllAppsButton;
@@ -367,17 +368,36 @@
}
/**
- * Maps {@code op} over all the child views, returning the view that {@code op} evaluates
- * {@code true} for, or {@code null} if none satisfy {@code op}.
+ * Maps {@code op} over all the child views.
*/
- protected View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+ public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
// map over all the shortcuts on the taskbar
for (int i = 0; i < getChildCount(); i++) {
View item = getChildAt(i);
if (op.evaluate((ItemInfo) item.getTag(), item)) {
- return item;
+ return;
}
}
- return null;
+ }
+
+ /**
+ * Finds the first icon to match one of the given matchers, from highest to lowest priority.
+ * @return The first match, or All Apps button if no match was found.
+ */
+ public View getFirstMatch(ItemInfoMatcher... matchers) {
+ for (ItemInfoMatcher matcher : matchers) {
+ for (int i = 0; i < getChildCount(); i++) {
+ View item = getChildAt(i);
+ if (!(item.getTag() instanceof ItemInfo)) {
+ // Should only happen for All Apps button.
+ continue;
+ }
+ ItemInfo info = (ItemInfo) item.getTag();
+ if (matcher.matchesInfo(info)) {
+ return item;
+ }
+ }
+ }
+ return mAllAppsButton;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 153ed14..6e34ee0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -37,6 +37,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.AnimatedFloat;
@@ -274,8 +275,22 @@
mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
}
- public View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
- return mTaskbarView.mapOverItems(op);
+ /**
+ * Maps the given operator to all the top-level children of TaskbarView.
+ */
+ public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+ mTaskbarView.mapOverItems(op);
+ }
+
+ /**
+ * Returns the first icon to match the given parameter, in priority from:
+ * 1) Icons directly on Taskbar
+ * 2) FolderIcon of the Folder containing the given icon
+ * 3) All Apps button
+ */
+ public View getFirstIconMatch(ItemInfoMatcher matcher) {
+ ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+ return mTaskbarView.getFirstMatch(matcher, folderMatcher);
}
/**
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 5e298f4..783c868 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -44,7 +44,7 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -156,12 +156,26 @@
RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
// Convert appTargets to type RemoteAnimationTarget for all apps except Home app
- RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appearedTaskTargets)
- .filter(remoteAnimationTarget ->
- remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME)
+ final ArrayList<RemoteAnimationTargetCompat> tmpNonHomeApps = new ArrayList<>();
+ final ArrayList<RemoteAnimationTargetCompat> tmpHomeApps = new ArrayList<>();
+ for (RemoteAnimationTargetCompat compat : appearedTaskTargets) {
+ if (compat.activityType != ACTIVITY_TYPE_HOME) {
+ tmpNonHomeApps.add(compat);
+ } else {
+ tmpHomeApps.add(compat);
+ }
+ }
+ RemoteAnimationTarget[] nonHomeApps = tmpNonHomeApps.stream()
.map(RemoteAnimationTargetCompat::unwrap)
.toArray(RemoteAnimationTarget[]::new);
-
+ RemoteAnimationTarget[] homeApps = tmpHomeApps.stream()
+ .map(RemoteAnimationTargetCompat::unwrap)
+ .toArray(RemoteAnimationTarget[]::new);
+ if (homeApps.length > 0
+ && activityInterface.getCreatedActivity() instanceof RecentsActivity) {
+ ((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
+ return;
+ }
RemoteAnimationTarget[] nonAppTargets =
SystemUiProxy.INSTANCE.getNoCreate()
.onGoingToRecentsLegacy(false, nonHomeApps);
@@ -198,8 +212,16 @@
RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
mController != null ? mController.getController() : null,
mCtx.getIApplicationThread());
- final ActivityOptions options = ActivityOptionsCompat.makeRemoteTransition(transition)
- .setTransientLaunch();
+ final ActivityOptions options = ActivityOptionsCompat.makeRemoteTransition(transition);
+ // Allowing to pause Home if Home is top activity and Recents is not Home. So when user
+ // start home when recents animation is playing, the home activity can be resumed again
+ // to let the transition controller collect Home activity.
+ ActivityManager.RunningTaskInfo rti = gestureState.getRunningTask();
+ boolean homeIsOnTop = rti != null && rti.topActivity != null
+ && rti.topActivity.equals(gestureState.getHomeIntent().getComponent());
+ if (!homeIsOnTop) {
+ options.setTransientLaunch();
+ }
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
UI_HELPER_EXECUTOR.execute(() -> mCtx.startActivity(intent, options.toBundle()));
} else {
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 12a638a..f86e790 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -93,8 +93,10 @@
/**
* Flags for converting SearchAttribute to integer value.
*/
- private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1;
+ private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1 << 0;
private static final int SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 << 1;
+ private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS = 1 << 2;
+ private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_QSB = 1 << 3;
public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
new CopyOnWriteArrayList<>();
@@ -110,6 +112,11 @@
return new StatsCompatLogger(mContext, mActivityContext);
}
+ @Override
+ protected StatsLatencyLogger createLatencyLogger() {
+ return new StatsCompatLatencyLogger(mContext, mActivityContext);
+ }
+
/**
* Synchronously writes an itemInfo to stats log
*/
@@ -141,7 +148,9 @@
getCardinality(info) /* cardinality */,
info.getWidget().getSpanX(),
info.getWidget().getSpanY(),
- getFeatures(info));
+ getFeatures(info),
+ null /* attributes */
+ );
}
/**
@@ -170,7 +179,8 @@
info.getAttribute().getNumber(), // attribute_id = 15;
getCardinality(info), // cardinality = 16;
info.getWidget().getSpanX(), // span_x = 17 [default = 1];
- info.getWidget().getSpanY() // span_y = 18 [default = 1];
+ info.getWidget().getSpanY(), // span_y = 18 [default = 1];
+ null /* attributes */
);
}
@@ -413,7 +423,63 @@
atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
getCardinality(atomInfo) /* cardinality */,
getFeatures(atomInfo) /* features */,
- getSearchAttributes(atomInfo) /* searchAttributes */
+ getSearchAttributes(atomInfo) /* searchAttributes */,
+ null /* attributes */
+ );
+ }
+ }
+
+ /**
+ * Helps to construct and log statsd compatible latency events.
+ */
+ private static class StatsCompatLatencyLogger implements StatsLatencyLogger {
+ private final Context mContext;
+ private final Optional<ActivityContext> mActivityContext;
+ private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
+ private LatencyType mType = LatencyType.UNKNOWN;
+ private long mLatencyInMillis;
+
+ StatsCompatLatencyLogger(Context context, ActivityContext activityContext) {
+ mContext = context;
+ mActivityContext = Optional.ofNullable(activityContext);
+ }
+
+ @Override
+ public StatsLatencyLogger withInstanceId(InstanceId instanceId) {
+ this.mInstanceId = instanceId;
+ return this;
+ }
+
+ @Override
+ public StatsLatencyLogger withType(LatencyType type) {
+ this.mType = type;
+ return this;
+ }
+
+ @Override
+ public StatsLatencyLogger withLatency(long latencyInMillis) {
+ this.mLatencyInMillis = latencyInMillis;
+ return this;
+ }
+
+ @Override
+ public void log(EventEnum event) {
+ if (IS_VERBOSE) {
+ String name = (event instanceof Enum) ? ((Enum) event).name() :
+ event.getId() + "";
+
+ Log.d(TAG, mInstanceId == DEFAULT_INSTANCE_ID
+ ? String.format("\n%s = %dms\n", name, mLatencyInMillis)
+ : String.format("\n%s = %dms (InstanceId:%s)\n", name,
+ mLatencyInMillis, mInstanceId));
+ }
+
+ SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_LATENCY,
+ event.getId(), // event_id
+ mInstanceId.getId(), // instance_id
+ 0, // package_id
+ mLatencyInMillis, // latency_in_millis
+ mType.getId() //type
);
}
}
@@ -592,6 +658,12 @@
if (searchAttributes.getDirectMatch()) {
response = response | SEARCH_ATTRIBUTES_DIRECT_MATCH;
}
+ if (searchAttributes.getEntryState() == SearchAttributes.EntryState.ALL_APPS) {
+ response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS;
+ } else if (searchAttributes.getEntryState() == SearchAttributes.EntryState.QSB) {
+ response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_QSB;
+ }
+
return response;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 984b0ef..1d621dc 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -725,7 +725,8 @@
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
- opts.options.setLaunchDisplayId(getRootViewDisplayId());
+ opts.options.setLaunchDisplayId(
+ getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
RecentsView recentsView = getRecentsView();
@@ -766,7 +767,8 @@
// Indicate success once the system has indicated that the transition has started
ActivityOptions opts = ActivityOptionsCompat.makeCustomAnimation(
getContext(), 0, 0, () -> callback.accept(true), MAIN_EXECUTOR.getHandler());
- opts.setLaunchDisplayId(getRootViewDisplayId());
+ opts.setLaunchDisplayId(
+ getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (freezeTaskList) {
ActivityOptionsCompat.setFreezeRecentTasksList(opts);
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 0d2bc37..9604766 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -562,7 +562,7 @@
}
/**
- * Helps to construct and write the log message.
+ * Helps to construct and log launcher event.
*/
public interface StatsLogger {
@@ -662,6 +662,58 @@
}
/**
+ * Helps to construct and log latency event.
+ */
+ public interface StatsLatencyLogger {
+
+ enum LatencyType {
+ UNKNOWN(0),
+ COLD(1),
+ HOT(2);
+
+ private final int mId;
+
+ LatencyType(int id) {
+ this.mId = id;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ }
+
+ /**
+ * Sets {@link InstanceId} of log message.
+ */
+ default StatsLatencyLogger withInstanceId(InstanceId instanceId) {
+ return this;
+ }
+
+
+ /**
+ * Sets latency of the event.
+ */
+ default StatsLatencyLogger withLatency(long latencyInMillis) {
+ return this;
+ }
+
+ /**
+ * Sets {@link LatencyType} of log message.
+ */
+ default StatsLatencyLogger withType(LatencyType type) {
+ return this;
+ }
+
+
+ /**
+ * Builds the final message and logs it as {@link EventEnum}.
+ */
+ default void log(EventEnum event) {
+ }
+ }
+
+ /**
* Returns new logger object.
*/
public StatsLogger logger() {
@@ -672,11 +724,27 @@
return logger;
}
+ /**
+ * Returns new latency logger object.
+ */
+ public StatsLatencyLogger latencyLogger() {
+ StatsLatencyLogger logger = createLatencyLogger();
+ if (mInstanceId != null) {
+ logger.withInstanceId(mInstanceId);
+ }
+ return logger;
+ }
+
protected StatsLogger createLogger() {
return new StatsLogger() {
};
}
+ protected StatsLatencyLogger createLatencyLogger() {
+ return new StatsLatencyLogger() {
+ };
+ }
+
/**
* Sets InstanceId to every new {@link StatsLogger} object returned by {@link #logger()} when
* not-null.