diff options
| author | 2018-12-07 15:09:30 -0800 | |
|---|---|---|
| committer | 2019-02-25 11:46:03 +0000 | |
| commit | 9f840c715eeb5d73f6c385935a7c47a5daad9878 (patch) | |
| tree | 6b5116a239ce7f7621ed70a6a2708bb6ef829e2d | |
| parent | 4c3ac2ba2653f06bb7151dabca711a01fba2e2b3 (diff) | |
Foldables: Add metric and report usage of the device state over Tron
The device reports the display state and focused app as an action.
The events have
category=ACTION_DISPLAY_FOLD
subtype=0(unfolded) or 1(folded)
package name of focused app.
(include ag/5796847)
The device also reports duration in which state the device is used as
an action.
The events have
category=ACTION_DISPLAY_FOLD
subtype=0x80000000(unfolded) or 0x80000001(folded)
duration is stored in latency field.
(include ag/5781648)
Test: manual - check logcat is output when device is folded/unfolded.
adb logcat -b events | \
fgrep --line-buffered 'sysui_multi_action: [757,1594,'
Bug: 117783763
Change-Id: If7ceafca27c28acf4afa72fe6a9702b9caac669e
5 files changed, 157 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index cf026e97b69f..0db3d78fed5b 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -35,10 +35,12 @@ import com.android.server.wm.WindowManagerInternal; /** * Controls the behavior of foldable devices whose screen can literally bend and fold. + * TODO(b/126160895): Move DisplayFoldController from PhoneWindowManager to DisplayPolicy. */ class DisplayFoldController { private static final String TAG = "DisplayFoldController"; + private final WindowManagerInternal mWindowManagerInternal; private final DisplayManagerInternal mDisplayManagerInternal; private final int mDisplayId; @@ -52,6 +54,8 @@ class DisplayFoldController { private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo(); private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>(); private Boolean mFolded; + private String mFocusedApp; + private final DisplayFoldDurationLogger mDurationLogger = new DisplayFoldDurationLogger(); DisplayFoldController(WindowManagerInternal windowManagerInternal, DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea, @@ -63,6 +67,14 @@ class DisplayFoldController { mHandler = handler; } + void finishedGoingToSleep() { + mDurationLogger.onFinishedGoingToSleep(); + } + + void finishedWakingUp() { + mDurationLogger.onFinishedWakingUp(mFolded); + } + void requestDeviceFolded(boolean folded) { mHandler.post(() -> setDeviceFolded(folded)); } @@ -97,6 +109,8 @@ class DisplayFoldController { mWindowManagerInternal.clearForcedDisplaySize(mDisplayId); mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0); } + mDurationLogger.setDeviceFolded(folded); + mDurationLogger.logFocusedAppWithFoldState(folded, mFocusedApp); mFolded = folded; final int n = mListeners.beginBroadcast(); @@ -167,6 +181,10 @@ class DisplayFoldController { return result; } + void onDefaultDisplayFocusChanged(String pkg) { + mFocusedApp = pkg; + } + static DisplayFoldController create(Context context, int displayId) { final DisplayManagerInternal displayService = LocalServices.getService(DisplayManagerInternal.class); diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java new file mode 100644 index 000000000000..bdcd2cde2e4e --- /dev/null +++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.policy; + +import android.annotation.IntDef; +import android.metrics.LogMaker; +import android.os.SystemClock; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Logger for tracking duration of usage in folded vs unfolded state. + */ +class DisplayFoldDurationLogger { + static final int SCREEN_STATE_UNKNOWN = -1; + static final int SCREEN_STATE_OFF = 0; + static final int SCREEN_STATE_ON_UNFOLDED = 1; + static final int SCREEN_STATE_ON_FOLDED = 2; + + @IntDef(flag = true, prefix = {"SCREEN_STATE_"}, value = { + SCREEN_STATE_UNKNOWN, + SCREEN_STATE_OFF, + SCREEN_STATE_ON_UNFOLDED, + SCREEN_STATE_ON_FOLDED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ScreenState {} + + private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN; + private Long mLastChanged = null; + + private static final int LOG_SUBTYPE_UNFOLDED = 0; + private static final int LOG_SUBTYPE_FOLDED = 1; + private static final int LOG_SUBTYPE_DURATION_MASK = 0x80000000; + + private final MetricsLogger mLogger = new MetricsLogger(); + + void onFinishedWakingUp(Boolean folded) { + if (folded == null) { + mScreenState = SCREEN_STATE_UNKNOWN; + } else if (folded) { + mScreenState = SCREEN_STATE_ON_FOLDED; + } else { + mScreenState = SCREEN_STATE_ON_UNFOLDED; + } + mLastChanged = SystemClock.uptimeMillis(); + } + + void onFinishedGoingToSleep() { + log(); + mScreenState = SCREEN_STATE_OFF; + mLastChanged = null; + } + + void setDeviceFolded(boolean folded) { + // This function is called even when the screen is in ADO mode, but we're only + // interested in the case that the screen is actually on. + if (!isOn()) { + return; + } + log(); + mScreenState = folded ? SCREEN_STATE_ON_FOLDED : SCREEN_STATE_ON_UNFOLDED; + mLastChanged = SystemClock.uptimeMillis(); + } + + void logFocusedAppWithFoldState(boolean folded, String packageName) { + mLogger.write( + new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD) + .setType(MetricsProto.MetricsEvent.TYPE_ACTION) + .setSubtype(folded ? LOG_SUBTYPE_FOLDED : LOG_SUBTYPE_UNFOLDED) + .setPackageName(packageName)); + } + + private void log() { + if (mLastChanged == null) { + return; + } + int subtype; + switch (mScreenState) { + case SCREEN_STATE_ON_UNFOLDED: + subtype = LOG_SUBTYPE_UNFOLDED | LOG_SUBTYPE_DURATION_MASK; + break; + case SCREEN_STATE_ON_FOLDED: + subtype = LOG_SUBTYPE_FOLDED | LOG_SUBTYPE_DURATION_MASK; + break; + default: + return; + } + mLogger.write( + new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD) + .setType(MetricsProto.MetricsEvent.TYPE_ACTION) + .setSubtype(subtype) + .setLatency(SystemClock.uptimeMillis() - mLastChanged)); + } + + private boolean isOn() { + return mScreenState == SCREEN_STATE_ON_UNFOLDED || mScreenState == SCREEN_STATE_ON_FOLDED; + } +} diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c87a81db16e4..77a0789a1cd4 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3237,6 +3237,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public void onDefaultDisplayFocusChangedLw(WindowState newFocus) { + if (mDisplayFoldController != null) { + mDisplayFoldController.onDefaultDisplayFocusChanged( + newFocus != null ? newFocus.getOwningPackage() : null); + } + } + + @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { synchronized (mLock) { @@ -4436,6 +4444,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.onFinishedGoingToSleep(why, mCameraGestureTriggeredDuringGoingToSleep); } + if (mDisplayFoldController != null) { + mDisplayFoldController.finishedGoingToSleep(); + } mCameraGestureTriggeredDuringGoingToSleep = false; } @@ -4476,6 +4487,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguardDelegate != null) { mKeyguardDelegate.onFinishedWakingUp(); } + if (mDisplayFoldController != null) { + mDisplayFoldController.finishedWakingUp(); + } } private void wakeUpFromPowerKey(long eventTime) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index d7e4b6cff4d8..57a44ce61c53 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1485,6 +1485,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** + * A new window on default display has been focused. + */ + default void onDefaultDisplayFocusChangedLw(WindowState newFocus) {} + + /** * Updates the flag about whether AOD is showing. * * @return whether the value was changed. diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 91d573defc16..6ae19050f8f8 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -2787,6 +2787,9 @@ public class DisplayPolicy { public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { mFocusedWindow = newFocus; mLastFocusedWindow = lastFocus; + if (mDisplayContent.isDefaultDisplay) { + mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus); + } if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) { // If the navigation bar has been hidden or shown, we need to do another // layout pass to update that window. |