From c979b749192a609d630173f944053e805ae58c11 Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Fri, 6 Jan 2023 16:41:46 +0800 Subject: [PATCH] RESTRICT AUTOMERGE Center align the lock screen wallpaper On smaller display of a multi display device the lock screen wallpaper should be showing the center area of the wallpaper. Check the display id to find out which display the lock screen wallpaper is on, the check needs to happened when we are adjusting the bounds to get the new display id. Bug: 263932616 Test: set the lock screen wallpaper and observe the result Change-Id: I32b93084a9e716a06e032f83a8cf625c25d3e5e5 --- .../statusbar/NotificationMediaManager.java | 67 ++++++++++++++++++- .../CentralSurfacesDependenciesModule.java | 7 +- .../statusbar/phone/CentralSurfacesImpl.java | 1 + .../statusbar/phone/LockscreenWallpaper.java | 36 ++++++++-- .../phone/LockscreenWallpaperTest.kt | 48 +++++++++++++ 5 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index ced725e0b1d60..89e48831a96b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -26,10 +26,12 @@ import android.annotation.Nullable; import android.app.Notification; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.hardware.display.DisplayManager; import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaSession; @@ -40,6 +42,7 @@ import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.Log; +import android.view.Display; import android.view.View; import android.widget.ImageView; @@ -72,11 +75,15 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import dagger.Lazy; @@ -134,6 +141,14 @@ public class NotificationMediaManager implements Dumpable { private BackDropView mBackdrop; private ImageView mBackdropFront; private ImageView mBackdropBack; + private final Point mTmpDisplaySize = new Point(); + + private final DisplayManager mDisplayManager; + @Nullable + private List mSmallerInternalDisplayUids; + private Display mCurrentDisplay; + + private LockscreenWallpaper.WallpaperDrawable mWallapperDrawable; private final MediaController.Callback mMediaListener = new MediaController.Callback() { @Override @@ -179,7 +194,8 @@ public class NotificationMediaManager implements Dumpable { StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor, KeyguardStateController keyguardStateController, - DumpManager dumpManager) { + DumpManager dumpManager, + DisplayManager displayManager) { mContext = context; mMediaArtworkProcessor = mediaArtworkProcessor; mKeyguardBypassController = keyguardBypassController; @@ -195,6 +211,7 @@ public class NotificationMediaManager implements Dumpable { mStatusBarStateController = statusBarStateController; mColorExtractor = colorExtractor; mKeyguardStateController = keyguardStateController; + mDisplayManager = displayManager; setupNotifPipeline(); @@ -470,6 +487,48 @@ public class NotificationMediaManager implements Dumpable { mMediaController = null; } + /** + * Notify lockscreen wallpaper drawable the current internal display. + */ + public void onDisplayUpdated(Display display) { + Trace.beginSection("NotificationMediaManager#onDisplayUpdated"); + mCurrentDisplay = display; + if (mWallapperDrawable != null) { + mWallapperDrawable.onDisplayUpdated(isOnSmallerInternalDisplays()); + } + Trace.endSection(); + } + + private boolean isOnSmallerInternalDisplays() { + if (mSmallerInternalDisplayUids == null) { + mSmallerInternalDisplayUids = findSmallerInternalDisplayUids(); + } + return mSmallerInternalDisplayUids.contains(mCurrentDisplay.getUniqueId()); + } + + private List findSmallerInternalDisplayUids() { + if (mSmallerInternalDisplayUids != null) { + return mSmallerInternalDisplayUids; + } + List internalDisplays = Arrays.stream(mDisplayManager.getDisplays( + DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .filter(display -> display.getType() == Display.TYPE_INTERNAL) + .collect(Collectors.toList()); + if (internalDisplays.isEmpty()) { + return List.of(); + } + Display largestDisplay = internalDisplays.stream() + .max(Comparator.comparingInt(this::getRealDisplayArea)) + .orElse(internalDisplays.get(0)); + internalDisplays.remove(largestDisplay); + return internalDisplays.stream().map(Display::getUniqueId).collect(Collectors.toList()); + } + + private int getRealDisplayArea(Display display) { + display.getRealSize(mTmpDisplaySize); + return mTmpDisplaySize.x * mTmpDisplaySize.y; + } + /** * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. */ @@ -542,7 +601,7 @@ public class NotificationMediaManager implements Dumpable { mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null; if (lockWallpaper != null) { artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( - mBackdropBack.getResources(), lockWallpaper); + mBackdropBack.getResources(), lockWallpaper, isOnSmallerInternalDisplays()); // We're in the SHADE mode on the SIM screen - yet we still need to show // the lockscreen wallpaper in that mode. allowWhenShade = mStatusBarStateController.getState() == KEYGUARD; @@ -602,6 +661,10 @@ public class NotificationMediaManager implements Dumpable { mBackdropBack.setBackgroundColor(0xFFFFFFFF); mBackdropBack.setImageDrawable(new ColorDrawable(c)); } else { + if (artworkDrawable instanceof LockscreenWallpaper.WallpaperDrawable) { + mWallapperDrawable = + (LockscreenWallpaper.WallpaperDrawable) artworkDrawable; + } mBackdropBack.setImageDrawable(artworkDrawable); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index d7568a9bd89c7..4afa21e83f089 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.dagger; import android.app.IActivityManager; import android.content.Context; +import android.hardware.display.DisplayManager; import android.os.RemoteException; import android.service.dreams.IDreamManager; import android.util.Log; @@ -139,7 +140,8 @@ public interface CentralSurfacesDependenciesModule { StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor, KeyguardStateController keyguardStateController, - DumpManager dumpManager) { + DumpManager dumpManager, + DisplayManager displayManager) { return new NotificationMediaManager( context, centralSurfacesOptionalLazy, @@ -154,7 +156,8 @@ public interface CentralSurfacesDependenciesModule { statusBarStateController, colorExtractor, keyguardStateController, - dumpManager); + dumpManager, + displayManager); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 56e2dc4602346..de129a3a2eb40 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2311,6 +2311,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { void updateDisplaySize() { mDisplay.getMetrics(mDisplayMetrics); mDisplay.getSize(mCurrentDisplaySize); + mMediaManager.onDisplayUpdated(mDisplay); if (DEBUG_GESTURES) { mGestureRec.tag("display", String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 1d7dfe1998714..b3b66a7635d90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -259,19 +259,25 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen /** * Drawable that aligns left horizontally and center vertically (like ImageWallpaper). + * + *

Aligns to the center when showing on the smaller internal display of a multi display + * device. */ public static class WallpaperDrawable extends DrawableWrapper { private final ConstantState mState; private final Rect mTmpRect = new Rect(); + private boolean mIsOnSmallerInternalDisplays; - public WallpaperDrawable(Resources r, Bitmap b) { - this(r, new ConstantState(b)); + public WallpaperDrawable(Resources r, Bitmap b, boolean isOnSmallerInternalDisplays) { + this(r, new ConstantState(b), isOnSmallerInternalDisplays); } - private WallpaperDrawable(Resources r, ConstantState state) { + private WallpaperDrawable(Resources r, ConstantState state, + boolean isOnSmallerInternalDisplays) { super(new BitmapDrawable(r, state.mBackground)); mState = state; + mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays; } @Override @@ -310,10 +316,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen } dy = (vheight - dheight * scale) * 0.5f; + int offsetX = 0; + // Offset to show the center area of the wallpaper on a smaller display for multi + // display device + if (mIsOnSmallerInternalDisplays) { + offsetX = bounds.centerX() - (Math.round(dwidth * scale) / 2); + } + mTmpRect.set( - bounds.left, + bounds.left + offsetX, bounds.top + Math.round(dy), - bounds.left + Math.round(dwidth * scale), + bounds.left + Math.round(dwidth * scale) + offsetX, bounds.top + Math.round(dheight * scale + dy)); super.onBoundsChange(mTmpRect); @@ -324,6 +337,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen return mState; } + /** + * Update bounds when the hosting display or the display size has changed. + * + * @param isOnSmallerInternalDisplays tru if the drawable is on one of the internal displays + * with the smaller area. + */ + public void onDisplayUpdated(boolean isOnSmallerInternalDisplays) { + mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays; + onBoundsChange(getBounds()); + } + static class ConstantState extends Drawable.ConstantState { private final Bitmap mBackground; @@ -339,7 +363,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen @Override public Drawable newDrawable(@Nullable Resources res) { - return new WallpaperDrawable(res, this); + return new WallpaperDrawable(res, this, /* isOnSmallerInternalDisplays= */ false); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt new file mode 100644 index 0000000000000..fece5bad970ac --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.systemui.statusbar.phone + +import android.graphics.Bitmap +import android.graphics.Rect +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class LockscreenWallpaperTest : SysuiTestCase() { + + @Test + fun testLockscreenWallpaper_onSmallerInternalDisplay_centerAlignsDrawable() { + val displaySize = Rect(0, 0, 1080, 2092) + val wallpaperDrawable = + LockscreenWallpaper.WallpaperDrawable( + context.resources, + Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888), + /* isOnSmallerInternalDisplays= */ false + ) + .apply { bounds = displaySize } + + wallpaperDrawable.onDisplayUpdated(true) + + assertThat(wallpaperDrawable.drawable.bounds.centerX()) + .isEqualTo(wallpaperDrawable.bounds.centerX()) + } +}