Merge "[Output Switcher] Adjust check for advanced icon" into tm-qpr-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 5ef6855..30eacf3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -68,6 +68,11 @@
*/
private final ArraySet<JobStatus> mChangedJobs = new ArraySet<>();
+ @GuardedBy("mLock")
+ private Boolean mLastReportedStatsdBatteryNotLow = null;
+ @GuardedBy("mLock")
+ private Boolean mLastReportedStatsdStablePower = null;
+
public BatteryController(JobSchedulerService service) {
super(service);
mPowerTracker = new PowerTracker();
@@ -173,6 +178,19 @@
Slog.d(TAG, "maybeReportNewChargingStateLocked: "
+ powerConnected + "/" + stablePower + "/" + batteryNotLow);
}
+
+ if (mLastReportedStatsdStablePower == null
+ || mLastReportedStatsdStablePower != stablePower) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_CHARGING, stablePower);
+ mLastReportedStatsdStablePower = stablePower;
+ }
+ if (mLastReportedStatsdBatteryNotLow == null
+ || mLastReportedStatsdBatteryNotLow != stablePower) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_BATTERY_NOT_LOW,
+ batteryNotLow);
+ mLastReportedStatsdBatteryNotLow = batteryNotLow;
+ }
+
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index f6de109..abbe177 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -153,6 +153,8 @@
changed = true;
}
mDeviceIdleMode = enabled;
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_DEVICE_NOT_DOZING,
+ !mDeviceIdleMode);
if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
mDeviceIdleUpdateFunctor.prepare();
if (enabled) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index a6fae2c..8311dc3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -93,6 +93,8 @@
@Override
public void reportNewIdleState(boolean isIdle) {
synchronized (mLock) {
+ logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_IDLE, isIdle);
+
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = mTrackedTasks.size()-1; i >= 0; i--) {
mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 866dc41..0d85dfd 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -151,13 +151,12 @@
*/
private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
| CONSTRAINT_DEADLINE
- | CONSTRAINT_IDLE
| CONSTRAINT_PREFETCH
| CONSTRAINT_TARE_WEALTH
| CONSTRAINT_TIMING_DELAY
| CONSTRAINT_WITHIN_QUOTA;
- // TODO(b/129954980)
+ // TODO(b/129954980): ensure this doesn't spam statsd, especially at boot
private static final boolean STATS_LOG_ENABLED = false;
// No override.
@@ -1864,7 +1863,7 @@
}
/** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
- private int getProtoConstraint(int constraint) {
+ static int getProtoConstraint(int constraint) {
switch (constraint) {
case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
@@ -1882,8 +1881,12 @@
return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
case CONSTRAINT_IDLE:
return JobServerProtoEnums.CONSTRAINT_IDLE;
+ case CONSTRAINT_PREFETCH:
+ return JobServerProtoEnums.CONSTRAINT_PREFETCH;
case CONSTRAINT_STORAGE_NOT_LOW:
return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
+ case CONSTRAINT_TARE_WEALTH:
+ return JobServerProtoEnums.CONSTRAINT_TARE_WEALTH;
case CONSTRAINT_TIMING_DELAY:
return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
case CONSTRAINT_WITHIN_QUOTA:
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 2a2d602..8453e53 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -26,6 +26,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
import com.android.server.job.StateChangedListener;
@@ -165,6 +166,15 @@
return mService.areComponentsInPlaceLocked(jobStatus);
}
+ protected void logDeviceWideConstraintStateToStatsd(int constraint, boolean satisfied) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED,
+ JobStatus.getProtoConstraint(constraint),
+ satisfied
+ ? FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+ : FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+ }
+
public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate);
public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f5ee467..93c0c4d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3406,6 +3406,7 @@
method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
method public int describeContents();
+ method @NonNull public android.window.WindowContainerTransaction finishActivity(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index ffbdf08..cfad1af 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -706,6 +706,23 @@
}
/**
+ * Finishes the Activity.
+ * Comparing to directly calling {@link android.app.Activity#finish()}, calling this can make
+ * sure the finishing happens in the same transaction with other operations.
+ * @param activityToken activity to be finished.
+ */
+ @NonNull
+ public WindowContainerTransaction finishActivity(@NonNull IBinder activityToken) {
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(
+ HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY)
+ .setContainer(activityToken)
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+ }
+
+ /**
* Sets/removes the always on top flag for this {@code windowContainer}. See
* {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
* Please note that this method is only intended to be used for a
@@ -1163,6 +1180,7 @@
public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20;
+ public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1484,6 +1502,8 @@
+ " alwaysOnTop=" + mAlwaysOnTop + "}";
case HIERARCHY_OP_TYPE_REMOVE_TASK:
return "{RemoveTask: task=" + mContainer + "}";
+ case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
+ return "{finishActivity: activity=" + mContainer + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ " mToTop=" + mToTop
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 87e8ac1..72b9cd2 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -473,7 +473,10 @@
}
}
mCurCombinedState = state;
- mStats.mUidStates.get(mUid).updateCombinedState(state, now);
+ final UidState uidState = mStats.mUidStates.get(mUid);
+ if (uidState != null) {
+ uidState.updateCombinedState(state, now);
+ }
}
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index d3f9e0a..8fcb6d5 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -29,6 +29,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
@@ -174,6 +175,12 @@
*/
public static final int ACTION_FOLD_TO_AOD = 18;
+ /**
+ * Time it takes to show the {@link android.service.voice.VoiceInteractionSession} system UI
+ * after a {@link android.hardware.soundtrigger3.ISoundTriggerHw} voice trigger.
+ */
+ public static final int ACTION_SHOW_VOICE_INTERACTION = 19;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -194,6 +201,7 @@
ACTION_LOAD_SHARE_SHEET,
ACTION_SHOW_SELECTION_TOOLBAR,
ACTION_FOLD_TO_AOD,
+ ACTION_SHOW_VOICE_INTERACTION,
};
/** @hide */
@@ -217,6 +225,7 @@
ACTION_LOAD_SHARE_SHEET,
ACTION_SHOW_SELECTION_TOOLBAR,
ACTION_FOLD_TO_AOD,
+ ACTION_SHOW_VOICE_INTERACTION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -243,6 +252,7 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
};
private static LatencyTracker sLatencyTracker;
@@ -340,6 +350,8 @@
return "ACTION_SHOW_SELECTION_TOOLBAR";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD:
return "ACTION_FOLD_TO_AOD";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION:
+ return "ACTION_SHOW_VOICE_INTERACTION";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 626e0d9..18712ae 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -432,7 +432,7 @@
// In case we have requested to reparent the activity to another container (as
// pendingAppeared), we don't want to finish it with this container.
&& mController.getContainerWithActivity(activity) == this) {
- activity.finish();
+ wct.finishActivity(activity.getActivityToken());
}
}
@@ -457,7 +457,7 @@
|| controller.shouldRetainAssociatedActivity(this, activity)) {
continue;
}
- activity.finish();
+ wct.finishActivity(activity.getActivityToken());
}
mActivitiesToFinishOnExit.clear();
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 179696a..25d0347 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -207,7 +207,7 @@
verify(mSplitPresenter, never()).deleteTaskFragment(any(), any());
verify(mSplitController).removeContainer(tf);
- verify(mActivity, never()).finish();
+ verify(mTransaction, never()).finishActivity(any());
}
@Test
@@ -1004,9 +1004,9 @@
assertTrue(primaryContainer.isFinished());
assertTrue(secondaryContainer0.isFinished());
assertTrue(secondaryContainer1.isFinished());
- verify(mActivity).finish();
- verify(secondaryActivity0).finish();
- verify(secondaryActivity1).finish();
+ verify(mTransaction).finishActivity(mActivity.getActivityToken());
+ verify(mTransaction).finishActivity(secondaryActivity0.getActivityToken());
+ verify(mTransaction).finishActivity(secondaryActivity1.getActivityToken());
assertTrue(taskContainer.mContainers.isEmpty());
assertTrue(taskContainer.mSplitContainers.isEmpty());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 73428a2..35415d8 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -107,30 +107,29 @@
final TaskFragmentContainer container = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
doReturn(container).when(mController).getContainerWithActivity(mActivity);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
// Only remove the activity, but not clear the reference until appeared.
- container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+ container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
- verify(mActivity).finish();
+ verify(mTransaction).finishActivity(mActivity.getActivityToken());
verify(mPresenter, never()).deleteTaskFragment(any(), any());
verify(mController, never()).removeContainer(any());
// Calling twice should not finish activity again.
- clearInvocations(mActivity);
- container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+ clearInvocations(mTransaction);
+ container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
- verify(mActivity, never()).finish();
+ verify(mTransaction, never()).finishActivity(any());
verify(mPresenter, never()).deleteTaskFragment(any(), any());
verify(mController, never()).removeContainer(any());
// Remove all references after the container has appeared in server.
doReturn(new ArrayList<>()).when(mInfo).getActivities();
container.setInfo(mTransaction, mInfo);
- container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+ container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
- verify(mActivity, never()).finish();
- verify(mPresenter).deleteTaskFragment(wct, container.getTaskFragmentToken());
+ verify(mTransaction, never()).finishActivity(any());
+ verify(mPresenter).deleteTaskFragment(mTransaction, container.getTaskFragmentToken());
verify(mController).removeContainer(container);
}
@@ -150,7 +149,7 @@
// The activity is requested to be reparented, so don't finish it.
container0.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
- verify(mActivity, never()).finish();
+ verify(mTransaction, never()).finishActivity(any());
verify(mPresenter).deleteTaskFragment(wct, container0.getTaskFragmentToken());
verify(mController).removeContainer(container0);
}
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index b5fdaca..6bb19ce 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -32,6 +32,8 @@
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
@@ -72,19 +74,32 @@
NOT_SHOWN_REASON_VIEW_CHANGED,
NOT_SHOWN_REASON_ACTIVITY_FINISHED,
NOT_SHOWN_REASON_REQUEST_TIMEOUT,
+ NOT_SHOWN_REASON_REQUEST_FAILED,
+ NOT_SHOWN_REASON_NO_FOCUS,
NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY,
NOT_SHOWN_REASON_UNKNOWN
})
@Retention(RetentionPolicy.SOURCE)
public @interface NotShownReason {}
- public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
- public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
- public static final int NOT_SHOWN_REASON_VIEW_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
- public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
- public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
- public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
- public static final int NOT_SHOWN_REASON_UNKNOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
+ public static final int NOT_SHOWN_REASON_ANY_SHOWN =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
+ public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
+ public static final int NOT_SHOWN_REASON_VIEW_CHANGED =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
+ public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
+ public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
+ public static final int NOT_SHOWN_REASON_REQUEST_FAILED =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
+ public static final int NOT_SHOWN_REASON_NO_FOCUS =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
+ public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
+ public static final int NOT_SHOWN_REASON_UNKNOWN =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
private final int mSessionId;
private Optional<PresentationStatsEventInternal> mEventInternal;
@@ -118,6 +133,14 @@
});
}
+ public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) {
+ mEventInternal.ifPresent(event -> {
+ if (event.mCountShown == 0 && event.mNoPresentationReason == NOT_SHOWN_REASON_UNKNOWN) {
+ event.mNoPresentationReason = reason;
+ }
+ });
+ }
+
public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList,
AutofillId currentViewId) {
mEventInternal.ifPresent(event -> {
@@ -180,7 +203,8 @@
public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
mEventInternal.ifPresent(event -> {
- event.mDisplayPresentationType = UI_TYPE_INLINE;
+ event.mDisplayPresentationType =
+ AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, userId);
if (TextUtils.isEmpty(imeString)) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3d955b7..5c11e2c 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -43,6 +43,8 @@
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_NO_FOCUS;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_FAILED;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_TIMEOUT;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_CHANGED;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED;
@@ -402,6 +404,13 @@
@GuardedBy("mLock")
private PresentationStatsEventLogger mPresentationStatsEventLogger;
+ /**
+ * Fill dialog request would likely be sent slightly later.
+ */
+ @NonNull
+ @GuardedBy("mLock")
+ private boolean mStartedLogEventWithoutFocus;
+
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -522,6 +531,7 @@
}
mLastFillRequest = mPendingFillRequest;
+ mPresentationStatsEventLogger.maybeSetIsNewRequest(true);
mRemoteFillService.onFillRequest(mPendingFillRequest);
mPendingInlineSuggestionsRequest = null;
mWaitForInlineRequest = false;
@@ -1128,6 +1138,7 @@
@Override
public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
@NonNull String servicePackageName, int requestFlags) {
+
final AutofillId[] fieldClassificationIds;
final LogMaker requestLog;
@@ -1285,9 +1296,8 @@
}
}
- // TODO(b/234185326): Add separate reason for failures.
mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
- NOT_SHOWN_REASON_REQUEST_TIMEOUT);
+ timedOut ? NOT_SHOWN_REASON_REQUEST_TIMEOUT : NOT_SHOWN_REASON_REQUEST_FAILED);
mPresentationStatsEventLogger.logAndEndEvent();
}
notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED,
@@ -2816,6 +2826,7 @@
@GuardedBy("mLock")
private boolean requestNewFillResponseOnViewEnteredIfNecessaryLocked(@NonNull AutofillId id,
@NonNull ViewState viewState, int flags) {
+ // Force new response for manual request
if ((flags & FLAG_MANUAL_REQUEST) != 0) {
mSessionFlags.mAugmentedAutofillOnly = false;
if (sDebug) Slog.d(TAG, "Re-starting session on view " + id + " and flags " + flags);
@@ -2823,7 +2834,7 @@
return true;
}
- // If it's not, then check if it it should start a partition.
+ // If it's not, then check if it should start a partition.
if (shouldStartNewPartitionLocked(id)) {
if (sDebug) {
Slog.d(TAG, "Starting partition or augmented request for view id " + id + ": "
@@ -2922,7 +2933,7 @@
if (sDebug) {
Slog.d(TAG, "Set the response has expired.");
}
- mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReasonIfNoReasonExists(
NOT_SHOWN_REASON_VIEW_CHANGED);
mPresentationStatsEventLogger.logAndEndEvent();
return;
@@ -2967,11 +2978,19 @@
// View is triggering autofill.
mCurrentViewId = viewState.id;
viewState.update(value, virtualBounds, flags);
- if (!isRequestSupportFillDialog(flags)) {
- mSessionFlags.mFillDialogDisabled = true;
- }
mPresentationStatsEventLogger.startNewEvent();
mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ if (isRequestSupportFillDialog(flags)) {
+ // Set the default reason for now if the user doesn't trigger any focus event
+ // on the autofillable view. This can be changed downstream when more
+ // information is available or session is committed.
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_NO_FOCUS);
+ mStartedLogEventWithoutFocus = true;
+ } else {
+ mSessionFlags.mFillDialogDisabled = true;
+ mStartedLogEventWithoutFocus = false;
+ }
requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
break;
case ACTION_VALUE_CHANGED:
@@ -3014,6 +3033,8 @@
}
break;
case ACTION_VIEW_ENTERED:
+ boolean startedEventWithoutFocus = mStartedLogEventWithoutFocus;
+ mStartedLogEventWithoutFocus = false;
if (sVerbose && virtualBounds != null) {
Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
}
@@ -3030,9 +3051,15 @@
return;
}
- mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
- NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
- mPresentationStatsEventLogger.logAndEndEvent();
+ // Previously, fill request will only start whenever a view is entered.
+ // With Fill Dialog, request starts prior to view getting entered. So, we can't end
+ // the event at this moment, otherwise we will be wrongly attributing fill dialog
+ // event as concluded.
+ if (!startedEventWithoutFocus) {
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
+ mPresentationStatsEventLogger.logAndEndEvent();
+ }
if ((flags & FLAG_MANUAL_REQUEST) == 0) {
// Not a manual request
@@ -3060,9 +3087,22 @@
}
}
- mPresentationStatsEventLogger.startNewEvent();
- mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ if (!startedEventWithoutFocus) {
+ mPresentationStatsEventLogger.startNewEvent();
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(
+ getAutofillServiceUid());
+ }
if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
+ // If a new request was issued even if previously it was fill dialog request,
+ // we should end the log event, and start a new one. However, it leaves us
+ // susceptible to race condition. But since mPresentationStatsEventLogger is
+ // lock guarded, we should be safe.
+ if (startedEventWithoutFocus) {
+ mPresentationStatsEventLogger.logAndEndEvent();
+ mPresentationStatsEventLogger.startNewEvent();
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(
+ getAutofillServiceUid());
+ }
return;
}
@@ -3289,7 +3329,7 @@
if (requestShowInlineSuggestionsLocked(response, filterText)) {
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_INLINE_SHOWN);
- // TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
+ // TODO(b/248378401): Fix it to log showed only when IME asks for inflation,
// rather than here where framework sends back the response.
mService.logDatasetShown(id, mClientState, UI_TYPE_INLINE);
@@ -3310,7 +3350,6 @@
synchronized (mLock) {
mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
-
mPresentationStatsEventLogger.maybeSetCountShown(
response.getDatasets(), mCurrentViewId);
mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_MENU);
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index dc4bdaa..ce1157e 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
@@ -33,6 +34,8 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.util.LatencyTracker;
+
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -65,9 +68,12 @@
public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
private static final String TAG = "SoundTriggerMiddlewareLogging";
private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
+ private final @NonNull Context mContext;
- public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareInternal delegate) {
+ public SoundTriggerMiddlewareLogging(@NonNull Context context,
+ @NonNull ISoundTriggerMiddlewareInternal delegate) {
mDelegate = delegate;
+ mContext = context;
}
@Override
@@ -298,6 +304,7 @@
int captureSession)
throws RemoteException {
try {
+ startKeyphraseEventLatencyTracking(event);
mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
logVoidReturn("onPhraseRecognition", modelHandle, event);
} catch (Exception e) {
@@ -347,6 +354,26 @@
logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
}
+ /**
+ * Starts the latency tracking log for keyphrase hotword invocation.
+ * The measurement covers from when the SoundTrigger HAL emits an event to when the
+ * {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
+ */
+ private void startKeyphraseEventLatencyTracking(PhraseRecognitionEvent event) {
+ String latencyTrackerTag = null;
+ if (event.phraseExtras.length > 0) {
+ latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id;
+ }
+ LatencyTracker latencyTracker = LatencyTracker.getInstance(mContext);
+ // To avoid adding cancel to all of the different failure modes between here and
+ // showing the system UI, we defensively cancel once.
+ // Either we hit the LatencyTracker timeout of 15 seconds or we defensively cancel
+ // here if any error occurs.
+ latencyTracker.onActionCancel(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION);
+ latencyTracker.onActionStart(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION,
+ latencyTrackerTag);
+ }
+
@Override
public IBinder asBinder() {
return mCallbackDelegate.asBinder();
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index 1995e54..807ed14 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -20,14 +20,14 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseSoundModel;
-import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.SoundModel;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.Identity;
import android.media.permission.PermissionUtil;
import android.media.permission.SafeCloseable;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -226,12 +226,13 @@
HalFactory[] factories = new HalFactory[]{new DefaultHalFactory()};
publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE,
- new SoundTriggerMiddlewareService(new SoundTriggerMiddlewareLogging(
- new SoundTriggerMiddlewarePermission(
- new SoundTriggerMiddlewareValidation(
- new SoundTriggerMiddlewareImpl(factories,
- new AudioSessionProviderImpl())),
- getContext())), getContext()));
+ new SoundTriggerMiddlewareService(
+ new SoundTriggerMiddlewareLogging(getContext(),
+ new SoundTriggerMiddlewarePermission(
+ new SoundTriggerMiddlewareValidation(
+ new SoundTriggerMiddlewareImpl(factories,
+ new AudioSessionProviderImpl())),
+ getContext())), getContext()));
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 9456f0f..2e1477d 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -25,6 +25,7 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER;
@@ -1007,6 +1008,20 @@
isInLockTaskMode);
break;
}
+ case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: {
+ final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
+ if (activity == null || activity.finishing) {
+ break;
+ }
+ if (activity.isVisible()) {
+ // Prevent the transition from being executed too early if the activity is
+ // visible.
+ activity.finishIfPossible("finish-activity-op", false /* oomAdj */);
+ } else {
+ activity.destroyIfPossible("finish-activity-op");
+ }
+ break;
+ }
case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"launchTask HierarchyOp");
@@ -1620,6 +1635,9 @@
organizer);
}
break;
+ case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
+ // Allow finish activity if it has the activity token.
+ break;
default:
// Other types of hierarchy changes are not allowed.
String msg = "Permission Denial: " + func + " from pid="
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 61cf8cc..1404de2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -730,6 +730,16 @@
}
@Test
+ public void testApplyTransaction_finishActivity() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+
+ mTransaction.finishActivity(activity.token);
+ assertApplyTransactionAllowed(mTransaction);
+
+ assertTrue(activity.finishing);
+ }
+
+ @Test
public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
mController.unregisterOrganizer(mIOrganizer);
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 0ce0265..3da4711 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -95,6 +95,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.LatencyTracker;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -191,6 +192,8 @@
mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mServiceStub.systemRunning(isSafeMode());
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ mServiceStub.registerVoiceInteractionSessionListener(mLatencyLoggingListener);
}
}
@@ -2334,4 +2337,36 @@
}
};
}
+
+ /**
+ * End the latency tracking log for keyphrase hotword invocation.
+ * The measurement covers from when the SoundTrigger HAL emits an event, captured in
+ * {@link com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging}
+ * to when the {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
+ */
+ private final IVoiceInteractionSessionListener mLatencyLoggingListener =
+ new IVoiceInteractionSessionListener.Stub() {
+ @Override
+ public void onVoiceSessionShown() throws RemoteException {}
+
+ @Override
+ public void onVoiceSessionHidden() throws RemoteException {}
+
+ @Override
+ public void onVoiceSessionWindowVisibilityChanged(boolean visible)
+ throws RemoteException {
+ if (visible) {
+ LatencyTracker.getInstance(mContext)
+ .onActionEnd(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION);
+ }
+ }
+
+ @Override
+ public void onSetUiHints(Bundle args) throws RemoteException {}
+
+ @Override
+ public IBinder asBinder() {
+ return mServiceStub;
+ }
+ };
}