Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 538c23d9 authored by Xiang Wang's avatar Xiang Wang Committed by Automerger Merge Worker
Browse files

Merge "Provide game task bitmap to TakeScreenshotService as screenshot" into tm-dev am: 81aa0eac

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16938819

Change-Id: I3efaffc791c8fc2c9ea52c1901e7133a9aa32b3e
parents b3a96731 81aa0eac
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11405,7 +11405,7 @@ package android.service.games {
  public static interface GameSession.ScreenshotCallback {
    method public void onFailure(int);
    method public void onSuccess(@NonNull android.graphics.Bitmap);
    method public void onSuccess();
    field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
  }
+11 −41
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package android.service.games;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;

@@ -30,9 +28,7 @@ import java.util.Objects;
/**
 * Result object for calls to {@link IGameSessionController#takeScreenshot}.
 *
 * It includes a status (see {@link #getStatus}) and, if the status is
 * {@link #GAME_SCREENSHOT_SUCCESS} an {@link android.graphics.Bitmap} result (see {@link
 * #getBitmap}).
 * It includes a status only (see {@link #getStatus}).
 *
 * @hide
 */
@@ -54,8 +50,7 @@ public final class GameScreenshotResult implements Parcelable {

    /**
     * Indicates that the result of a call to {@link IGameSessionController#takeScreenshot} was
     * successful and an {@link android.graphics.Bitmap} result should be available by calling
     * {@link #getBitmap}.
     * successful.
     *
     * @hide
     */
@@ -81,9 +76,7 @@ public final class GameScreenshotResult implements Parcelable {
            new Parcelable.Creator<GameScreenshotResult>() {
                @Override
                public GameScreenshotResult createFromParcel(Parcel source) {
                    return new GameScreenshotResult(
                            source.readInt(),
                            source.readParcelable(null, Bitmap.class));
                    return new GameScreenshotResult(source.readInt());
                }

                @Override
@@ -95,14 +88,11 @@ public final class GameScreenshotResult implements Parcelable {
    @GameScreenshotStatus
    private final int mStatus;

    @Nullable
    private final Bitmap mBitmap;

    /**
     * Creates a successful {@link GameScreenshotResult} with the provided bitmap.
     * Creates a successful {@link GameScreenshotResult}.
     */
    public static GameScreenshotResult createSuccessResult(@NonNull Bitmap bitmap) {
        return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS, bitmap);
    public static GameScreenshotResult createSuccessResult() {
        return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS);
    }

    /**
@@ -110,12 +100,11 @@ public final class GameScreenshotResult implements Parcelable {
     * {@link #GAME_SCREENSHOT_ERROR_INTERNAL_ERROR} status.
     */
    public static GameScreenshotResult createInternalErrorResult() {
        return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR, null);
        return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR);
    }

    private GameScreenshotResult(@GameScreenshotStatus int status, @Nullable Bitmap bitmap) {
    private GameScreenshotResult(@GameScreenshotStatus int status) {
        this.mStatus = status;
        this.mBitmap = bitmap;
    }

    @Override
@@ -126,7 +115,6 @@ public final class GameScreenshotResult implements Parcelable {
    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mStatus);
        dest.writeParcelable(mBitmap, flags);
    }

    @GameScreenshotStatus
@@ -134,29 +122,12 @@ public final class GameScreenshotResult implements Parcelable {
        return mStatus;
    }

    /**
     * Gets the {@link Bitmap} result from a successful screenshot attempt.
     *
     * @return The bitmap.
     * @throws IllegalStateException if this method is called when {@link #getStatus} does not
     *                               return {@link #GAME_SCREENSHOT_SUCCESS}.
     */
    @NonNull
    public Bitmap getBitmap() {
        if (mBitmap == null) {
            throw new IllegalStateException("Bitmap not available for failed screenshot result");
        }
        return mBitmap;
    }

    @Override
    public String toString() {
        return "GameScreenshotResult{"
                + "mStatus="
                + mStatus
                + ", has bitmap='"
                + mBitmap != null ? "yes" : "no"
                + "\'}";
                + "}";
    }

    @Override
@@ -170,12 +141,11 @@ public final class GameScreenshotResult implements Parcelable {
        }

        GameScreenshotResult that = (GameScreenshotResult) o;
        return mStatus == that.mStatus
                && Objects.equals(mBitmap, that.mBitmap);
        return mStatus == that.mStatus;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mStatus, mBitmap);
        return Objects.hash(mStatus);
    }
}
+5 −8
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -367,7 +366,7 @@ public abstract class GameSession {
    }

    /**
     * Interface for returning screenshot outcome from calls to {@link #takeScreenshot}.
     * Interface for handling result of {@link #takeScreenshot}.
     */
    public interface ScreenshotCallback {

@@ -402,18 +401,16 @@ public abstract class GameSession {

        /**
         * Called when taking the screenshot succeeded.
         *
         * @param bitmap The screenshot.
         */
        void onSuccess(@NonNull Bitmap bitmap);
        void onSuccess();
    }

    /**
     * Takes a screenshot of the associated game. For this call to succeed, the device screen
     * must be turned on and the game task must be visible.
     *
     * If the callback is called with {@link ScreenshotCallback#onSuccess}, the provided {@link
     * Bitmap} may be used.
     * If the callback is called with {@link ScreenshotCallback#onSuccess}, the screenshot is
     * taken successfully.
     *
     * If the callback is called with {@link ScreenshotCallback#onFailure}, the provided status
     * code should be checked.
@@ -460,7 +457,7 @@ public abstract class GameSession {
        @GameScreenshotResult.GameScreenshotStatus int status = result.getStatus();
        switch (status) {
            case GameScreenshotResult.GAME_SCREENSHOT_SUCCESS:
                callback.onSuccess(result.getBitmap());
                callback.onSuccess();
                break;
            case GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR:
                Slog.w(TAG, "Error taking screenshot");
+71 −0
Original line number Diff line number Diff line
@@ -11,8 +11,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.Insets;
import android.graphics.ParcelableColorSpace;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -26,6 +30,7 @@ import android.os.UserHandle;
import android.util.Log;
import android.view.WindowManager;

import java.util.Objects;
import java.util.function.Consumer;

public class ScreenshotHelper {
@@ -154,6 +159,72 @@ public class ScreenshotHelper {
                };
    }

    /**
     * Bundler used to convert between a hardware bitmap and a bundle without copying the internal
     * content. This is expected to be used together with {@link #provideScreenshot} to handle a
     * hardware bitmap as a screenshot.
     */
    public static final class HardwareBitmapBundler {
        private static final String KEY_BUFFER = "bitmap_util_buffer";
        private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";

        private HardwareBitmapBundler() {
        }

        /**
         * Creates a Bundle that represents the given Bitmap.
         * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
         * copies when passing across processes, only pass to processes you trust.
         *
         * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
         * returned Bundle should be treated as a standalone object.
         *
         * @param bitmap to convert to bundle
         * @return a Bundle representing the bitmap, should only be parsed by
         * {@link #bundleToHardwareBitmap(Bundle)}
         */
        public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
            if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
                throw new IllegalArgumentException(
                        "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
            }

            // Bitmap assumes SRGB for null color space
            ParcelableColorSpace colorSpace =
                    bitmap.getColorSpace() == null
                            ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
                            : new ParcelableColorSpace(bitmap.getColorSpace());

            Bundle bundle = new Bundle();
            bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
            bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);

            return bundle;
        }

        /**
         * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
         *
         * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing
         * this
         * Bitmap on to any other source.
         *
         * @param bundle containing the bitmap
         * @return a hardware Bitmap
         */
        public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
            if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
                throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
            }

            HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
            ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);

            return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
                    colorSpace.getColorSpace());
        }
    }

    private static final String TAG = "ScreenshotHelper";

    // Time until we give up on the screenshot & show an error instead.
+0 −87
Original line number Diff line number Diff line
/*
 * 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.systemui.shared.recents.utilities;

import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.ParcelableColorSpace;
import android.hardware.HardwareBuffer;
import android.os.Bundle;

import java.util.Objects;

/**
 * Utils for working with Bitmaps.
 */
public final class BitmapUtil {
    private static final String KEY_BUFFER = "bitmap_util_buffer";
    private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";

    private BitmapUtil(){ }

    /**
     * Creates a Bundle that represents the given Bitmap.
     * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
     * copies when passing across processes, only pass to processes you trust.
     *
     * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
     * returned Bundle should be treated as a standalone object.
     *
     * @param bitmap to convert to bundle
     * @return a Bundle representing the bitmap, should only be parsed by
     *         {@link #bundleToHardwareBitmap(Bundle)}
     */
    public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
        if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
            throw new IllegalArgumentException(
                    "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
        }

        // Bitmap assumes SRGB for null color space
        ParcelableColorSpace colorSpace =
                bitmap.getColorSpace() == null
                        ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
                        : new ParcelableColorSpace(bitmap.getColorSpace());

        Bundle bundle = new Bundle();
        bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
        bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);

        return bundle;
    }

    /**
     * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
     *
     * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
     * Bitmap on to any other source.
     *
     * @param bundle containing the bitmap
     * @return a hardware Bitmap
     */
    public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
        if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
            throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
        }

        HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
        ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);

        return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
                colorSpace.getColorSpace());
    }
}
Loading