diff --git a/demos/main/src/main/java/androidx/media3/demo/main/DownloadTracker.java b/demos/main/src/main/java/androidx/media3/demo/main/DownloadTracker.java index 07d1b8deca..8a530f87fb 100644 --- a/demos/main/src/main/java/androidx/media3/demo/main/DownloadTracker.java +++ b/demos/main/src/main/java/androidx/media3/demo/main/DownloadTracker.java @@ -199,6 +199,8 @@ public class DownloadTracker { return; } + // The content is DRM protected. We need to acquire an offline license. + // TODO(internal b/163107948): Support cases where DrmInitData are not in the manifest. if (!hasNonNullWidevineSchemaData(format.drmInitData)) { Toast.makeText(context, R.string.download_start_error_offline_license, Toast.LENGTH_LONG) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java index 6f24da13c2..d8d604c77d 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java @@ -180,7 +180,7 @@ public final class GlUtil { return false; } - return Api17.isExtensionSupported(EXTENSION_PROTECTED_CONTENT); + return isExtensionSupported(EXTENSION_PROTECTED_CONTENT); } /** @@ -191,7 +191,7 @@ public final class GlUtil { * EGLContext)}. */ public static boolean isSurfacelessContextExtensionSupported() { - return Api17.isExtensionSupported(EXTENSION_SURFACELESS_CONTEXT); + return isExtensionSupported(EXTENSION_SURFACELESS_CONTEXT); } /** @@ -202,7 +202,7 @@ public final class GlUtil { */ public static boolean isYuvTargetExtensionSupported() { @Nullable String glExtensions; - if (Util.areEqual(Api17.getCurrentContext(), EGL14.EGL_NO_CONTEXT)) { + if (Util.areEqual(EGL14.eglGetCurrentContext(), EGL14.EGL_NO_CONTEXT)) { // Create a placeholder context and make it current to allow calling GLES20.glGetString(). try { EGLDisplay eglDisplay = getDefaultEglDisplay(); @@ -222,12 +222,23 @@ public final class GlUtil { /** Returns whether {@link #EXTENSION_COLORSPACE_BT2020_PQ} is supported. */ public static boolean isBt2020PqExtensionSupported() { - return Api17.isExtensionSupported(EXTENSION_COLORSPACE_BT2020_PQ); + return isExtensionSupported(EXTENSION_COLORSPACE_BT2020_PQ); } /** Returns an initialized default {@link EGLDisplay}. */ public static EGLDisplay getDefaultEglDisplay() throws GlException { - return Api17.getDefaultEglDisplay(); + EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + checkGlException(!eglDisplay.equals(EGL14.EGL_NO_DISPLAY), "No EGL display."); + checkGlException( + EGL14.eglInitialize( + eglDisplay, + /* unusedMajor */ new int[1], + /* majorOffset= */ 0, + /* unusedMinor */ new int[1], + /* minorOffset= */ 0), + "Error in eglInitialize."); + checkGlError(); + return eglDisplay; } /** @@ -263,7 +274,23 @@ public final class GlUtil { Arrays.equals(configAttributes, EGL_CONFIG_ATTRIBUTES_RGBA_8888) || Arrays.equals(configAttributes, EGL_CONFIG_ATTRIBUTES_RGBA_1010102)); checkArgument(openGlVersion == 2 || openGlVersion == 3); - return Api17.createEglContext(sharedContext, eglDisplay, openGlVersion, configAttributes); + int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, openGlVersion, EGL14.EGL_NONE}; + EGLContext eglContext = + EGL14.eglCreateContext( + eglDisplay, + getEglConfig(eglDisplay, configAttributes), + sharedContext, + contextAttributes, + /* offset= */ 0); + if (eglContext == null) { + EGL14.eglTerminate(eglDisplay); + throw new GlException( + "eglCreateContext() failed to create a valid context. The device may not support EGL" + + " version " + + openGlVersion); + } + checkGlError(); + return eglContext; } /** @@ -308,7 +335,15 @@ public final class GlUtil { } else { throw new IllegalArgumentException("Unsupported color transfer: " + colorTransfer); } - return Api17.createEglSurface(eglDisplay, surface, configAttributes, windowAttributes); + EGLSurface eglSurface = + EGL14.eglCreateWindowSurface( + eglDisplay, + getEglConfig(eglDisplay, configAttributes), + surface, + windowAttributes, + /* offset= */ 0); + checkEglException("Error creating a new EGL surface"); + return eglSurface; } /** @@ -328,7 +363,14 @@ public final class GlUtil { EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE }; - return Api17.createEglPbufferSurface(eglDisplay, configAttributes, pbufferAttributes); + EGLSurface eglSurface = + EGL14.eglCreatePbufferSurface( + eglDisplay, + getEglConfig(eglDisplay, configAttributes), + pbufferAttributes, + /* offset= */ 0); + checkEglException("Error creating a new EGL Pbuffer surface"); + return eglSurface; } /** @@ -363,8 +405,15 @@ public final class GlUtil { * is focused}. */ public static long getContextMajorVersion() throws GlException { - return Api17.getContextMajorVersion(); - } + int[] currentEglContextVersion = new int[1]; + EGL14.eglQueryContext( + EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY), + EGL14.eglGetCurrentContext(), + EGL_CONTEXT_CLIENT_VERSION, + currentEglContextVersion, + /* offset= */ 0); + checkGlError(); + return currentEglContextVersion[0]; } /** * Returns a newly created sync object and inserts it into the GL command stream. @@ -374,8 +423,19 @@ public final class GlUtil { * less than 3.0. */ public static long createGlSyncFence() throws GlException { - // If the context is an OpenGL 3.0 context, we must be running API 18 or later. - return Api17.getContextMajorVersion() >= 3 ? Api18.createSyncFence() : 0; + if (getContextMajorVersion() >= 3) { + long syncObject = GLES30.glFenceSync(GLES30.GL_SYNC_GPU_COMMANDS_COMPLETE, /* flags= */ 0); + checkGlError(); + // Due to specifics of OpenGL, it might happen that the fence creation command is not yet + // sent into the GPU command queue, which can cause other threads to wait infinitely if + // the glSyncWait/glClientSyncWait command went into the GPU earlier. Hence, we have to + // call glFlush to ensure that glFenceSync is inside of the GPU command queue. + GLES20.glFlush(); + checkGlError(); + return syncObject; + } else { + return 0; + } } /** @@ -384,17 +444,12 @@ public final class GlUtil { *
The {@code syncObject} must not be used after deletion. */ public static void deleteSyncObject(long syncObject) throws GlException { - Api18.deleteSyncObject(syncObject); - } + deleteSyncObjectQuietly(syncObject); + checkGlError(); } /** Releases the GL sync object if set, suppressing any error. */ public static void deleteSyncObjectQuietly(long syncObject) { - try { - // glDeleteSync ignores a 0-valued sync object. - Api18.deleteSyncObject(syncObject); - } catch (GlException unused) { - // Suppress exceptions. - } + GLES30.glDeleteSync(syncObject); } /** @@ -407,14 +462,14 @@ public final class GlUtil { // Fallback to using glFinish for synchronization when fence creation failed. GLES20.glFinish(); } else { - // If the sync object is set, we must be running API 18 or later. - Api18.waitSync(syncObject); + GLES30.glWaitSync(syncObject, /* flags= */ 0, GLES30.GL_TIMEOUT_IGNORED); + checkGlError(); } } /** Gets the current {@link EGLContext context}. */ public static EGLContext getCurrentContext() { - return Api17.getCurrentContext(); + return EGL14.eglGetCurrentContext(); } /** @@ -491,7 +546,7 @@ public final class GlUtil { public static void focusEglSurface( EGLDisplay eglDisplay, EGLContext eglContext, EGLSurface eglSurface, int width, int height) throws GlException { - Api17.focusRenderTarget( + focusRenderTarget( eglDisplay, eglContext, eglSurface, /* framebuffer= */ 0, width, height); } @@ -507,7 +562,7 @@ public final class GlUtil { int width, int height) throws GlException { - Api17.focusRenderTarget(eglDisplay, eglContext, eglSurface, framebuffer, width, height); + focusRenderTarget(eglDisplay, eglContext, eglSurface, framebuffer, width, height); } /** @@ -702,7 +757,20 @@ public final class GlUtil { */ public static void destroyEglContext( @Nullable EGLDisplay eglDisplay, @Nullable EGLContext eglContext) throws GlException { - Api17.destroyEglContext(eglDisplay, eglContext); + if (eglDisplay == null) { + return; + } + EGL14.eglMakeCurrent( + eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + checkEglException("Error releasing context"); + if (eglContext != null) { + EGL14.eglDestroyContext(eglDisplay, eglContext); + checkEglException("Error destroying context"); + } + EGL14.eglReleaseThread(); + checkEglException("Error releasing thread"); + EGL14.eglTerminate(eglDisplay); + checkEglException("Error terminating display"); } /** @@ -711,7 +779,15 @@ public final class GlUtil { */ public static void destroyEglSurface( @Nullable EGLDisplay eglDisplay, @Nullable EGLSurface eglSurface) throws GlException { - Api17.destroyEglSurface(eglDisplay, eglSurface); + if (eglDisplay == null || eglSurface == null) { + return; + } + if (EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW) == EGL_NO_SURFACE) { + return; + } + + EGL14.eglDestroySurface(eglDisplay, eglSurface); + checkEglException("Error destroying surface"); } /** Deletes a framebuffer, or silently ignores the method call if {@code fboId} is unused. */ @@ -737,201 +813,46 @@ public final class GlUtil { } } - private static final class Api17 { - private Api17() {} - - @DoNotInline - public static EGLDisplay getDefaultEglDisplay() throws GlException { - EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - checkGlException(!eglDisplay.equals(EGL14.EGL_NO_DISPLAY), "No EGL display."); - checkGlException( - EGL14.eglInitialize( - eglDisplay, - /* unusedMajor */ new int[1], - /* majorOffset= */ 0, - /* unusedMinor */ new int[1], - /* minorOffset= */ 0), - "Error in eglInitialize."); - checkGlError(); - return eglDisplay; - } - - @DoNotInline - public static EGLContext createEglContext( - EGLContext sharedContext, EGLDisplay eglDisplay, int version, int[] configAttributes) - throws GlException { - int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, version, EGL14.EGL_NONE}; - EGLContext eglContext = - EGL14.eglCreateContext( - eglDisplay, - getEglConfig(eglDisplay, configAttributes), - sharedContext, - contextAttributes, - /* offset= */ 0); - if (eglContext == null) { - EGL14.eglTerminate(eglDisplay); - throw new GlException( - "eglCreateContext() failed to create a valid context. The device may not support EGL" - + " version " - + version); - } - checkGlError(); - return eglContext; - } - - @DoNotInline - public static EGLContext getCurrentContext() { - return EGL14.eglGetCurrentContext(); - } - - @DoNotInline - private static EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] attributes) - throws GlException { - EGLConfig[] eglConfigs = new EGLConfig[1]; - if (!EGL14.eglChooseConfig( - eglDisplay, - attributes, - /* attrib_listOffset= */ 0, - eglConfigs, - /* configsOffset= */ 0, - /* config_size= */ 1, - /* unusedNumConfig */ new int[1], - /* num_configOffset= */ 0)) { - throw new GlException("eglChooseConfig failed."); - } - return eglConfigs[0]; - } - - @DoNotInline - public static boolean isExtensionSupported(String extensionName) { - EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - @Nullable String eglExtensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); - return eglExtensions != null && eglExtensions.contains(extensionName); - } - - @DoNotInline - public static int getContextMajorVersion() throws GlException { - int[] currentEglContextVersion = new int[1]; - EGL14.eglQueryContext( - EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY), - EGL14.eglGetCurrentContext(), - EGL_CONTEXT_CLIENT_VERSION, - currentEglContextVersion, - /* offset= */ 0); - checkGlError(); - return currentEglContextVersion[0]; - } - - @DoNotInline - public static EGLSurface createEglSurface( - EGLDisplay eglDisplay, Object surface, int[] configAttributes, int[] windowAttributes) - throws GlException { - EGLSurface eglSurface = - EGL14.eglCreateWindowSurface( - eglDisplay, - getEglConfig(eglDisplay, configAttributes), - surface, - windowAttributes, - /* offset= */ 0); - checkEglException("Error creating a new EGL surface"); - return eglSurface; - } - - @DoNotInline - public static EGLSurface createEglPbufferSurface( - EGLDisplay eglDisplay, int[] configAttributes, int[] pbufferAttributes) throws GlException { - EGLSurface eglSurface = - EGL14.eglCreatePbufferSurface( - eglDisplay, - getEglConfig(eglDisplay, configAttributes), - pbufferAttributes, - /* offset= */ 0); - checkEglException("Error creating a new EGL Pbuffer surface"); - return eglSurface; - } - - @DoNotInline - public static void focusRenderTarget( - EGLDisplay eglDisplay, - EGLContext eglContext, - EGLSurface eglSurface, - int framebuffer, - int width, - int height) - throws GlException { - EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); - checkEglException("Error making context current"); - focusFramebufferUsingCurrentContext(framebuffer, width, height); - } - - @DoNotInline - public static void destroyEglContext( - @Nullable EGLDisplay eglDisplay, @Nullable EGLContext eglContext) throws GlException { - if (eglDisplay == null) { - return; - } - EGL14.eglMakeCurrent( - eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); - checkEglException("Error releasing context"); - if (eglContext != null) { - EGL14.eglDestroyContext(eglDisplay, eglContext); - checkEglException("Error destroying context"); - } - EGL14.eglReleaseThread(); - checkEglException("Error releasing thread"); - EGL14.eglTerminate(eglDisplay); - checkEglException("Error terminating display"); - } - - @DoNotInline - public static void destroyEglSurface( - @Nullable EGLDisplay eglDisplay, @Nullable EGLSurface eglSurface) throws GlException { - if (eglDisplay == null || eglSurface == null) { - return; - } - if (EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW) == EGL_NO_SURFACE) { - return; - } - - EGL14.eglDestroySurface(eglDisplay, eglSurface); - checkEglException("Error destroying surface"); - } - - @DoNotInline - public static void checkEglException(String errorMessage) throws GlException { - int error = EGL14.eglGetError(); - if (error != EGL14.EGL_SUCCESS) { - throw new GlException(errorMessage + ", error code: 0x" + Integer.toHexString(error)); - } + private static EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] attributes) + throws GlException { + EGLConfig[] eglConfigs = new EGLConfig[1]; + if (!EGL14.eglChooseConfig( + eglDisplay, + attributes, + /* attrib_listOffset= */ 0, + eglConfigs, + /* configsOffset= */ 0, + /* config_size= */ 1, + /* unusedNumConfig */ new int[1], + /* num_configOffset= */ 0)) { + throw new GlException("eglChooseConfig failed."); } + return eglConfigs[0]; } - private static final class Api18 { - private Api18() {} + private static boolean isExtensionSupported(String extensionName) { + EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + @Nullable String eglExtensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); + return eglExtensions != null && eglExtensions.contains(extensionName); + } - @DoNotInline - public static long createSyncFence() throws GlException { - long syncObject = GLES30.glFenceSync(GLES30.GL_SYNC_GPU_COMMANDS_COMPLETE, /* flags= */ 0); - checkGlError(); - // Due to specifics of OpenGL, it might happen that the fence creation command is not yet - // sent into the GPU command queue, which can cause other threads to wait infinitely if - // the glSyncWait/glClientSyncWait command went into the GPU earlier. Hence, we have to - // call glFlush to ensure that glFenceSync is inside of the GPU command queue. - GLES20.glFlush(); - checkGlError(); - return syncObject; - } + private static void focusRenderTarget( + EGLDisplay eglDisplay, + EGLContext eglContext, + EGLSurface eglSurface, + int framebuffer, + int width, + int height) + throws GlException { + EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + checkEglException("Error making context current"); + focusFramebufferUsingCurrentContext(framebuffer, width, height); + } - @DoNotInline - public static void deleteSyncObject(long syncObject) throws GlException { - GLES30.glDeleteSync(syncObject); - checkGlError(); - } - - @DoNotInline - public static void waitSync(long syncObject) throws GlException { - GLES30.glWaitSync(syncObject, /* flags= */ 0, GLES30.GL_TIMEOUT_IGNORED); - checkGlError(); + private static void checkEglException(String errorMessage) throws GlException { + int error = EGL14.eglGetError(); + if (error != EGL14.EGL_SUCCESS) { + throw new GlException(errorMessage + ", error code: 0x" + Integer.toHexString(error)); } } } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java index 6483a62e06..95e67501da 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java @@ -803,7 +803,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer } else { MediaCodecInfo codecInfo = getCodecInfo(); if (codecInfo != null && shouldUsePlaceholderSurface(codecInfo)) { - placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure); + placeholderSurface = PlaceholderSurface.newInstance(context, codecInfo.secure); displaySurface = placeholderSurface; } } @@ -890,7 +890,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer throw new IllegalStateException(); } if (placeholderSurface == null) { - placeholderSurface = PlaceholderSurface.newInstanceV17(context, codecInfo.secure); + placeholderSurface = PlaceholderSurface.newInstance(context, codecInfo.secure); } displaySurface = placeholderSurface; } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/PlaceholderSurface.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/PlaceholderSurface.java index 5a3e263597..26e886342b 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/PlaceholderSurface.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/PlaceholderSurface.java @@ -64,6 +64,14 @@ public final class PlaceholderSurface extends Surface { return secureMode != SECURE_MODE_NONE; } + /** + * @deprecated Use {@link #newInstance(Context, boolean)} instead. + */ + @Deprecated + public static PlaceholderSurface newInstanceV17(Context context, boolean secure) { + return newInstance(context, secure); + } + /** * Returns a newly created placeholder surface. The surface must be released by calling {@link * #release} when it's no longer required. @@ -76,12 +84,14 @@ public final class PlaceholderSurface extends Surface { * @throws IllegalStateException If a secure surface is requested on a device for which {@link * #isSecureSupported(Context)} returns {@code false}. */ - public static PlaceholderSurface newInstanceV17(Context context, boolean secure) { + public static PlaceholderSurface newInstance(Context context, boolean secure) { Assertions.checkState(!secure || isSecureSupported(context)); PlaceholderSurfaceThread thread = new PlaceholderSurfaceThread(); return thread.init(secure ? secureMode : SECURE_MODE_NONE); } + + private PlaceholderSurface( PlaceholderSurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) { super(surfaceTexture); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameReleaseHelper.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameReleaseHelper.java index cf7df55bea..a8c90850f1 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameReleaseHelper.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameReleaseHelper.java @@ -161,7 +161,7 @@ public final class VideoFrameReleaseHelper { resetAdjustment(); if (displayHelper != null) { checkNotNull(vsyncSampler).addObserver(); - displayHelper.register(this::updateDefaultDisplayRefreshRateParams); + displayHelper.register(); } updateSurfacePlaybackFrameRate(/* forceUpdate= */ false); } @@ -418,16 +418,11 @@ public final class VideoFrameReleaseHelper { } @Nullable - private static DisplayHelper maybeBuildDisplayHelper(@Nullable Context context) { - @Nullable DisplayHelper displayHelper = null; - if (context != null) { - context = context.getApplicationContext(); - displayHelper = DisplayHelperV17.maybeBuildNewInstance(context); - if (displayHelper == null) { - displayHelper = DisplayHelperV16.maybeBuildNewInstance(context); - } - } - return displayHelper; + private DisplayHelper maybeBuildDisplayHelper(@Nullable Context context) { + if (context == null) { return null;} + DisplayManager displayManager = + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + return displayManager != null ? new DisplayHelper(displayManager) : null; } // Nested classes. @@ -448,91 +443,28 @@ public final class VideoFrameReleaseHelper { } } - /** Helper for listening to changes to the default display. */ - private interface DisplayHelper { - - /** Listener for changes to the default display. */ - interface Listener { - - /** - * Called when the default display changes. - * - * @param defaultDisplay The default display, or {@code null} if a corresponding {@link - * Display} object could not be obtained. - */ - void onDefaultDisplayChanged(@Nullable Display defaultDisplay); - } - - /** - * Enables the helper, invoking {@link Listener#onDefaultDisplayChanged(Display)} to pass the - * initial default display. - */ - void register(Listener listener); - - /** Disables the helper. */ - void unregister(); - } - - private static final class DisplayHelperV16 implements DisplayHelper { - - @Nullable - public static DisplayHelper maybeBuildNewInstance(Context context) { - WindowManager windowManager = - (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return windowManager != null ? new DisplayHelperV16(windowManager) : null; - } - - private final WindowManager windowManager; - - private DisplayHelperV16(WindowManager windowManager) { - this.windowManager = windowManager; - } - - @Override - public void register(Listener listener) { - listener.onDefaultDisplayChanged(windowManager.getDefaultDisplay()); - } - - @Override - public void unregister() { - // Do nothing. - } - } - - private static final class DisplayHelperV17 - implements DisplayHelper, DisplayManager.DisplayListener { - - @Nullable - public static DisplayHelper maybeBuildNewInstance(Context context) { - DisplayManager displayManager = - (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - return displayManager != null ? new DisplayHelperV17(displayManager) : null; - } + private final class DisplayHelper + implements DisplayManager.DisplayListener { private final DisplayManager displayManager; - @Nullable private Listener listener; - private DisplayHelperV17(DisplayManager displayManager) { + public DisplayHelper(DisplayManager displayManager) { this.displayManager = displayManager; } - @Override - public void register(Listener listener) { - this.listener = listener; + public void register() { displayManager.registerDisplayListener(this, Util.createHandlerForCurrentLooper()); - listener.onDefaultDisplayChanged(getDefaultDisplay()); + updateDefaultDisplayRefreshRateParams(getDefaultDisplay()); } - @Override public void unregister() { displayManager.unregisterDisplayListener(this); - listener = null; } @Override public void onDisplayChanged(int displayId) { - if (listener != null && displayId == Display.DEFAULT_DISPLAY) { - listener.onDefaultDisplayChanged(getDefaultDisplay()); + if (displayId == Display.DEFAULT_DISPLAY) { + updateDefaultDisplayRefreshRateParams(getDefaultDisplay()); } }