diff options
6 files changed, 153 insertions, 43 deletions
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index f3841d5..305fd5c 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -285,6 +285,16 @@ public final class DisplayInfo implements Parcelable { getMetricsWithSize(outMetrics, cih, logicalWidth, logicalHeight); } + public int getNaturalWidth() { + return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? + logicalWidth : logicalHeight; + } + + public int getNaturalHeight() { + return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? + logicalHeight : logicalWidth; + } + private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih, int width, int height) { outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi; diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index e58a0a5..e09970e 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -41,6 +41,7 @@ import android.view.DisplayInfo; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; /** * Manages attached displays. @@ -152,6 +153,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub { new SparseArray<LogicalDisplay>(); private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; + // List of all display transaction listeners. + private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners = + new CopyOnWriteArrayList<DisplayTransactionListener>(); + // Set to true if all displays have been blanked by the power manager. private int mAllDisplayBlankStateFromPowerManager; @@ -261,6 +266,36 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } /** + * Registers a display transaction listener to provide the client a chance to + * update its surfaces within the same transaction as any display layout updates. + * + * @param listener The listener to register. + */ + public void registerDisplayTransactionListener(DisplayTransactionListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + // List is self-synchronized copy-on-write. + mDisplayTransactionListeners.add(listener); + } + + /** + * Unregisters a display transaction listener to provide the client a chance to + * update its surfaces within the same transaction as any display layout updates. + * + * @param listener The listener to unregister. + */ + public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + // List is self-synchronized copy-on-write. + mDisplayTransactionListeners.remove(listener); + } + + /** * Overrides the display information of a particular logical display. * This is used by the window manager to control the size and characteristics * of the default display. It is expected to apply the requested change @@ -298,6 +333,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub { performTraversalInTransactionLocked(); } + + // List is self-synchronized copy-on-write. + for (DisplayTransactionListener listener : mDisplayTransactionListeners) { + listener.onDisplayTransaction(); + } } /** diff --git a/services/java/com/android/server/display/DisplayTransactionListener.java b/services/java/com/android/server/display/DisplayTransactionListener.java new file mode 100644 index 0000000..34eb8f9 --- /dev/null +++ b/services/java/com/android/server/display/DisplayTransactionListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +/** + * Called within a Surface transaction whenever the size or orientation of a + * display may have changed. Provides an opportunity for the client to + * update the position of its surfaces as part of the same transaction. + */ +public interface DisplayTransactionListener { + void onDisplayTransaction(); +} diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index 317fec0..724e126 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -19,6 +19,7 @@ package com.android.server.power; import com.android.server.LightsService; import com.android.server.TwilightService; import com.android.server.TwilightService.TwilightState; +import com.android.server.display.DisplayManagerService; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -29,7 +30,6 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.SystemSensorManager; -import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -40,7 +40,6 @@ import android.util.FloatMath; import android.util.Slog; import android.util.Spline; import android.util.TimeUtils; -import android.view.Display; import java.io.PrintWriter; @@ -183,7 +182,7 @@ final class DisplayPowerController { private final TwilightService mTwilight; // The display manager. - private final DisplayManager mDisplayManager; + private final DisplayManagerService mDisplayManager; // The sensor manager. private final SensorManager mSensorManager; @@ -346,6 +345,7 @@ final class DisplayPowerController { */ public DisplayPowerController(Looper looper, Context context, Notifier notifier, LightsService lights, TwilightService twilight, + DisplayManagerService displayManager, DisplayBlanker displayBlanker, Callbacks callbacks, Handler callbackHandler) { mHandler = new DisplayControllerHandler(looper); @@ -357,7 +357,7 @@ final class DisplayPowerController { mLights = lights; mTwilight = twilight; mSensorManager = new SystemSensorManager(mHandler.getLooper()); - mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); + mDisplayManager = displayManager; final Resources resources = context.getResources(); @@ -518,9 +518,8 @@ final class DisplayPowerController { } private void initialize() { - Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); mPowerState = new DisplayPowerState( - new ElectronBeam(display), mDisplayBlanker, + new ElectronBeam(mDisplayManager), mDisplayBlanker, mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT)); mElectronBeamOnAnimator = ObjectAnimator.ofFloat( diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java index 9a53648..8e19e11 100644 --- a/services/java/com/android/server/power/ElectronBeam.java +++ b/services/java/com/android/server/power/ElectronBeam.java @@ -16,6 +16,9 @@ package com.android.server.power; +import com.android.server.display.DisplayManagerService; +import com.android.server.display.DisplayTransactionListener; + import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.opengl.EGL14; @@ -72,14 +75,13 @@ final class ElectronBeam { private boolean mPrepared; private int mMode; - private final Display mDisplay; - private final DisplayInfo mDisplayInfo = new DisplayInfo(); + private final DisplayManagerService mDisplayManager; private int mDisplayLayerStack; // layer stack associated with primary display - private int mDisplayRotation; private int mDisplayWidth; // real width, not rotated private int mDisplayHeight; // real height, not rotated private SurfaceSession mSurfaceSession; private Surface mSurface; + private NaturalSurfaceLayout mSurfaceLayout; private EGLDisplay mEglDisplay; private EGLConfig mEglConfig; private EGLContext mEglContext; @@ -111,8 +113,8 @@ final class ElectronBeam { */ public static final int MODE_FADE = 2; - public ElectronBeam(Display display) { - mDisplay = display; + public ElectronBeam(DisplayManagerService displayManager) { + mDisplayManager = displayManager; } /** @@ -129,18 +131,12 @@ final class ElectronBeam { mMode = mode; - // Get the display size and adjust it for rotation. - mDisplay.getDisplayInfo(mDisplayInfo); - mDisplayLayerStack = mDisplay.getLayerStack(); - mDisplayRotation = mDisplayInfo.rotation; - if (mDisplayRotation == Surface.ROTATION_90 - || mDisplayRotation == Surface.ROTATION_270) { - mDisplayWidth = mDisplayInfo.logicalHeight; - mDisplayHeight = mDisplayInfo.logicalWidth; - } else { - mDisplayWidth = mDisplayInfo.logicalWidth; - mDisplayHeight = mDisplayInfo.logicalHeight; - } + // Get the display size and layer stack. + // This is not expected to change while the electron beam surface is showing. + DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); + mDisplayLayerStack = displayInfo.layerStack; + mDisplayWidth = displayInfo.getNaturalWidth(); + mDisplayHeight = displayInfo.getNaturalHeight(); // Prepare the surface for drawing. if (!tryPrepare()) { @@ -551,24 +547,8 @@ final class ElectronBeam { mSurface.setLayerStack(mDisplayLayerStack); mSurface.setSize(mDisplayWidth, mDisplayHeight); - switch (mDisplayRotation) { - case Surface.ROTATION_0: - mSurface.setPosition(0, 0); - mSurface.setMatrix(1, 0, 0, 1); - break; - case Surface.ROTATION_90: - mSurface.setPosition(0, mDisplayWidth); - mSurface.setMatrix(0, -1, 1, 0); - break; - case Surface.ROTATION_180: - mSurface.setPosition(mDisplayWidth, mDisplayHeight); - mSurface.setMatrix(-1, 0, 0, -1); - break; - case Surface.ROTATION_270: - mSurface.setPosition(mDisplayHeight, 0); - mSurface.setMatrix(0, 1, -1, 0); - break; - } + mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurface); + mSurfaceLayout.onDisplayTransaction(); } finally { Surface.closeTransaction(); } @@ -601,6 +581,8 @@ final class ElectronBeam { private void destroySurface() { if (mSurface != null) { + mSurfaceLayout.dispose(); + mSurfaceLayout = null; Surface.openTransaction(); try { mSurface.destroy(); @@ -711,10 +693,63 @@ final class ElectronBeam { pw.println(" mPrepared=" + mPrepared); pw.println(" mMode=" + mMode); pw.println(" mDisplayLayerStack=" + mDisplayLayerStack); - pw.println(" mDisplayRotation=" + mDisplayRotation); pw.println(" mDisplayWidth=" + mDisplayWidth); pw.println(" mDisplayHeight=" + mDisplayHeight); pw.println(" mSurfaceVisible=" + mSurfaceVisible); pw.println(" mSurfaceAlpha=" + mSurfaceAlpha); } + + /** + * Keeps a surface aligned with the natural orientation of the device. + * Updates the position and transformation of the matrix whenever the display + * is rotated. This is a little tricky because the display transaction + * callback can be invoked on any thread, not necessarily the thread that + * owns the electron beam. + */ + private static final class NaturalSurfaceLayout implements DisplayTransactionListener { + private final DisplayManagerService mDisplayManager; + private Surface mSurface; + + public NaturalSurfaceLayout(DisplayManagerService displayManager, Surface surface) { + mDisplayManager = displayManager; + mSurface = surface; + mDisplayManager.registerDisplayTransactionListener(this); + } + + public void dispose() { + synchronized (this) { + mSurface = null; + } + mDisplayManager.unregisterDisplayTransactionListener(this); + } + + @Override + public void onDisplayTransaction() { + synchronized (this) { + if (mSurface == null) { + return; + } + + DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); + switch (displayInfo.rotation) { + case Surface.ROTATION_0: + mSurface.setPosition(0, 0); + mSurface.setMatrix(1, 0, 0, 1); + break; + case Surface.ROTATION_90: + mSurface.setPosition(0, displayInfo.logicalHeight); + mSurface.setMatrix(0, -1, 1, 0); + break; + case Surface.ROTATION_180: + mSurface.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight); + mSurface.setMatrix(-1, 0, 0, -1); + break; + case Surface.ROTATION_270: + mSurface.setPosition(displayInfo.logicalWidth, 0); + mSurface.setMatrix(0, 1, -1, 0); + break; + } + } + } + } } diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index 2690442..7f83c17 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -432,7 +432,7 @@ public final class PowerManagerService extends IPowerManager.Stub // The display power controller runs on the power manager service's // own handler thread. mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(), - mContext, mNotifier, mLightsService, twilight, + mContext, mNotifier, mLightsService, twilight, mDisplayManagerService, mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler); mSettingsObserver = new SettingsObserver(mHandler); |