diff options
45 files changed, 1097 insertions, 600 deletions
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java index 1d07e88773c3..8f9427303dff 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.os.UserHandle; import android.text.format.TimeMigrationUtils; import android.util.Slog; @@ -34,8 +35,8 @@ class BlobStoreUtils { static Resources getPackageResources(@NonNull Context context, @NonNull String packageName, int userId) { try { - return context.getPackageManager() - .getResourcesForApplicationAsUser(packageName, userId); + return context.createContextAsUser(UserHandle.of(userId), /* flags */ 0) + .getPackageManager().getResourcesForApplication(packageName); } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, "Unknown package in user " + userId + ": " + packageName, e); diff --git a/api/current.txt b/api/current.txt index f007bae5a350..d20bff2da8eb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1613,6 +1613,7 @@ package android { field public static final int windowHideAnimation = 16842935; // 0x10100b7 field public static final int windowIsFloating = 16842839; // 0x1010057 field public static final int windowIsTranslucent = 16842840; // 0x1010058 + field public static final int windowLayoutAffinity = 16844313; // 0x1010619 field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586 field public static final int windowLightNavigationBar = 16844140; // 0x101056c field public static final int windowLightStatusBar = 16844000; // 0x10104e0 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 28bd5406df87..a6fa9ecf113b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3631,7 +3631,7 @@ public final class ActivityThread extends ClientTransactionHandler { TAG, "Handling launch of " + r); // Initialize before creating the activity - if (!ThreadedRenderer.sRendererDisabled + if (ThreadedRenderer.sRendererEnabled && (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { HardwareRenderer.preload(); } @@ -7417,14 +7417,7 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage public static ActivityThread systemMain() { - // The system process on low-memory devices do not get to use hardware - // accelerated drawing, since this can add too much overhead to the - // process. - if (!ActivityManager.isHighEndGfx()) { - ThreadedRenderer.disable(true); - } else { - ThreadedRenderer.enableForegroundTrimming(); - } + ThreadedRenderer.initForSystemProcess(); ActivityThread thread = new ActivityThread(); thread.attach(true, 0); return thread; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index ea4b76257ab7..b371141ca9c1 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1419,6 +1419,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public static final class WindowLayout { public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity, int minWidth, int minHeight) { + this(width, widthFraction, height, heightFraction, gravity, minWidth, minHeight, + null /* windowLayoutAffinity */); + } + + /** @hide */ + public WindowLayout(int width, float widthFraction, int height, float heightFraction, + int gravity, int minWidth, int minHeight, String windowLayoutAffinity) { this.width = width; this.widthFraction = widthFraction; this.height = height; @@ -1426,6 +1433,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { this.gravity = gravity; this.minWidth = minWidth; this.minHeight = minHeight; + this.windowLayoutAffinity = windowLayoutAffinity; } /** @hide */ @@ -1506,6 +1514,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { /** * Affinity of window layout parameters. Activities with the same UID and window layout * affinity will share the same window dimension record. + * + * @attr ref android.R.styleable#AndroidManifestLayout_windowLayoutAffinity * @hide */ public String windowLayoutAffinity; diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index 8c0bfef19d0f..511ee5d9580d 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -368,8 +368,8 @@ public class ParsedActivityUtils { } result = intentResult; } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) { - ParseResult<ActivityInfo.WindowLayout> layoutResult = parseLayout(resources, parser, - input); + ParseResult<ActivityInfo.WindowLayout> layoutResult = + parseActivityWindowLayout(resources, parser, input); if (layoutResult.isSuccess()) { activity.windowLayout = layoutResult.getResult(); } @@ -383,7 +383,8 @@ public class ParsedActivityUtils { } } - ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveWindowLayout(activity, input); + ParseResult<ActivityInfo.WindowLayout> layoutResult = + resolveActivityWindowLayout(activity, input); if (layoutResult.isError()) { return input.error(layoutResult); } @@ -468,7 +469,7 @@ public class ParsedActivityUtils { } @NonNull - private static ParseResult<ActivityInfo.WindowLayout> parseLayout(Resources res, + private static ParseResult<ActivityInfo.WindowLayout> parseActivityWindowLayout(Resources res, AttributeSet attrs, ParseInput input) { TypedArray sw = res.obtainAttributes(attrs, R.styleable.AndroidManifestLayout); try { @@ -496,8 +497,13 @@ public class ParsedActivityUtils { int minWidth = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minWidth, -1); int minHeight = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minHeight, -1); - return input.success(new ActivityInfo.WindowLayout(width, widthFraction, height, - heightFraction, gravity, minWidth, minHeight)); + String windowLayoutAffinity = + sw.getNonConfigurationString( + R.styleable.AndroidManifestLayout_windowLayoutAffinity, 0); + final ActivityInfo.WindowLayout windowLayout = new ActivityInfo.WindowLayout(width, + widthFraction, height, heightFraction, gravity, minWidth, minHeight, + windowLayoutAffinity); + return input.success(windowLayout); } finally { sw.recycle(); } @@ -509,7 +515,7 @@ public class ParsedActivityUtils { * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in * Android R and some variants of pre-R. */ - private static ParseResult<ActivityInfo.WindowLayout> resolveWindowLayout( + private static ParseResult<ActivityInfo.WindowLayout> resolveActivityWindowLayout( ParsedActivity activity, ParseInput input) { // There isn't a metadata for us to fall back. Whatever is in layout is correct. if (activity.metaData == null || !activity.metaData.containsKey( @@ -528,9 +534,10 @@ public class ParsedActivityUtils { if (layout == null) { layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY, - -1 /* minWidth */, -1 /* minHeight */); + -1 /* minWidth */, -1 /* minHeight */, windowLayoutAffinity); + } else { + layout.windowLayoutAffinity = windowLayoutAffinity; } - layout.windowLayoutAffinity = windowLayoutAffinity; return input.success(layout); } } diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index defcab7c3035..a86c5cbd2451 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -267,6 +267,12 @@ public abstract class DisplayManagerInternal { public abstract void ignoreProximitySensorUntilChanged(); /** + * Sets the folded state of the device. + * TODO: b/168208522 - Remove in favor of DisplayStatePolicy when that is available. + */ + public abstract void setDeviceFolded(boolean isFolded); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 14a324dc3abe..57ca71ae4b02 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; import android.graphics.HardwareRenderer; @@ -26,7 +27,6 @@ import android.graphics.Point; import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RenderNode; -import android.os.SystemProperties; import android.os.Trace; import android.util.Log; import android.view.Surface.OutOfResourcesException; @@ -186,37 +186,12 @@ public final class ThreadedRenderer extends HardwareRenderer { public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102; public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103; - static { - // Try to check OpenGL support early if possible. - isAvailable(); - } - - /** - * A process can set this flag to false to prevent the use of threaded - * rendering. - * - * @hide - */ - public static boolean sRendererDisabled = false; - /** * Further threaded renderer disabling for the system process. * * @hide */ - public static boolean sSystemRendererDisabled = false; - - /** - * Invoke this method to disable threaded rendering in the current process. - * - * @hide - */ - public static void disable(boolean system) { - sRendererDisabled = true; - if (system) { - sSystemRendererDisabled = true; - } - } + public static boolean sRendererEnabled = true; public static boolean sTrimForeground = false; @@ -230,16 +205,19 @@ public final class ThreadedRenderer extends HardwareRenderer { sTrimForeground = true; } - /** - * Indicates whether threaded rendering is available under any form for - * the view hierarchy. - * - * @return True if the view hierarchy can potentially be defer rendered, - * false otherwise + * Initialize HWUI for being in a system process like system_server + * Should not be called in non-system processes */ - public static boolean isAvailable() { - return true; + public static void initForSystemProcess() { + // The system process on low-memory devices do not get to use hardware + // accelerated drawing, since this can add too much overhead to the + // process. + if (!ActivityManager.isHighEndGfx()) { + sRendererEnabled = false; + } else { + enableForegroundTrimming(); + } } /** @@ -250,11 +228,7 @@ public final class ThreadedRenderer extends HardwareRenderer { * @return A threaded renderer backed by OpenGL. */ public static ThreadedRenderer create(Context context, boolean translucent, String name) { - ThreadedRenderer renderer = null; - if (isAvailable()) { - renderer = new ThreadedRenderer(context, translucent, name); - } - return renderer; + return new ThreadedRenderer(context, translucent, name); } private static final String[] VISUALIZERS = { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4f05a599c171..cf5ca56eb188 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -23573,8 +23573,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; - if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && - ThreadedRenderer.isAvailable()) { + if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { // This is set if HW acceleration is requested, even if the current // process doesn't allow it. This is just to allow app preview // windows to better match their app. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 52357402877a..5c5f4417380b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1291,10 +1291,6 @@ public final class ViewRootImpl implements ViewParent, (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; if (hardwareAccelerated) { - if (!ThreadedRenderer.isAvailable()) { - return; - } - // Persistent processes (including the system) should not do // accelerated rendering on low-end devices. In that case, // sRendererDisabled will be set. In addition, the system process @@ -1314,8 +1310,7 @@ public final class ViewRootImpl implements ViewParent, // shows for launching applications, so they will look more like // the app being launched. mAttachInfo.mHardwareAccelerationRequested = true; - } else if (!ThreadedRenderer.sRendererDisabled - || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) { + } else if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) { if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.destroy(); } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 8490f2abeffa..f01cbcc1430e 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -527,7 +527,7 @@ public final class WindowManagerGlobal { } allViewsRemoved = mRoots.isEmpty(); } - if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) { + if (ThreadedRenderer.sTrimForeground) { doTrimForeground(); } @@ -561,29 +561,28 @@ public final class WindowManagerGlobal { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void trimMemory(int level) { - if (ThreadedRenderer.isAvailable()) { - if (shouldDestroyEglContext(level)) { - // Destroy all hardware surfaces and resources associated to - // known windows - synchronized (mLock) { - for (int i = mRoots.size() - 1; i >= 0; --i) { - mRoots.get(i).destroyHardwareResources(); - } + + if (shouldDestroyEglContext(level)) { + // Destroy all hardware surfaces and resources associated to + // known windows + synchronized (mLock) { + for (int i = mRoots.size() - 1; i >= 0; --i) { + mRoots.get(i).destroyHardwareResources(); } - // Force a full memory flush - level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; } + // Force a full memory flush + level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; + } - ThreadedRenderer.trimMemory(level); + ThreadedRenderer.trimMemory(level); - if (ThreadedRenderer.sTrimForeground) { - doTrimForeground(); - } + if (ThreadedRenderer.sTrimForeground) { + doTrimForeground(); } } public static void trimForeground() { - if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) { + if (ThreadedRenderer.sTrimForeground) { WindowManagerGlobal wm = WindowManagerGlobal.getInstance(); wm.doTrimForeground(); } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 25c64a9f8781..e3ddbd8d25a2 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -3200,6 +3200,15 @@ then the system will set the same minimal height on all other activities in the task. It will also ignore any other minimal height attributes of non-root activities. --> <attr name="minHeight" /> + + <!-- Window layout affinity of this activity. Activities with the same window layout + affinity will share the same layout record. If an activity is launched in freeform window, + the activity will be launched to the latest position and size where any task, if the root + activity of that task shares the same window layout affinity with the activity being + launched. Window layout affinity is shared only among activities with the same UID. + + <p>By default activity doesn't share any affinity with other activities. --> + <attr name="windowLayoutAffinity" format="string" /> </declare-styleable> <!-- <code>restrict-update</code> tag restricts system apps from being updated unless the diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a334be301a46..c4d096320607 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4443,4 +4443,13 @@ <!-- WindowsManager JetPack display features --> <string name="config_display_features" translatable="false" /> + + <!-- Physical Display IDs of the display-devices that are swapped when a folding device folds. + This list is expected to contain two elements: the first is the display to use + when the device is folded, the second is the display to use when unfolded. If the array + is empty or the display IDs are not recognized, this feature is turned off and the value + ignored. + TODO: b/170470621 - remove once we can have multiple Internal displays in DMS as + well as a notification from DisplayStateManager. --> + <string-array name="config_internalFoldedPhysicalDisplayIds" translatable="false" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index fe17eca35545..45bdff99fb9f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3046,6 +3046,7 @@ <public-group type="attr" first-id="0x01010617"> <public name="rollbackDataPolicy" /> <public name="allowClickWhenDisabled" /> + <public name="windowLayoutAffinity" /> </public-group> <public-group type="drawable" first-id="0x010800b5"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 54101e6b369f..9858f5e7c585 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4076,4 +4076,5 @@ <java-symbol type="array" name="config_keep_warming_services" /> <java-symbol type="string" name="config_display_features" /> + <java-symbol type="array" name="config_internalFoldedPhysicalDisplayIds" /> </resources> diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 3d19cd25da0e..74c79d76bb24 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -1613,6 +1613,7 @@ package android { field public static final int windowHideAnimation = 16842935; // 0x10100b7 field public static final int windowIsFloating = 16842839; // 0x1010057 field public static final int windowIsTranslucent = 16842840; // 0x1010058 + field public static final int windowLayoutAffinity = 16844313; // 0x1010619 field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586 field public static final int windowLightNavigationBar = 16844140; // 0x101056c field public static final int windowLightStatusBar = 16844000; // 0x10104e0 diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index fe5fcc6fd632..1562444f6f87 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -17,24 +17,32 @@ package com.android.keyguard; import android.app.WallpaperManager; -import android.view.View; +import android.content.res.Resources; +import android.text.format.DateFormat; +import android.util.TypedValue; import android.view.ViewGroup; import com.android.internal.colorextraction.ColorExtractor; import com.android.keyguard.clock.ClockManager; +import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.util.ViewController; + +import java.util.Locale; +import java.util.TimeZone; import javax.inject.Inject; /** * Injectable controller for {@link KeyguardClockSwitch}. */ -public class KeyguardClockSwitchController { +public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch> { private static final boolean CUSTOM_CLOCKS_ENABLED = true; - private final KeyguardClockSwitch mView; + private final Resources mResources; private final StatusBarStateController mStatusBarStateController; private final SysuiColorExtractor mColorExtractor; private final ClockManager mClockManager; @@ -65,35 +73,15 @@ public class KeyguardClockSwitchController { private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin; - private final View.OnAttachStateChangeListener mOnAttachStateChangeListener = - new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - if (CUSTOM_CLOCKS_ENABLED) { - mClockManager.addOnClockChangedListener(mClockChangedListener); - } - mStatusBarStateController.addCallback(mStateListener); - mColorExtractor.addOnColorsChangedListener(mColorsListener); - mView.updateColors(getGradientColors()); - } - - @Override - public void onViewDetachedFromWindow(View v) { - if (CUSTOM_CLOCKS_ENABLED) { - mClockManager.removeOnClockChangedListener(mClockChangedListener); - } - mStatusBarStateController.removeCallback(mStateListener); - mColorExtractor.removeOnColorsChangedListener(mColorsListener); - mView.setClockPlugin(null, mStatusBarStateController.getState()); - } - }; - @Inject - public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch, + public KeyguardClockSwitchController( + KeyguardClockSwitch keyguardClockSwitch, + @Main Resources resources, StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor, ClockManager clockManager, KeyguardSliceViewController keyguardSliceViewController) { - mView = keyguardClockSwitch; + super(keyguardClockSwitch); + mResources = resources; mStatusBarStateController = statusBarStateController; mColorExtractor = colorExtractor; mClockManager = clockManager; @@ -103,13 +91,39 @@ public class KeyguardClockSwitchController { /** * Attach the controller to the view it relates to. */ + @Override public void init() { - if (mView.isAttachedToWindow()) { - mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + super.init(); + mKeyguardSliceViewController.init(); + } + + @Override + protected void onViewAttached() { + if (CUSTOM_CLOCKS_ENABLED) { + mClockManager.addOnClockChangedListener(mClockChangedListener); + } + refreshFormat(); + mStatusBarStateController.addCallback(mStateListener); + mColorExtractor.addOnColorsChangedListener(mColorsListener); + mView.updateColors(getGradientColors()); + } + + @Override + protected void onViewDetached() { + if (CUSTOM_CLOCKS_ENABLED) { + mClockManager.removeOnClockChangedListener(mClockChangedListener); } - mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + mStatusBarStateController.removeCallback(mStateListener); + mColorExtractor.removeOnColorsChangedListener(mColorsListener); + mView.setClockPlugin(null, mStatusBarStateController.getState()); + } - mKeyguardSliceViewController.init(); + /** + * Updates clock's text + */ + public void onDensityOrFontScaleChanged() { + mView.setTextSize(TypedValue.COMPLEX_UNIT_PX, + mResources.getDimensionPixelSize(R.dimen.widget_big_font_size)); } /** @@ -119,6 +133,61 @@ public class KeyguardClockSwitchController { mView.setBigClockContainer(bigClockContainer, mStatusBarStateController.getState()); } + /** + * Set whether or not the lock screen is showing notifications. + */ + public void setHasVisibleNotifications(boolean hasVisibleNotifications) { + mView.setHasVisibleNotifications(hasVisibleNotifications); + } + + /** + * If we're presenting a custom clock of just the default one. + */ + public boolean hasCustomClock() { + return mView.hasCustomClock(); + } + + /** + * Get the clock text size. + */ + public float getClockTextSize() { + return mView.getTextSize(); + } + + /** + * Returns the preferred Y position of the clock. + * + * @param totalHeight The height available to position the clock. + * @return Y position of clock. + */ + public int getClockPreferredY(int totalHeight) { + return mView.getPreferredY(totalHeight); + } + + /** + * Refresh clock. Called in response to TIME_TICK broadcasts. + */ + void refresh() { + mView.refresh(); + } + + /** + * Update lockscreen mode that may change clock display. + */ + void updateLockScreenMode(int mode) { + mView.updateLockScreenMode(mode); + } + + void updateTimeZone(TimeZone timeZone) { + mView.onTimeZoneChanged(timeZone); + } + + void refreshFormat() { + Patterns.update(mResources); + mView.setFormat12Hour(Patterns.sClockView12); + mView.setFormat24Hour(Patterns.sClockView24); + } + private void setClockPlugin(ClockPlugin plugin) { mView.setClockPlugin(plugin, mStatusBarStateController.getState()); } @@ -126,4 +195,35 @@ public class KeyguardClockSwitchController { private ColorExtractor.GradientColors getGradientColors() { return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK); } + + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. + // This is an optimization to ensure we only recompute the patterns when the inputs change. + private static final class Patterns { + static String sClockView12; + static String sClockView24; + static String sCacheKey; + + static void update(Resources res) { + final Locale locale = Locale.getDefault(); + final String clockView12Skel = res.getString(R.string.clock_12hr_format); + final String clockView24Skel = res.getString(R.string.clock_24hr_format); + final String key = locale.toString() + clockView12Skel + clockView24Skel; + if (key.equals(sCacheKey)) return; + + sClockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); + // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton + // format. The following code removes the AM/PM indicator if we didn't want it. + if (!clockView12Skel.contains("a")) { + sClockView12 = sClockView12.replaceAll("a", "").trim(); + } + + sClockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); + + // Use fancy colon. + sClockView24 = sClockView24.replace(':', '\uee01'); + sClockView12 = sClockView12.replace(':', '\uee01'); + + sCacheKey = key; + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java index 2470b958a85f..3be7e0a2b0b3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -59,7 +59,6 @@ public class KeyguardSliceViewController implements Dumpable { private static final String TAG = "KeyguardSliceViewCtrl"; private final KeyguardSliceView mView; - private final KeyguardStatusView mKeyguardStatusView; private final ActivityStarter mActivityStarter; private final ConfigurationController mConfigurationController; private final TunerService mTunerService; @@ -135,11 +134,10 @@ public class KeyguardSliceViewController implements Dumpable { @Inject public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView, - KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter, + ActivityStarter activityStarter, ConfigurationController configurationController, TunerService tunerService, DumpManager dumpManager) { mView = keyguardSliceView; - mKeyguardStatusView = keyguardStatusView; mActivityStarter = activityStarter; mConfigurationController = configurationController; mTunerService = tunerService; @@ -153,8 +151,6 @@ public class KeyguardSliceViewController implements Dumpable { } mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); mView.setOnClickListener(mOnClickListener); - // TODO: remove the line below. - mKeyguardStatusView.setKeyguardSliceViewController(this); } /** @@ -233,7 +229,5 @@ public class KeyguardSliceViewController implements Dumpable { public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println(" mSlice: " + mSlice); pw.println(" mClickActions: " + mClickActions); - - mKeyguardStatusView.dump(fd, pw, args); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 9ef2def04ec1..2036b3321bda 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -19,16 +19,13 @@ package com.android.keyguard; import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; -import android.content.res.Resources; import android.graphics.Color; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; -import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Log; -import android.util.Slog; import android.util.TypedValue; import android.view.View; import android.widget.GridLayout; @@ -39,15 +36,18 @@ import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Locale; -import java.util.TimeZone; -public class KeyguardStatusView extends GridLayout implements - ConfigurationController.ConfigurationListener { +/** + * View consisting of: + * - keyguard clock + * - logout button (on certain managed devices) + * - owner information (if set) + * - notification icons (shown on AOD) + */ +public class KeyguardStatusView extends GridLayout { private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardStatusView"; private static final int MARQUEE_DELAY_MS = 2000; @@ -62,9 +62,7 @@ public class KeyguardStatusView extends GridLayout implements private View mNotificationIcons; private Runnable mPendingMarqueeStart; private Handler mHandler; - private KeyguardSliceViewController mKeyguardSliceViewController; - private boolean mPulsing; private float mDarkAmount = 0; private int mTextColor; @@ -76,56 +74,6 @@ public class KeyguardStatusView extends GridLayout implements private int mIconTopMarginWithHeader; private boolean mShowingHeader; - private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onLockScreenModeChanged(int mode) { - updateLockScreenMode(mode); - } - - @Override - public void onTimeChanged() { - refreshTime(); - } - - @Override - public void onTimeZoneChanged(TimeZone timeZone) { - updateTimeZone(timeZone); - } - - @Override - public void onKeyguardVisibilityChanged(boolean showing) { - if (showing) { - if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); - refreshTime(); - updateOwnerInfo(); - updateLogoutView(); - } - } - - @Override - public void onStartedWakingUp() { - setEnableMarquee(true); - } - - @Override - public void onFinishedGoingToSleep(int why) { - setEnableMarquee(false); - } - - @Override - public void onUserSwitchComplete(int userId) { - refreshFormat(); - updateOwnerInfo(); - updateLogoutView(); - } - - @Override - public void onLogoutEnabledChanged() { - updateLogoutView(); - } - }; - public KeyguardStatusView(Context context) { this(context, null, 0); } @@ -142,21 +90,7 @@ public class KeyguardStatusView extends GridLayout implements onDensityOrFontScaleChanged(); } - /** - * If we're presenting a custom clock of just the default one. - */ - public boolean hasCustomClock() { - return mClockView.hasCustomClock(); - } - - /** - * Set whether or not the lock screen is showing notifications. - */ - public void setHasVisibleNotifications(boolean hasVisibleNotifications) { - mClockView.setHasVisibleNotifications(hasVisibleNotifications); - } - - private void setEnableMarquee(boolean enabled) { + void setEnableMarquee(boolean enabled) { if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable")); if (enabled) { if (mPendingMarqueeStart == null) { @@ -203,7 +137,6 @@ public class KeyguardStatusView extends GridLayout implements boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); setEnableMarquee(shouldMarquee); - refreshFormat(); updateOwnerInfo(); updateLogoutView(); updateDark(); @@ -238,64 +171,14 @@ public class KeyguardStatusView extends GridLayout implements layoutOwnerInfo(); } - @Override - public void onDensityOrFontScaleChanged() { - if (mClockView != null) { - mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, - getResources().getDimensionPixelSize(R.dimen.widget_big_font_size)); - } - if (mOwnerInfo != null) { - mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX, - getResources().getDimensionPixelSize(R.dimen.widget_label_font_size)); - } - loadBottomMargin(); - } - - public void dozeTimeTick() { - refreshTime(); - mKeyguardSliceViewController.refresh(); - } - - private void refreshTime() { - mClockView.refresh(); - } - - private void updateLockScreenMode(int mode) { - mClockView.updateLockScreenMode(mode); - } - - private void updateTimeZone(TimeZone timeZone) { - mClockView.onTimeZoneChanged(timeZone); - } - - private void refreshFormat() { - Patterns.update(mContext); - mClockView.setFormat12Hour(Patterns.clockView12); - mClockView.setFormat24Hour(Patterns.clockView24); - } - - public int getLogoutButtonHeight() { + int getLogoutButtonHeight() { if (mLogoutView == null) { return 0; } return mLogoutView.getVisibility() == VISIBLE ? mLogoutView.getHeight() : 0; } - public float getClockTextSize() { - return mClockView.getTextSize(); - } - - /** - * Returns the preferred Y position of the clock. - * - * @param totalHeight The height available to position the clock. - * @return Y position of clock. - */ - public int getClockPreferredY(int totalHeight) { - return mClockView.getPreferredY(totalHeight); - } - - private void updateLogoutView() { + void updateLogoutView() { if (mLogoutView == null) { return; } @@ -305,7 +188,16 @@ public class KeyguardStatusView extends GridLayout implements com.android.internal.R.string.global_action_logout)); } - private void updateOwnerInfo() { + void onDensityOrFontScaleChanged() { + if (mOwnerInfo != null) { + mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize( + com.android.systemui.R.dimen.widget_label_font_size)); + loadBottomMargin(); + } + } + + void updateOwnerInfo() { if (mOwnerInfo == null) return; String info = mLockPatternUtils.getDeviceOwnerInfo(); if (info == null) { @@ -320,30 +212,36 @@ public class KeyguardStatusView extends GridLayout implements updateDark(); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback); - Dependency.get(ConfigurationController.class).addCallback(this); + void setDarkAmount(float darkAmount) { + if (mDarkAmount == darkAmount) { + return; + } + mDarkAmount = darkAmount; + mClockView.setDarkAmount(darkAmount); + updateDark(); } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback); - Dependency.get(ConfigurationController.class).removeCallback(this); - } + void updateDark() { + boolean dark = mDarkAmount == 1; + if (mLogoutView != null) { + mLogoutView.setAlpha(dark ? 0 : 1); + } - @Override - public void onLocaleListChanged() { - refreshFormat(); + if (mOwnerInfo != null) { + boolean hasText = !TextUtils.isEmpty(mOwnerInfo.getText()); + mOwnerInfo.setVisibility(hasText ? VISIBLE : GONE); + layoutOwnerInfo(); + } + + final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount); + mKeyguardSlice.setDarkAmount(mDarkAmount); + mClockView.setTextColor(blendedTextColor); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardStatusView:"); pw.println(" mOwnerInfo: " + (mOwnerInfo == null ? "null" : mOwnerInfo.getVisibility() == VISIBLE)); - pw.println(" mPulsing: " + mPulsing); pw.println(" mDarkAmount: " + mDarkAmount); pw.println(" mTextColor: " + Integer.toHexString(mTextColor)); if (mLogoutView != null) { @@ -363,64 +261,6 @@ public class KeyguardStatusView extends GridLayout implements R.dimen.widget_vertical_padding_with_header); } - // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. - // This is an optimization to ensure we only recompute the patterns when the inputs change. - private static final class Patterns { - static String clockView12; - static String clockView24; - static String cacheKey; - - static void update(Context context) { - final Locale locale = Locale.getDefault(); - final Resources res = context.getResources(); - final String clockView12Skel = res.getString(R.string.clock_12hr_format); - final String clockView24Skel = res.getString(R.string.clock_24hr_format); - final String key = locale.toString() + clockView12Skel + clockView24Skel; - if (key.equals(cacheKey)) return; - - clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); - // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton - // format. The following code removes the AM/PM indicator if we didn't want it. - if (!clockView12Skel.contains("a")) { - clockView12 = clockView12.replaceAll("a", "").trim(); - } - - clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); - - // Use fancy colon. - clockView24 = clockView24.replace(':', '\uee01'); - clockView12 = clockView12.replace(':', '\uee01'); - - cacheKey = key; - } - } - - public void setDarkAmount(float darkAmount) { - if (mDarkAmount == darkAmount) { - return; - } - mDarkAmount = darkAmount; - mClockView.setDarkAmount(darkAmount); - updateDark(); - } - - private void updateDark() { - boolean dark = mDarkAmount == 1; - if (mLogoutView != null) { - mLogoutView.setAlpha(dark ? 0 : 1); - } - - if (mOwnerInfo != null) { - boolean hasText = !TextUtils.isEmpty(mOwnerInfo.getText()); - mOwnerInfo.setVisibility(hasText ? VISIBLE : GONE); - layoutOwnerInfo(); - } - - final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount); - mKeyguardSlice.setDarkAmount(mDarkAmount); - mClockView.setTextColor(blendedTextColor); - } - private void layoutOwnerInfo() { if (mOwnerInfo != null && mOwnerInfo.getVisibility() != GONE) { // Animate owner info during wake-up transition @@ -442,13 +282,6 @@ public class KeyguardStatusView extends GridLayout implements } } - public void setPulsing(boolean pulsing) { - if (mPulsing == pulsing) { - return; - } - mPulsing = pulsing; - } - private boolean shouldShowLogout() { return Dependency.get(KeyguardUpdateMonitor.class).isLogoutEnabled() && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM; @@ -463,9 +296,4 @@ public class KeyguardStatusView extends GridLayout implements Log.e(TAG, "Failed to logout user", re); } } - - // TODO: remove this method when a controller is available. - void setKeyguardSliceViewController(KeyguardSliceViewController keyguardSliceViewController) { - mKeyguardSliceViewController = keyguardSliceViewController; - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java new file mode 100644 index 000000000000..0efb5eea4217 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2020 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.keyguard; + +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; + +import android.util.Slog; +import android.view.View; + +import com.android.systemui.Interpolators; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.AnimatableProperty; +import com.android.systemui.statusbar.notification.PropertyAnimator; +import com.android.systemui.statusbar.notification.stack.AnimationProperties; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.ViewController; + +import java.util.TimeZone; + +import javax.inject.Inject; + +/** + * Injectable controller for {@link KeyguardStatusView}. + */ +public class KeyguardStatusViewController extends ViewController<KeyguardStatusView> { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "KeyguardStatusViewController"; + + private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = + new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + + private final KeyguardSliceViewController mKeyguardSliceViewController; + private final KeyguardClockSwitchController mKeyguardClockSwitchController; + private final KeyguardStateController mKeyguardStateController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final ConfigurationController mConfigurationController; + + private boolean mKeyguardStatusViewAnimating; + + @Inject + public KeyguardStatusViewController( + KeyguardStatusView keyguardStatusView, + KeyguardSliceViewController keyguardSliceViewController, + KeyguardClockSwitchController keyguardClockSwitchController, + KeyguardStateController keyguardStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + ConfigurationController configurationController) { + super(keyguardStatusView); + mKeyguardSliceViewController = keyguardSliceViewController; + mKeyguardClockSwitchController = keyguardClockSwitchController; + mKeyguardStateController = keyguardStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mConfigurationController = configurationController; + } + + @Override + public void init() { + super.init(); + mKeyguardClockSwitchController.init(); + } + + @Override + protected void onViewAttached() { + mKeyguardUpdateMonitor.registerCallback(mInfoCallback); + mConfigurationController.addCallback(mConfigurationListener); + } + + @Override + protected void onViewDetached() { + mKeyguardUpdateMonitor.removeCallback(mInfoCallback); + mConfigurationController.removeCallback(mConfigurationListener); + } + + /** + * Updates views on doze time tick. + */ + public void dozeTimeTick() { + refreshTime(); + mKeyguardSliceViewController.refresh(); + } + + /** + * The amount we're in doze. + */ + public void setDarkAmount(float darkAmount) { + mView.setDarkAmount(darkAmount); + } + + /** + * Set whether or not the lock screen is showing notifications. + */ + public void setHasVisibleNotifications(boolean hasVisibleNotifications) { + mKeyguardClockSwitchController.setHasVisibleNotifications(hasVisibleNotifications); + } + + /** + * If we're presenting a custom clock of just the default one. + */ + public boolean hasCustomClock() { + return mKeyguardClockSwitchController.hasCustomClock(); + } + + /** + * Get the height of the logout button. + */ + public int getLogoutButtonHeight() { + return mView.getLogoutButtonHeight(); + } + + /** + * Set keyguard status view alpha. + */ + public void setAlpha(float alpha) { + if (!mKeyguardStatusViewAnimating) { + mView.setAlpha(alpha); + } + } + + /** + * Set pivot x. + */ + public void setPivotX(float pivot) { + mView.setPivotX(pivot); + } + + /** + * Set pivot y. + */ + public void setPivotY(float pivot) { + mView.setPivotY(pivot); + } + + /** + * Get the clock text size. + */ + public float getClockTextSize() { + return mKeyguardClockSwitchController.getClockTextSize(); + } + + /** + * Returns the preferred Y position of the clock. + * + * @param totalHeight The height available to position the clock. + * @return Y position of clock. + */ + public int getClockPreferredY(int totalHeight) { + return mKeyguardClockSwitchController.getClockPreferredY(totalHeight); + } + + /** + * Get the height of the keyguard status view. + */ + public int getHeight() { + return mView.getHeight(); + } + + /** + * Set whether the view accessibility importance mode. + */ + public void setStatusAccessibilityImportance(int mode) { + mView.setImportantForAccessibility(mode); + } + + /** + * Update position of the view with an optional animation + */ + public void updatePosition(int clockTranslationX, int clockTranslationY, + boolean animateClock) { + PropertyAnimator.setProperty(mView, AnimatableProperty.X, + clockTranslationX, CLOCK_ANIMATION_PROPERTIES, animateClock); + PropertyAnimator.setProperty(mView, AnimatableProperty.Y, + clockTranslationY, CLOCK_ANIMATION_PROPERTIES, animateClock); + } + + /** + * Set the visibility of the keyguard status view based on some new state. + */ + public void setKeyguardStatusViewVisibility( + int statusBarState, + boolean keyguardFadingAway, + boolean goingToFullShade, + int oldStatusBarState) { + mView.animate().cancel(); + mKeyguardStatusViewAnimating = false; + if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD + && statusBarState != KEYGUARD) || goingToFullShade) { + mKeyguardStatusViewAnimating = true; + mView.animate() + .alpha(0f) + .setStartDelay(0) + .setDuration(160) + .setInterpolator(Interpolators.ALPHA_OUT) + .withEndAction( + mAnimateKeyguardStatusViewGoneEndRunnable); + if (keyguardFadingAway) { + mView.animate() + .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) + .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration()) + .start(); + } + } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) { + mView.setVisibility(View.VISIBLE); + mKeyguardStatusViewAnimating = true; + mView.setAlpha(0f); + mView.animate() + .alpha(1f) + .setStartDelay(0) + .setDuration(320) + .setInterpolator(Interpolators.ALPHA_IN) + .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable); + } else if (statusBarState == KEYGUARD) { + if (keyguardFadingAway) { + mKeyguardStatusViewAnimating = true; + mView.animate() + .alpha(0) + .translationYBy(-getHeight() * 0.05f) + .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN) + .setDuration(125) + .setStartDelay(0) + .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable) + .start(); + } else { + mView.setVisibility(View.VISIBLE); + mView.setAlpha(1f); + } + } else { + mView.setVisibility(View.GONE); + mView.setAlpha(1f); + } + } + + private void refreshTime() { + mKeyguardClockSwitchController.refresh(); + } + + private final ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onLocaleListChanged() { + refreshTime(); + } + + @Override + public void onDensityOrFontScaleChanged() { + mKeyguardClockSwitchController.onDensityOrFontScaleChanged(); + mView.onDensityOrFontScaleChanged(); + } + }; + + private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onLockScreenModeChanged(int mode) { + mKeyguardClockSwitchController.updateLockScreenMode(mode); + } + + @Override + public void onTimeChanged() { + refreshTime(); + } + + @Override + public void onTimeZoneChanged(TimeZone timeZone) { + mKeyguardClockSwitchController.updateTimeZone(timeZone); + } + + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + if (showing) { + if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); + refreshTime(); + mView.updateOwnerInfo(); + mView.updateLogoutView(); + } + } + + @Override + public void onStartedWakingUp() { + mView.setEnableMarquee(true); + } + + @Override + public void onFinishedGoingToSleep(int why) { + mView.setEnableMarquee(false); + } + + @Override + public void onUserSwitchComplete(int userId) { + mKeyguardClockSwitchController.refreshFormat(); + mView.updateOwnerInfo(); + mView.updateLogoutView(); + } + + @Override + public void onLogoutEnabledChanged() { + mView.updateLogoutView(); + } + }; + + private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> { + mKeyguardStatusViewAnimating = false; + mView.setVisibility(View.INVISIBLE); + }; + + + private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> { + mKeyguardStatusViewAnimating = false; + mView.setVisibility(View.GONE); + }; + + private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> { + mKeyguardStatusViewAnimating = false; + }; +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java index 21ccff707d34..1b6476ce74df 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -18,6 +18,7 @@ package com.android.keyguard.dagger; import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; +import com.android.keyguard.KeyguardStatusViewController; import dagger.BindsInstance; import dagger.Subcomponent; @@ -36,4 +37,7 @@ public interface KeyguardStatusViewComponent { /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */ KeyguardClockSwitchController getKeyguardClockSwitchController(); + + /** Builds a {@link com.android.keyguard.KeyguardStatusViewController}. */ + KeyguardStatusViewController getKeyguardStatusViewController(); } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 2592a2c4c768..8147f6619cd1 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -317,10 +317,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { updateColorInversion(value); } }; - - mColorInversionSetting.setListening(true); - mColorInversionSetting.onChange(false); } + mColorInversionSetting.setListening(true); + mColorInversionSetting.onChange(false); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); @@ -640,8 +639,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { com.android.internal.R.dimen.rounded_corner_radius_bottom); final boolean changed = mRoundedDefault.x != newRoundedDefault - || mRoundedDefaultTop.x != newRoundedDefault - || mRoundedDefaultBottom.x != newRoundedDefault; + || mRoundedDefaultTop.x != newRoundedDefaultTop + || mRoundedDefaultBottom.x != newRoundedDefaultBottom; if (changed) { // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index e1e77b0723a4..7c3b791aed09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -618,6 +618,7 @@ public class NotificationEntryManager implements NotificationEntry entry = mPendingNotifications.get(key); if (entry != null) { entry.setSbn(notification); + entry.setRanking(ranking); } else { entry = new NotificationEntry( notification, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index 133ddfebe84f..6da4d8b70944 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -41,8 +41,6 @@ import javax.inject.Inject; */ @SysUISingleton public class RankingCoordinator implements Coordinator { - private static final String TAG = "RankingNotificationCoordinator"; - private final StatusBarStateController mStatusBarStateController; private final HighPriorityProvider mHighPriorityProvider; private final NodeController mSilentHeaderController; @@ -65,7 +63,7 @@ public class RankingCoordinator implements Coordinator { mStatusBarStateController.addCallback(mStatusBarStateCallback); pipeline.addPreGroupFilter(mSuspendedFilter); - pipeline.addPreGroupFilter(mDozingFilter); + pipeline.addPreGroupFilter(mDndVisualEffectsFilter); } public NotifSectioner getAlertingSectioner() { @@ -114,10 +112,10 @@ public class RankingCoordinator implements Coordinator { } }; - private final NotifFilter mDozingFilter = new NotifFilter("IsDozingFilter") { + private final NotifFilter mDndVisualEffectsFilter = new NotifFilter( + "DndSuppressingVisualEffects") { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - // Dozing + DND Settings from Ranking object if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { return true; } @@ -130,7 +128,7 @@ public class RankingCoordinator implements Coordinator { new StatusBarStateController.StateListener() { @Override public void onDozingChanged(boolean isDozing) { - mDozingFilter.invalidateList(); + mDndVisualEffectsFilter.invalidateList(); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index d8d412bf2d41..ba88f628d632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -497,7 +497,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif - * or is in a whitelist). + * or is in an allowList). */ public boolean getIsNonblockable() { // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 86d4ac1cb443..47b16c8eaaa5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -70,6 +70,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; +import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.dagger.KeyguardStatusViewComponent; @@ -202,9 +203,6 @@ public class NotificationPanelViewController extends PanelViewController { private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1); private static final Rect EMPTY_RECT = new Rect(); - private static final AnimationProperties - CLOCK_ANIMATION_PROPERTIES = - new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); private final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT = AnimatableProperty.from( "KEYGUARD_HEADS_UP_SHOWING_AMOUNT", (notificationPanelView, aFloat) -> setKeyguardHeadsUpShowingAmount(aFloat), @@ -280,7 +278,7 @@ public class NotificationPanelViewController extends PanelViewController { private ViewGroup mBigClockContainer; private QS mQs; private FrameLayout mQsFrame; - private KeyguardStatusView mKeyguardStatusView; + private KeyguardStatusViewController mKeyguardStatusViewController; private View mQsNavbarScrim; private NotificationsQuickSettingsContainer mNotificationContainerParent; private boolean mAnimateNextPositionUpdate; @@ -344,7 +342,6 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mIsLaunchTransitionRunning; private Runnable mLaunchAnimationEndRunnable; private boolean mOnlyAffordanceInThisMotion; - private boolean mKeyguardStatusViewAnimating; private ValueAnimator mQsSizeChangeAnimator; private boolean mQsScrimEnabled = true; @@ -606,16 +603,8 @@ public class NotificationPanelViewController extends PanelViewController { private void onFinishInflate() { loadDimens(); mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); - mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view); - - KeyguardClockSwitchController keyguardClockSwitchController = - mKeyguardStatusViewComponentFactory - .build(mKeyguardStatusView) - .getKeyguardClockSwitchController(); - keyguardClockSwitchController.init(); mBigClockContainer = mView.findViewById(R.id.big_clock_container); - keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); - + updateViewControllers(mView.findViewById(R.id.keyguard_status_view)); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -689,11 +678,24 @@ public class NotificationPanelViewController extends PanelViewController { R.dimen.heads_up_status_bar_padding); } + private void updateViewControllers(KeyguardStatusView keyguardStatusView) { + // Re-associate the KeyguardStatusViewController + KeyguardStatusViewComponent statusViewComponent = + mKeyguardStatusViewComponentFactory.build(keyguardStatusView); + mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController(); + mKeyguardStatusViewController.init(); + + // Re-associate the clock container with the keyguard clock switch. + KeyguardClockSwitchController keyguardClockSwitchController = + statusViewComponent.getKeyguardClockSwitchController(); + keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); + } + /** * Returns if there's a custom clock being presented. */ public boolean hasCustomClock() { - return mKeyguardStatusView.hasCustomClock(); + return mKeyguardStatusViewController.hasCustomClock(); } private void setStatusBar(StatusBar bar) { @@ -730,21 +732,16 @@ public class NotificationPanelViewController extends PanelViewController { private void reInflateViews() { // Re-inflate the status view group. - int index = mView.indexOfChild(mKeyguardStatusView); - mView.removeView(mKeyguardStatusView); - mKeyguardStatusView = (KeyguardStatusView) mInjectionInflationController.injectable( + KeyguardStatusView keyguardStatusView = mView.findViewById(R.id.keyguard_status_view); + int index = mView.indexOfChild(keyguardStatusView); + mView.removeView(keyguardStatusView); + keyguardStatusView = (KeyguardStatusView) mInjectionInflationController.injectable( LayoutInflater.from(mView.getContext())).inflate( R.layout.keyguard_status_view, mView, false); - mView.addView(mKeyguardStatusView, index); + mView.addView(keyguardStatusView, index); - // Re-associate the clock container with the keyguard clock switch. mBigClockContainer.removeAllViews(); - KeyguardClockSwitchController keyguardClockSwitchController = - mKeyguardStatusViewComponentFactory - .build(mKeyguardStatusView) - .getKeyguardClockSwitchController(); - keyguardClockSwitchController.init(); - keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); + updateViewControllers(keyguardStatusView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); @@ -764,7 +761,11 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusBar.onThemeChanged(); } - setKeyguardStatusViewVisibility(mBarState, false, false); + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( + mBarState, + false, + false, + mBarState); setKeyguardBottomAreaVisibility(mBarState, false); if (mOnReinflationListener != null) { mOnReinflationListener.run(); @@ -858,23 +859,23 @@ public class NotificationPanelViewController extends PanelViewController { } else { int totalHeight = mView.getHeight(); int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); - int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight); + int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight); boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); final boolean hasVisibleNotifications = !bypassEnabled && mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0; - mKeyguardStatusView.setHasVisibleNotifications(hasVisibleNotifications); + mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications); mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding, mNotificationStackScrollLayoutController.getIntrinsicContentHeight(), getExpandedFraction(), - totalHeight, (int) (mKeyguardStatusView.getHeight() - mShelfHeight / 2.0f - - mDarkIconSize / 2.0f), clockPreferredY, hasCustomClock(), + totalHeight, + (int) (mKeyguardStatusViewController.getHeight() + - mShelfHeight / 2.0f - mDarkIconSize / 2.0f), + clockPreferredY, hasCustomClock(), hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, bypassEnabled, getUnlockedStackScrollerPadding()); mClockPositionAlgorithm.run(mClockPositionResult); - PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X, - mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock); - PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y, - mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock); + mKeyguardStatusViewController.updatePosition( + mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock); updateNotificationTranslucency(); updateClock(); stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; @@ -910,7 +911,7 @@ public class NotificationPanelViewController extends PanelViewController { float availableSpace = mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding) - - mKeyguardStatusView.getLogoutButtonHeight(); + - mKeyguardStatusViewController.getLogoutButtonHeight(); int count = 0; ExpandableView previousView = null; for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) { @@ -1005,9 +1006,7 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateClock() { - if (!mKeyguardStatusViewAnimating) { - mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha); - } + mKeyguardStatusViewController.setAlpha(mClockPositionResult.clockAlpha); } public void animateToFullShade(long delay) { @@ -1605,29 +1604,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() { - @Override - public void run() { - mKeyguardStatusViewAnimating = false; - mKeyguardStatusView.setVisibility(View.INVISIBLE); - } - }; - - private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = new Runnable() { - @Override - public void run() { - mKeyguardStatusViewAnimating = false; - mKeyguardStatusView.setVisibility(View.GONE); - } - }; - - private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = new Runnable() { - @Override - public void run() { - mKeyguardStatusViewAnimating = false; - } - }; - private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() { @Override public void run() { @@ -1705,46 +1681,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - private void setKeyguardStatusViewVisibility(int statusBarState, boolean keyguardFadingAway, - boolean goingToFullShade) { - mKeyguardStatusView.animate().cancel(); - mKeyguardStatusViewAnimating = false; - if ((!keyguardFadingAway && mBarState == KEYGUARD - && statusBarState != KEYGUARD) || goingToFullShade) { - mKeyguardStatusViewAnimating = true; - mKeyguardStatusView.animate().alpha(0f).setStartDelay(0).setDuration( - 160).setInterpolator(Interpolators.ALPHA_OUT).withEndAction( - mAnimateKeyguardStatusViewGoneEndRunnable); - if (keyguardFadingAway) { - mKeyguardStatusView.animate().setStartDelay( - mKeyguardStateController.getKeyguardFadingAwayDelay()).setDuration( - mKeyguardStateController.getShortenedFadingAwayDuration()).start(); - } - } else if (mBarState == StatusBarState.SHADE_LOCKED - && statusBarState == KEYGUARD) { - mKeyguardStatusView.setVisibility(View.VISIBLE); - mKeyguardStatusViewAnimating = true; - mKeyguardStatusView.setAlpha(0f); - mKeyguardStatusView.animate().alpha(1f).setStartDelay(0).setDuration( - 320).setInterpolator(Interpolators.ALPHA_IN).withEndAction( - mAnimateKeyguardStatusViewVisibleEndRunnable); - } else if (statusBarState == KEYGUARD) { - if (keyguardFadingAway) { - mKeyguardStatusViewAnimating = true; - mKeyguardStatusView.animate().alpha(0).translationYBy( - -getHeight() * 0.05f).setInterpolator( - Interpolators.FAST_OUT_LINEAR_IN).setDuration(125).setStartDelay( - 0).withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable).start(); - } else { - mKeyguardStatusView.setVisibility(View.VISIBLE); - mKeyguardStatusView.setAlpha(1f); - } - } else { - mKeyguardStatusView.setVisibility(View.GONE); - mKeyguardStatusView.setAlpha(1f); - } - } - private void updateQsState() { mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded); mNotificationStackScrollLayoutController.setScrollingEnabled( @@ -2075,7 +2011,7 @@ public class NotificationPanelViewController extends PanelViewController { private int getMaxPanelHeightBypass() { int position = mClockPositionAlgorithm.getExpandedClockPosition() - + mKeyguardStatusView.getHeight(); + + mKeyguardStatusViewController.getHeight(); if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0) { position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f; } @@ -2156,7 +2092,7 @@ public class NotificationPanelViewController extends PanelViewController { int minKeyguardPanelBottom = mClockPositionAlgorithm.getExpandedClockPosition() - + mKeyguardStatusView.getHeight() + + mKeyguardStatusViewController.getHeight() + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(); return Math.max(maxHeight, minKeyguardPanelBottom); } else { @@ -2604,7 +2540,7 @@ public class NotificationPanelViewController extends PanelViewController { } public void onScreenTurningOn() { - mKeyguardStatusView.dozeTimeTick(); + mKeyguardStatusViewController.dozeTimeTick(); } @Override @@ -2989,7 +2925,6 @@ public class NotificationPanelViewController extends PanelViewController { mAnimateNextPositionUpdate = false; } mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse); - mKeyguardStatusView.setPulsing(pulsing); } public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) { @@ -3001,14 +2936,14 @@ public class NotificationPanelViewController extends PanelViewController { public void dozeTimeTick() { mKeyguardBottomArea.dozeTimeTick(); - mKeyguardStatusView.dozeTimeTick(); + mKeyguardStatusViewController.dozeTimeTick(); if (mInterpolatedDarkAmount > 0) { positionClockAndNotifications(); } } public void setStatusAccessibilityImportance(int mode) { - mKeyguardStatusView.setImportantForAccessibility(mode); + mKeyguardStatusViewController.setStatusAccessibilityImportance(mode); } /** @@ -3068,8 +3003,11 @@ public class NotificationPanelViewController extends PanelViewController { * security view of the bouncer. */ public void onBouncerPreHideAnimation() { - setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */, - false /* goingToFullShade */); + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( + mBarState, + true /* keyguardFadingAway */, + false /* goingToFullShade */, + mBarState); } /** @@ -3639,7 +3577,11 @@ public class NotificationPanelViewController extends PanelViewController { int oldState = mBarState; boolean keyguardShowing = statusBarState == KEYGUARD; - setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade); + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( + statusBarState, + keyguardFadingAway, + goingToFullShade, + mBarState); setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade); mBarState = statusBarState; @@ -3690,7 +3632,7 @@ public class NotificationPanelViewController extends PanelViewController { public void onDozeAmountChanged(float linearAmount, float amount) { mInterpolatedDarkAmount = amount; mLinearDarkAmount = linearAmount; - mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount); + mKeyguardStatusViewController.setDarkAmount(mInterpolatedDarkAmount); mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount); positionClockAndNotifications(); } @@ -3736,9 +3678,10 @@ public class NotificationPanelViewController extends PanelViewController { setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth()); // Update Clock Pivot - mKeyguardStatusView.setPivotX(mView.getWidth() / 2); - mKeyguardStatusView.setPivotY( - (FONT_HEIGHT - CAP_HEIGHT) / 2048f * mKeyguardStatusView.getClockTextSize()); + mKeyguardStatusViewController.setPivotX(mView.getWidth() / 2); + mKeyguardStatusViewController.setPivotY( + (FONT_HEIGHT - CAP_HEIGHT) / 2048f + * mKeyguardStatusViewController.getClockTextSize()); // Calculate quick setting heights. int oldMaxHeight = mQsMaxExpansionHeight; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 3aa6ec08683f..094230db9d8c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.res.Resources; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.view.View; @@ -64,6 +65,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { ColorExtractor.GradientColors mGradientColors; @Mock KeyguardSliceViewController mKeyguardSliceViewController; + @Mock + Resources mResources; private KeyguardClockSwitchController mController; @@ -72,9 +75,13 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); when(mView.isAttachedToWindow()).thenReturn(true); - + when(mResources.getString(anyInt())).thenReturn("h:mm"); mController = new KeyguardClockSwitchController( - mView, mStatusBarStateController, mColorExtractor, mClockManager, + mView, + mResources, + mStatusBarStateController, + mColorExtractor, + mClockManager, mKeyguardSliceViewController); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java index b7bcaa3c3566..9f8f6c1940ef 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java @@ -44,9 +44,7 @@ import org.mockito.MockitoAnnotations; @RunWithLooper(setAsMainLooper = true) public class KeyguardSliceViewControllerTest extends SysuiTestCase { @Mock - private KeyguardSliceView mView;; - @Mock - private KeyguardStatusView mKeyguardStatusView; + private KeyguardSliceView mView; @Mock private TunerService mTunerService; @Mock @@ -63,7 +61,7 @@ public class KeyguardSliceViewControllerTest extends SysuiTestCase { when(mView.isAttachedToWindow()).thenReturn(true); when(mView.getContext()).thenReturn(mContext); mController = new KeyguardSliceViewController( - mView, mKeyguardStatusView, mActivityStarter, mConfigurationController, + mView, mActivityStarter, mConfigurationController, mTunerService, mDumpManager); mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java new file mode 100644 index 000000000000..752a744826a1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 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.keyguard; + +import static org.mockito.Mockito.verify; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class KeyguardStatusViewControllerTest extends SysuiTestCase { + + @Mock + private KeyguardStatusView mKeyguardStatusView; + @Mock + private KeyguardSliceViewController mKeyguardSliceViewController; + @Mock + private KeyguardClockSwitchController mKeyguardClockSwitchController; + @Mock + private KeyguardStateController mKeyguardStateController; + @Mock + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + ConfigurationController mConfigurationController; + + private KeyguardStatusViewController mController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mController = new KeyguardStatusViewController( + mKeyguardStatusView, + mKeyguardSliceViewController, + mKeyguardClockSwitchController, + mKeyguardStateController, + mKeyguardUpdateMonitor, + mConfigurationController); + } + + @Test + public void dozeTimeTick_updatesSlice() { + mController.dozeTimeTick(); + verify(mKeyguardSliceViewController).refresh(); + } + + @Test + public void dozeTimeTick_updatesClock() { + mController.dozeTimeTick(); + verify(mKeyguardClockSwitchController).refresh(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java deleted file mode 100644 index 79ec4f2c553a..000000000000 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2018 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.keyguard; - -import static org.mockito.Mockito.verify; - -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper.RunWithLooper; -import android.view.LayoutInflater; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -@SmallTest -@RunWithLooper -@RunWith(AndroidTestingRunner.class) -public class KeyguardStatusViewTest extends SysuiTestCase { - - @Mock - KeyguardSliceViewController mKeyguardSliceViewController; - - @Mock - KeyguardClockSwitch mClockView; - @InjectMocks - KeyguardStatusView mKeyguardStatusView; - - @Before - public void setUp() { - allowTestableLooperAsMainThread(); - LayoutInflater layoutInflater = LayoutInflater.from(getContext()); - mKeyguardStatusView = - (KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null); - org.mockito.MockitoAnnotations.initMocks(this); - } - - @Test - public void dozeTimeTick_updatesSlice() { - mKeyguardStatusView.dozeTimeTick(); - verify(mKeyguardSliceViewController).refresh(); - } - - @Test - public void dozeTimeTick_updatesClock() { - mKeyguardStatusView.dozeTimeTick(); - verify(mClockView).refresh(); - } - -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index ab805f42ab56..0c87f59af822 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -621,6 +621,44 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5)); } + @Test + public void testOnlyRoundedCornerRadiusTop() { + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius, 0); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_top, 10); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_bottom, 0); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); + + mScreenDecorations.start(); + assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); + assertEquals(new Point(10, 10), mScreenDecorations.mRoundedDefaultTop); + assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultBottom); + } + + @Test + public void testOnlyRoundedCornerRadiusBottom() { + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius, 0); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_top, 0); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_bottom, 20); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); + + mScreenDecorations.start(); + assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); + assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultTop); + assertEquals(new Point(20, 20), mScreenDecorations.mRoundedDefaultBottom); + } + @Test public void testBoundingRectsToRegion() throws Exception { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index d04d8ee76b99..0be9f7de5825 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -380,6 +380,36 @@ public class NotificationEntryManagerTest extends SysuiTestCase { } @Test + public void testUpdatePendingNotification_rankingUpdated() { + // GIVEN a notification with ranking is pending + final Ranking originalRanking = mEntry.getRanking(); + mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry); + + // WHEN the same notification has been updated with a new ranking + final int newRank = 2345; + doAnswer(invocationOnMock -> { + Ranking ranking = (Ranking) + invocationOnMock.getArguments()[1]; + ranking.populate( + mEntry.getKey(), + newRank, /* this changed!! */ + false, + 0, + 0, + IMPORTANCE_DEFAULT, + null, null, + null, null, null, true, + Ranking.USER_SENTIMENT_NEUTRAL, false, -1, + false, null, null, false, false, false, null, 0, false); + return true; + }).when(mRankingMap).getRanking(eq(mEntry.getKey()), any(Ranking.class)); + mEntryManager.addNotification(mSbn, mRankingMap); + + // THEN ranking for the entry has been updated with new ranking + assertEquals(newRank, mEntry.getRanking().getRank()); + } + + @Test public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() { // GIVEN an entry manager with a notification mEntryManager.addActiveNotificationForTest(mEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 386844317720..cb56f1fbc054 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -53,6 +53,7 @@ import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; +import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.R; @@ -190,6 +191,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock + private KeyguardStatusViewController mKeyguardStatusViewController; + @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; private NotificationPanelViewController mNotificationPanelViewController; @@ -246,6 +249,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { .thenReturn(mKeyguardStatusViewComponent); when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController()) .thenReturn(mKeyguardClockSwitchController); + when(mKeyguardStatusViewComponent.getKeyguardStatusViewController()) + .thenReturn(mKeyguardStatusViewController); mNotificationPanelViewController = new NotificationPanelViewController(mView, mResources, mInjectionInflationController, diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index fc6abc8d2dd2..35f119428dc7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -236,7 +236,6 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.HashMap; @@ -6203,20 +6202,12 @@ public class ConnectivityService extends IConnectivityManager.Stub return; // no updating necessary } - final NetworkAgentInfo defaultNai = getDefaultNetwork(); - final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); - if (DBG) { final Collection<InetAddress> dnses = newLp.getDnsServers(); log("Setting DNS servers for network " + netId + " to " + dnses); } try { mDnsManager.noteDnsServersForNetwork(netId, newLp); - // TODO: netd should listen on [::1]:53 and proxy queries to the current - // default network, and we should just set net.dns1 to ::1, not least - // because applications attempting to use net.dns resolvers will bypass - // the privacy protections of things like DNS-over-TLS. - if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers()); mDnsManager.flushVmDnsCache(); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); @@ -6731,8 +6722,6 @@ public class ConnectivityService extends IConnectivityManager.Stub ? newNetwork.linkProperties.getHttpProxy() : null); updateTcpBufferSizes(null != newNetwork ? newNetwork.linkProperties.getTcpBufferSizes() : null); - mDnsManager.setDefaultDnsSystemProperties(null != newNetwork - ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST); notifyIfacesChangedForNetworkStats(); // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. updateAllVpnsCapabilities(); diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index cf6a7f6e8d70..271ec4eac9e8 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -50,7 +50,6 @@ import android.util.Slog; import java.net.InetAddress; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -245,7 +244,6 @@ public class DnsManager { private final Map<Integer, LinkProperties> mLinkPropertiesMap; private final Map<Integer, int[]> mTransportsMap; - private int mNumDnsEntries; private int mSampleValidity; private int mSuccessThreshold; private int mMinSamples; @@ -409,18 +407,6 @@ public class DnsManager { } } - public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { - int last = 0; - for (InetAddress dns : dnses) { - ++last; - setNetDnsProperty(last, dns.getHostAddress()); - } - for (int i = last + 1; i <= mNumDnsEntries; ++i) { - setNetDnsProperty(i, ""); - } - mNumDnsEntries = last; - } - /** * Flush DNS caches and events work before boot has completed. */ @@ -476,16 +462,6 @@ public class DnsManager { return Settings.Global.getInt(mContentResolver, which, dflt); } - private void setNetDnsProperty(int which, String value) { - final String key = "net.dns" + which; - // Log and forget errors setting unsupported properties. - try { - mSystemProperties.set(key, value); - } catch (Exception e) { - Slog.e(TAG, "Error setting unsupported net.dns property: ", e); - } - } - private static String getPrivateDnsMode(ContentResolver cr) { String mode = getStringSetting(cr, PRIVATE_DNS_MODE); if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE); diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java index aa4db29e0d49..5c0fceb9b795 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java +++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java @@ -112,6 +112,17 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener { } } + public DisplayDevice getByIdLocked(@NonNull String uniqueId) { + final int count = mDisplayDevices.size(); + for (int i = 0; i < count; i++) { + final DisplayDevice d = mDisplayDevices.get(i); + if (uniqueId.equals(d.getUniqueId())) { + return d; + } + } + return null; + } + private void handleDisplayDeviceAdded(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index ffce3be4b769..a600292eca31 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -324,7 +324,7 @@ public final class DisplayManagerService extends SystemService { mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore); - mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, + mLogicalDisplayMapper = new LogicalDisplayMapper(context, mDisplayDeviceRepo, new LogicalDisplayListener(), mPersistentDataStore); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); Resources resources = mContext.getResources(); @@ -576,6 +576,7 @@ public final class DisplayManagerService extends SystemService { Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestGlobalDisplayState(" + Display.stateToString(state) + ", brightness=" + brightnessState + ")"); + mGlobalDisplayState = state; mGlobalDisplayBrightness = brightnessState; applyGlobalDisplayStateLocked(mTempDisplayStateWorkQueue); @@ -983,6 +984,15 @@ public final class DisplayManagerService extends SystemService { scheduleTraversalLocked(false); } + private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) { + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + final Runnable work = updateDisplayStateLocked(device); + if (work != null) { + mHandler.post(work); + } + handleLogicalDisplayChangedLocked(display); + } + private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) { mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { Runnable runnable = updateDisplayStateLocked(device); @@ -997,10 +1007,15 @@ public final class DisplayManagerService extends SystemService { // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { - // TODO - multi-display - The rules regarding what display state to apply to each + // TODO - b/170498827 The rules regarding what display state to apply to each // display will depend on the configuration/mapping of logical displays. - return device.requestDisplayStateLocked( - mGlobalDisplayState, mGlobalDisplayBrightness); + // Clean up LogicalDisplay.isEnabled() mechanism once this is fixed. + int state = mGlobalDisplayState; + final LogicalDisplay display = mLogicalDisplayMapper.getLocked(device); + if (display != null && !display.isEnabled()) { + state = Display.STATE_OFF; + } + return device.requestDisplayStateLocked(state, mGlobalDisplayBrightness); } return null; } @@ -1346,6 +1361,12 @@ public final class DisplayManagerService extends SystemService { } } + void setFoldOverride(Boolean isFolded) { + synchronized (mSyncRoot) { + mLogicalDisplayMapper.setFoldOverrideLocked(isFolded); + } + } + private void clearViewportsLocked() { mViewports.clear(); } @@ -1698,6 +1719,10 @@ public final class DisplayManagerService extends SystemService { case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED: handleLogicalDisplayRemovedLocked(display); break; + + case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_SWAPPED: + handleLogicalDisplaySwappedLocked(display); + break; } } @@ -2538,6 +2563,13 @@ public final class DisplayManagerService extends SystemService { public void ignoreProximitySensorUntilChanged() { mDisplayPowerController.ignoreProximitySensorUntilChanged(); } + + @Override + public void setDeviceFolded(boolean isFolded) { + synchronized (mSyncRoot) { + mLogicalDisplayMapper.setDeviceFoldedLocked(isFolded); + } + } } class DesiredDisplayModeSpecsObserver diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java index 0c6c797b917a..111664a078df 100644 --- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java +++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java @@ -56,6 +56,8 @@ class DisplayManagerShellCommand extends ShellCommand { return setDisplayWhiteBalanceLoggingEnabled(false); case "dwb-set-cct": return setAmbientColorTemperatureOverride(); + case "set-fold": + return setFoldOverride(); default: return handleDefaultCommands(cmd); } @@ -82,6 +84,8 @@ class DisplayManagerShellCommand extends ShellCommand { pw.println(" Disable display white-balance logging."); pw.println(" dwb-set-cct CCT"); pw.println(" Sets the ambient color temperature override to CCT (use -1 to disable)."); + pw.println(" set-fold [fold|unfold|reset]"); + pw.println(" Simulates the 'fold' state of a device. 'reset' for default behavior."); pw.println(); Intent.printIntentArgsHelp(pw , ""); } @@ -148,4 +152,26 @@ class DisplayManagerShellCommand extends ShellCommand { mService.setAmbientColorTemperatureOverride(cct); return 0; } + + private int setFoldOverride() { + String state = getNextArg(); + if (state == null) { + getErrPrintWriter().println("Error: no parameter specified for set-fold"); + return 1; + } + final Boolean isFolded; + if ("fold".equals(state)) { + isFolded = true; + } else if ("unfold".equals(state)) { + isFolded = false; + } else if ("reset".equals(state)) { + isFolded = null; + } else { + getErrPrintWriter().println("Error: Invalid fold state request: " + state); + return 1; + } + + mService.setFoldOverride(isFolded); + return 0; + } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index bf8b891cffb8..a17a294cd1d7 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -16,9 +16,11 @@ package com.android.server.display; +import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManagerInternal; +import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -57,6 +59,7 @@ import java.util.Objects; * </p> */ final class LogicalDisplay { + private static final String TAG = "LogicalDisplay"; private final DisplayInfo mBaseDisplayInfo = new DisplayInfo(); // The layer stack we use when the display has been blanked to prevent any @@ -114,6 +117,12 @@ final class LogicalDisplay { private final Rect mTempLayerStackRect = new Rect(); private final Rect mTempDisplayRect = new Rect(); + /** + * Indicates that the Logical display is enabled (default). See {@link #setEnabled} for + * more information. + */ + private boolean mIsEnabled = true; + public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { mDisplayId = displayId; mLayerStack = layerStack; @@ -575,6 +584,44 @@ final class LogicalDisplay { mDisplayScalingDisabled = disableScaling; } + /** + * Swap the underlying {@link DisplayDevice} with the specificed LogicalDisplay. + * + * @param targetDisplay The display with which to swap display-devices. + * @return {@code true} if the displays were swapped, {@code false} otherwise. + */ + public boolean swapDisplaysLocked(@NonNull LogicalDisplay targetDisplay) { + final DisplayDevice targetDevice = targetDisplay.getPrimaryDisplayDeviceLocked(); + if (mPrimaryDisplayDevice == null || targetDevice == null) { + Slog.e(TAG, "Missing display device during swap: " + mPrimaryDisplayDevice + " , " + + targetDevice); + return false; + } + + final DisplayDevice tmpDevice = mPrimaryDisplayDevice; + mPrimaryDisplayDevice = targetDisplay.mPrimaryDisplayDevice; + targetDisplay.mPrimaryDisplayDevice = tmpDevice; + return true; + } + + /** + * Sets the LogicalDisplay to be enabled or disabled. If the display is not enabled, + * the system will always set the display to power off, regardless of the global state of the + * device. + * TODO: b/170498827 - Remove when updateDisplayStateLocked is updated. + */ + public void setEnabled(boolean isEnabled) { + mIsEnabled = isEnabled; + } + + /** + * @return {@code true} iff the LogicalDisplay is enabled or {@code false} + * if disabled indicating that the display has been forced to be OFF. + */ + public boolean isEnabled() { + return mIsEnabled; + } + public void dumpLocked(PrintWriter pw) { pw.println("mDisplayId=" + mDisplayId); pw.println("mLayerStack=" + mLayerStack); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 8a90a142a765..942a12ebf64e 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -16,7 +16,9 @@ package com.android.server.display; +import android.content.Context; import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; import android.view.Display; @@ -26,6 +28,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Objects; import java.util.function.Consumer; /** @@ -39,9 +42,12 @@ import java.util.function.Consumer; class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private static final String TAG = "LogicalDisplayMapper"; + private static final boolean DEBUG = false; + public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1; public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2; public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3; + public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4; /** * Temporary display info, used for comparing display configurations. @@ -59,6 +65,24 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final boolean mSingleDisplayDemoMode; /** + * Physical Display ID of the DisplayDevice to associate with the default LogicalDisplay + * when {@link mIsFolded} is set to {@code true}. + */ + private String mDisplayIdToUseWhenFolded; + + /** + * Physical Display ID of the DisplayDevice to associate with the default LogicalDisplay + * when {@link mIsFolded} is set to {@code false}. + */ + private String mDisplayIdToUseWhenUnfolded; + + /** Overrides the folded state of the device. For use with ADB commands. */ + private Boolean mIsFoldedOverride; + + /** Saves the last device fold state. */ + private boolean mIsFolded; + + /** * List of all logical displays indexed by logical display id. * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. * TODO: multi-display - Move the aforementioned comment? @@ -71,13 +95,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final PersistentDataStore mPersistentDataStore; private final Listener mListener; - LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener, + LogicalDisplayMapper(Context context, DisplayDeviceRepository repo, Listener listener, PersistentDataStore persistentDataStore) { mDisplayDeviceRepo = repo; mPersistentDataStore = persistentDataStore; mListener = listener; mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mDisplayDeviceRepo.addListener(this); + + loadFoldedDisplayConfig(context); } @Override @@ -141,23 +167,104 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } } + public void setDeviceFoldedLocked(boolean isFolded) { + mIsFolded = isFolded; + if (mIsFoldedOverride != null) { + isFolded = mIsFoldedOverride.booleanValue(); + } + + if (mDisplayIdToUseWhenFolded == null || mDisplayIdToUseWhenUnfolded == null + || mLogicalDisplays.size() < 2) { + // Do nothing if this behavior is disabled or there are less than two displays. + return; + } + + final DisplayDevice deviceFolded = + mDisplayDeviceRepo.getByIdLocked(mDisplayIdToUseWhenFolded); + final DisplayDevice deviceUnfolded = + mDisplayDeviceRepo.getByIdLocked(mDisplayIdToUseWhenUnfolded); + if (deviceFolded == null || deviceUnfolded == null) { + // If the expected devices for folding functionality are not present, return early. + return; + } + + // Find the associated LogicalDisplays for the configured "folding" DeviceDisplays. + final LogicalDisplay displayFolded = getLocked(deviceFolded); + final LogicalDisplay displayUnfolded = getLocked(deviceUnfolded); + if (displayFolded == null || displayFolded == null) { + // If the expected displays are not present, return early. + return; + } + + // Find out which display is currently default and which is disabled. + final LogicalDisplay defaultDisplay = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); + final LogicalDisplay disabledDisplay; + if (defaultDisplay == displayFolded) { + disabledDisplay = displayUnfolded; + } else if (defaultDisplay == displayUnfolded) { + disabledDisplay = displayFolded; + } else { + // If neither folded or unfolded displays are currently set to the default display, we + // are in an unknown state and it's best to log the error and bail. + Slog.e(TAG, "Unexpected: when attempting to swap displays, neither of the two" + + " configured displays were set up as the default display. Default: " + + defaultDisplay.getDisplayInfoLocked() + ", ConfiguredDisplays: [ folded=" + + displayFolded.getDisplayInfoLocked() + ", unfolded=" + + displayUnfolded.getDisplayInfoLocked() + " ]"); + return; + } + + if (isFolded == (defaultDisplay == displayFolded)) { + // Nothing to do, already in the right state. + return; + } + + // Everything was checked and we need to swap, lets swap. + displayFolded.swapDisplaysLocked(displayUnfolded); + + // We ensure that the non-default Display is always forced to be off. This was likely + // already done in a previous iteration, but we do it with each swap in case something in + // the underlying LogicalDisplays changed: like LogicalDisplay recreation, for example. + defaultDisplay.setEnabled(true); + disabledDisplay.setEnabled(false); + + // Update the world + updateLogicalDisplaysLocked(); + + if (DEBUG) { + Slog.d(TAG, "Folded displays: isFolded: " + isFolded + ", defaultDisplay? " + + defaultDisplay.getDisplayInfoLocked()); + } + } + public void dumpLocked(PrintWriter pw) { pw.println("LogicalDisplayMapper:"); - pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); - pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + ipw.increaseIndent(); + + ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); + ipw.println("mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); final int logicalDisplayCount = mLogicalDisplays.size(); - pw.println(); - pw.println(" Logical Displays: size=" + logicalDisplayCount); + ipw.println(); + ipw.println("Logical Displays: size=" + logicalDisplayCount); - IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - ipw.increaseIndent(); for (int i = 0; i < logicalDisplayCount; i++) { int displayId = mLogicalDisplays.keyAt(i); LogicalDisplay display = mLogicalDisplays.valueAt(i); - pw.println(" Display " + displayId + ":"); + ipw.println("Display " + displayId + ":"); + ipw.increaseIndent(); display.dumpLocked(ipw); + ipw.decreaseIndent(); + ipw.println(); + } + } + + void setFoldOverrideLocked(Boolean isFolded) { + if (!Objects.equals(isFolded, mIsFoldedOverride)) { + mIsFoldedOverride = isFolded; + setDeviceFoldedLocked(mIsFolded); } } @@ -211,8 +318,11 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mListener.onLogicalDisplayEventLocked(display, LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED); } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { - mListener.onLogicalDisplayEventLocked(display, - LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED); + final String oldUniqueId = mTempDisplayInfo.uniqueId; + final String newUniqueId = display.getDisplayInfoLocked().uniqueId; + final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId) + ? LOGICAL_DISPLAY_EVENT_CHANGED : LOGICAL_DISPLAY_EVENT_SWAPPED; + mListener.onLogicalDisplayEventLocked(display, eventMsg); } else { // While applications shouldn't know nor care about the non-overridden info, we // still need to let WindowManager know so it can update its own internal state for @@ -236,6 +346,21 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return displayId; } + private void loadFoldedDisplayConfig(Context context) { + final String[] displayIds = context.getResources().getStringArray( + com.android.internal.R.array.config_internalFoldedPhysicalDisplayIds); + + if (displayIds.length != 2 || TextUtils.isEmpty(displayIds[0]) + || TextUtils.isEmpty(displayIds[1])) { + Slog.w(TAG, "Folded display configuration invalid: [" + Arrays.toString(displayIds) + + "]"); + return; + } + + mDisplayIdToUseWhenFolded = displayIds[0]; + mDisplayIdToUseWhenUnfolded = displayIds[1]; + } + public interface Listener { void onLogicalDisplayEventLocked(LogicalDisplay display, int event); void onTraversalRequested(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 03bf74f40205..4d6b760fc56f 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6652,7 +6652,7 @@ public class NotificationManagerService extends SystemService { // Log event to statsd mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position, - buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey())); + buzzBeepBlinkLoggingCode, getGroupInstanceId(r.getSbn().getGroupKey())); } finally { int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index 0db3d78fed5b..0ca6e5923f1b 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -80,6 +80,8 @@ class DisplayFoldController { } void setDeviceFolded(boolean folded) { + mDisplayManagerInternal.setDeviceFolded(folded); + if (mFolded != null && mFolded == folded) { return; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 0313aaeef0d6..b74de1347224 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -117,6 +117,7 @@ import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerInternal; import android.hardware.hdmi.HdmiAudioSystemClient; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; @@ -366,6 +367,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { StatusBarManagerInternal mStatusBarManagerInternal; AudioManagerInternal mAudioManagerInternal; DisplayManager mDisplayManager; + DisplayManagerInternal mDisplayManagerInternal; boolean mPreloadedRecentApps; final Object mServiceAquireLock = new Object(); Vibrator mVibrator; // Vibrator for giving feedback of orientation changes @@ -469,6 +471,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidKeyboardAccessibility; int mLidNavigationAccessibility; private boolean mLidControlsDisplayFold; + private boolean mShouldSwapDisplaysOnLidSwitch; int mShortPressOnPowerBehavior; int mLongPressOnPowerBehavior; int mVeryLongPressOnPowerBehavior; @@ -1752,6 +1755,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mPackageManager = mContext.getPackageManager(); mHasFeatureWatch = mPackageManager.hasSystemFeature(FEATURE_WATCH); mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK); @@ -1845,6 +1849,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_lidNavigationAccessibility); mLidControlsDisplayFold = mContext.getResources().getBoolean( com.android.internal.R.bool.config_lidControlsDisplayFold); + mShouldSwapDisplaysOnLidSwitch = mContext.getResources().getStringArray( + com.android.internal.R.array.config_internalFoldedPhysicalDisplayIds).length == 2; mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromKey); @@ -5035,6 +5041,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { final int lidState = mDefaultDisplayPolicy.getLidState(); if (mLidControlsDisplayFold && mDisplayFoldController != null) { mDisplayFoldController.requestDeviceFolded(lidState == LID_CLOSED); + } else if (mShouldSwapDisplaysOnLidSwitch) { + mDisplayManagerInternal.setDeviceFolded(lidState == LID_CLOSED); } else if (lidState == LID_CLOSED) { int lidBehavior = getLidBehavior(); switch (lidBehavior) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 6ee583164284..1100496dffbe 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -1883,7 +1883,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testGroupInstanceIds() throws Exception { final NotificationRecord group1 = generateNotificationRecord( mTestNotificationChannel, 1, "group1", true); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testGroupInstanceIds", group1.getSbn().getId(), group1.getSbn().getNotification(), group1.getSbn().getUserId()); waitForIdle(); @@ -1891,7 +1891,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // same group, child, should be returned final NotificationRecord group1Child = generateNotificationRecord( mTestNotificationChannel, 2, "group1", false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testGroupInstanceIds", group1Child.getSbn().getId(), group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); waitForIdle(); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 8ad6c46b913d..b29fae30565e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -147,8 +147,7 @@ class SeamlessAppRotationTest( navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible(bugId = 140855415) noUncoveredRegions(configuration.startRotation, - configuration.endRotation, allStates = false - /*, bugId = 147659548*/) + configuration.endRotation, allStates = false, bugId = 147659548) navBarLayerRotatesAndScales(configuration.startRotation, configuration.endRotation) statusBarLayerRotatesScales(configuration.startRotation, @@ -161,7 +160,7 @@ class SeamlessAppRotationTest( val endingBounds = WindowUtils .getDisplayBounds(configuration.endRotation) - all("appLayerRotates"/*, bugId = 147659548*/) { + all("appLayerRotates", bugId = 147659548) { if (startingBounds == endingBounds) { this.hasVisibleRegion( configuration.intentPackageName, startingBounds) diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 753dbf80b449..32bfa7059b0b 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -159,7 +159,6 @@ public class DnsManagerTest { // Send a validation event that is tracked on the alternate netId mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp); @@ -196,7 +195,6 @@ public class DnsManagerTest { })); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); @@ -232,7 +230,6 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("3.3.3.3")); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, @@ -246,7 +243,6 @@ public class DnsManagerTest { mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED, @@ -295,7 +291,6 @@ public class DnsManagerTest { mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, @@ -341,7 +336,6 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("4.4.4.4")); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor = |