Skip to content

ashelke/media drm snippets#826

Draft
askandroid wants to merge 2 commits intoandroid:mainfrom
askandroid:ashelke/media-drm-snippets
Draft

ashelke/media drm snippets#826
askandroid wants to merge 2 commits intoandroid:mainfrom
askandroid:ashelke/media-drm-snippets

Conversation

@askandroid
Copy link

Test PR for Kat's skills.md.

Aparna Kliebenstein and others added 2 commits September 26, 2025 19:54
Adds a new ButtonExample composable to the compose/snippets module.

Region-Tag: android_compose_snippets_button_example
@askandroid askandroid requested review from a team, kkuan2011 and yrezgui as code owners March 5, 2026 02:36
@snippet-bot
Copy link

snippet-bot bot commented Mar 5, 2026

Here is the summary of changes.

You are about to add 5 region tags.

This comment is generated by snippet-bot.
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
To update this comment, add snippet-bot:force-run label or use the checkbox below:

  • Refresh this comment

@google-cla
Copy link

google-cla bot commented Mar 5, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces new code snippets demonstrating synchronous and asynchronous Digital Rights Management (DRM) handling with Android's MediaPlayer in both Kotlin and Java. It also sets up a new media module for these snippets and includes a placeholder Compose Button snippet. The PR description indicates this is a test PR.

Highlights

  • New Media Module: A new Gradle module named 'media' has been added to the project structure to house media-related code snippets.
  • MediaPlayer DRM Snippets (Kotlin): Implemented Kotlin examples for both synchronous and asynchronous Digital Rights Management (DRM) setup and playback using Android's MediaPlayer.
  • MediaPlayer DRM Snippets (Java): Provided equivalent Java examples for synchronous and asynchronous DRM integration with Android's MediaPlayer.
  • Compose Button Snippet: A new placeholder file for Compose Button snippets was added, though its direct relation to the media DRM changes is not immediately apparent.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • compose/snippets/src/main/java/com/example/compose/snippets/components/ButtonSnippets.kt
    • Added a new Kotlin file to host Compose Button snippets.
  • media/build.gradle.kts
    • Created a new Gradle build script for the media module, configuring it as an Android library with Kotlin support.
  • media/src/main/java/com/example/media/snippets/mediaplayer/DRMSnippets.kt
    • Introduced a new Kotlin file containing MediaPlayer DRM examples, covering both synchronous and asynchronous approaches.
  • media/src/main/java/com/example/media/snippets/mediaplayer/DRMSnippetsJava.java
    • Added a new Java file with MediaPlayer DRM examples, mirroring the Kotlin implementations for synchronous and asynchronous handling.
  • settings.gradle.kts
    • Updated the project's settings to include the newly created media module.
Activity
  • No activity (comments, reviews, etc.) was found for this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@askandroid askandroid requested review from mlykotom and removed request for mlykotom March 5, 2026 02:36
@askandroid askandroid marked this pull request as draft March 5, 2026 02:37
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds new media DRM snippets in both Kotlin and Java, along with a placeholder for a Compose Button snippet. My review focuses on improving the correctness and robustness of these snippets. The main issues identified are uninitialized variables that would lead to runtime crashes, missing exception handling for I/O and DRM operations, and resource leaks from not releasing MediaPlayer instances. I've provided suggestions to make the snippets functional and safe. Additionally, the new Compose snippet is currently empty, and I've suggested a basic implementation to make it useful.

Comment on lines +9 to +28
fun syncDRM() {
// [START android_mediaplayer_drm_sync]
mediaPlayer?.apply {
setDataSource("https://example.com/video.mp4")
setOnDrmConfigHelper { _ -> /* configuration */ } // optional, for custom configuration
prepare()
drmInfo?.also {
prepareDrm(UUID.randomUUID())
getKeyRequest(byteArrayOf(), byteArrayOf(), "", 0, null)
provideKeyResponse(byteArrayOf(), byteArrayOf())
}

// MediaPlayer is now ready to use
start()
// ...play/pause/resume...
stop()
releaseDrm()
}
// [END android_mediaplayer_drm_sync]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The syncDRM function has several critical issues:

  1. The mediaPlayer property is never initialized, so the code inside mediaPlayer?.apply will never execute, making the snippet non-functional.
  2. Methods like setDataSource() and prepare() can throw exceptions which are not handled.
  3. The MediaPlayer is not released with release() after use, which will cause a resource leak. releaseDrm() is called, but release() is also necessary.

I suggest refactoring the function to be self-contained and robust by initializing the MediaPlayer locally and using try-catch-finally for exception handling and resource management.

    fun syncDRM() {
        // [START android_mediaplayer_drm_sync]
        val mediaPlayer = MediaPlayer()
        try {
            mediaPlayer.apply {
                setDataSource("https://example.com/video.mp4")
                setOnDrmConfigHelper { _ -> /* configuration */ } // optional, for custom configuration
                prepare()
                drmInfo?.also {
                    try {
                        prepareDrm(UUID.randomUUID())
                        getKeyRequest(byteArrayOf(), byteArrayOf(), "", 0, null)
                        provideKeyResponse(byteArrayOf(), byteArrayOf())
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }

                // MediaPlayer is now ready to use
                start()
                // ...play/pause/resume...
                stop()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            mediaPlayer.releaseDrm()
            mediaPlayer.release()
        }
        // [END android_mediaplayer_drm_sync]
    }

Comment on lines +9 to +30
public void syncDRM() {
// [START android_mediaplayer_drm_sync_java]
try {
mediaPlayer.setDataSource("https://example.com/video.mp4");
mediaPlayer.setOnDrmConfigHelper(null); // optional, for custom configuration
mediaPlayer.prepare();
if (mediaPlayer.getDrmInfo() != null) {
mediaPlayer.prepareDrm(UUID.randomUUID());
mediaPlayer.getKeyRequest(null, null, null, 0, null);
mediaPlayer.provideKeyResponse(null, null);
}

// MediaPlayer is now ready to use
mediaPlayer.start();
// ...play/pause/resume...
mediaPlayer.stop();
mediaPlayer.releaseDrm();
} catch (Exception e) {
// Handle exceptions
}
// [END android_mediaplayer_drm_sync_java]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This function has two critical issues:

  1. The mediaPlayer field is used without being initialized, which will cause a NullPointerException as soon as mediaPlayer.setDataSource() is called.
  2. The MediaPlayer resource is not released with mediaPlayer.release(). This will lead to a resource leak. release() should be called in a finally block to ensure it executes even if exceptions occur.

I recommend initializing MediaPlayer within the method and using a finally block for cleanup.

    public void syncDRM() {
        // [START android_mediaplayer_drm_sync_java]
        MediaPlayer mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource("https://example.com/video.mp4");
            mediaPlayer.setOnDrmConfigHelper(null); // optional, for custom configuration
            mediaPlayer.prepare();
            if (mediaPlayer.getDrmInfo() != null) {
                mediaPlayer.prepareDrm(UUID.randomUUID());
                mediaPlayer.getKeyRequest(null, null, null, 0, null);
                mediaPlayer.provideKeyResponse(null, null);
            }

            // MediaPlayer is now ready to use
            mediaPlayer.start();
            // ...play/pause/resume...
            mediaPlayer.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mediaPlayer.releaseDrm();
            mediaPlayer.release();
        }
        // [END android_mediaplayer_drm_sync_java]
    }

Comment on lines +33 to +38
mediaPlayer.apply {
setOnPreparedListener(this@MyDrmActivity)
setOnDrmInfoListener(this@MyDrmActivity)
setDataSource("https://example.com/video.mp4")
prepareAsync()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The setDataSource() method can throw an IOException among other exceptions. This is unhandled and could crash the application. The corresponding Java snippet includes a try-catch block, and this Kotlin version should as well for robustness.

Suggested change
mediaPlayer.apply {
setOnPreparedListener(this@MyDrmActivity)
setOnDrmInfoListener(this@MyDrmActivity)
setDataSource("https://example.com/video.mp4")
prepareAsync()
}
try {
mediaPlayer.apply {
setOnPreparedListener(this@MyDrmActivity)
setOnDrmInfoListener(this@MyDrmActivity)
setDataSource("https://example.com/video.mp4")
prepareAsync()
}
} catch (e: Exception) {
e.printStackTrace()
}

Comment on lines +43 to +47
mediaPlayer.apply {
prepareDrm(UUID.randomUUID())
getKeyRequest(byteArrayOf(), byteArrayOf(), "", 0, null)
provideKeyResponse(byteArrayOf(), byteArrayOf())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The DRM methods prepareDrm(), getKeyRequest(), and provideKeyResponse() can all throw exceptions (e.g., UnsupportedSchemeException, NotProvisionedException). These should be handled in a try-catch block to prevent crashes.

            try {
                mediaPlayer.apply {
                    prepareDrm(UUID.randomUUID())
                    getKeyRequest(byteArrayOf(), byteArrayOf(), "", 0, null)
                    provideKeyResponse(byteArrayOf(), byteArrayOf())
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

Comment on lines +8 to +10
fun ButtonExample() {

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ButtonExample function is currently empty. To make this snippet useful, it should contain a basic implementation of a Button. I've suggested an example using fully qualified names to avoid needing to add imports. You may need to add a dependency on androidx.compose.material3 if it's not already present.

Additionally, the file is missing a newline character at the end, which is a common convention.

    fun ButtonExample() {
        androidx.compose.material3.Button(onClick = { /* Do something */ }) {
            androidx.compose.material3.Text("Button")
        }
    }

mediaPlayer.setDataSource("https://example.com/video.mp4");
mediaPlayer.prepareAsync();
} catch (Exception e) {
// Handle exceptions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This catch block is empty except for a comment. This can hide errors and make debugging difficult. At a minimum, the exception should be logged.

                e.printStackTrace();

mediaPlayer.getKeyRequest(null, null, null, 0, null);
mediaPlayer.provideKeyResponse(null, null);
} catch (Exception e) {
// Handle exceptions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This catch block is empty except for a comment. This can hide errors and make debugging difficult. At a minimum, the exception should be logged.

                e.printStackTrace();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant