diff options
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 0759419be608..c0e597497740 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3241,6 +3241,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) { @@ -4440,6 +4448,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.onFinishedGoingToSleep(why, mCameraGestureTriggeredDuringGoingToSleep); } + if (mDisplayFoldController != null) { + mDisplayFoldController.finishedGoingToSleep(); + } mCameraGestureTriggeredDuringGoingToSleep = false; } @@ -4480,6 +4491,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 5cd00145821e..d58707cf2eec 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1489,6 +1489,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 f3f507f156be..b028569ccb08 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. |