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

Commit ced69804 authored by Uwais Ashraf's avatar Uwais Ashraf Committed by Android (Google) Code Review
Browse files

Merge "Convert ThumbnailData to kotlin for easier mocking in tests" into main

parents 458ab233 102a7307
Loading
Loading
Loading
Loading
+0 −120
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.model;

import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.graphics.Bitmap.Config.ARGB_8888;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Log;
import android.view.WindowInsetsController.Appearance;
import android.window.TaskSnapshot;

import java.util.HashMap;

/**
 * Data for a single thumbnail.
 */
public class ThumbnailData {

    public final Bitmap thumbnail;
    public int orientation;
    public int rotation;
    public Rect insets;
    public Rect letterboxInsets;
    public boolean reducedResolution;
    public boolean isRealSnapshot;
    public boolean isTranslucent;
    public int windowingMode;
    public @Appearance int appearance;
    public float scale;
    public long snapshotId;

    public ThumbnailData() {
        thumbnail = null;
        orientation = ORIENTATION_UNDEFINED;
        rotation = ROTATION_UNDEFINED;
        insets = new Rect();
        letterboxInsets = new Rect();
        reducedResolution = false;
        scale = 1f;
        isRealSnapshot = true;
        isTranslucent = false;
        windowingMode = WINDOWING_MODE_UNDEFINED;
        snapshotId = 0;
    }

    public void recycleBitmap() {
        if (thumbnail != null) {
            thumbnail.recycle();
        }
    }

    private static Bitmap makeThumbnail(TaskSnapshot snapshot) {
        Bitmap thumbnail = null;
        try (final HardwareBuffer buffer = snapshot.getHardwareBuffer()) {
            if (buffer != null) {
                thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
            }
        } catch (IllegalArgumentException ex) {
            // TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
            Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
                    + snapshot.getHardwareBuffer(), ex);
        }
        if (thumbnail == null) {
            Point taskSize = snapshot.getTaskSize();
            thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
            thumbnail.eraseColor(Color.BLACK);
        }
        return thumbnail;
    }

    public static HashMap<Integer, ThumbnailData> wrap(int[] taskIds, TaskSnapshot[] snapshots) {
        HashMap<Integer, ThumbnailData> temp = new HashMap<>();
        if (taskIds == null || snapshots == null || taskIds.length != snapshots.length) {
            return temp;
        }

        for (int i = snapshots.length - 1; i >= 0; i--) {
            temp.put(taskIds[i], new ThumbnailData(snapshots[i]));
        }
        return temp;
    }

    public ThumbnailData(TaskSnapshot snapshot) {
        thumbnail = makeThumbnail(snapshot);
        insets = new Rect(snapshot.getContentInsets());
        letterboxInsets = new Rect(snapshot.getLetterboxInsets());
        orientation = snapshot.getOrientation();
        rotation = snapshot.getRotation();
        reducedResolution = snapshot.isLowResolution();
        // TODO(b/149579527): Pass task size instead of computing scale.
        // Assume width and height were scaled the same; compute scale only for width
        scale = (float) thumbnail.getWidth() / snapshot.getTaskSize().x;
        isRealSnapshot = snapshot.isRealSnapshot();
        isTranslucent = snapshot.isTranslucent();
        windowingMode = snapshot.getWindowingMode();
        appearance = snapshot.getAppearance();
        snapshotId = snapshot.getId();
    }
}
+101 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.model

import android.app.WindowConfiguration
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Bitmap.Config.ARGB_8888
import android.graphics.Color
import android.graphics.Rect
import android.util.Log
import android.view.WindowInsetsController.Appearance
import android.window.TaskSnapshot

/** Data for a single thumbnail. */
data class ThumbnailData(
    val thumbnail: Bitmap? = null,
    var orientation: Int = Configuration.ORIENTATION_UNDEFINED,
    @JvmField var rotation: Int = WindowConfiguration.ROTATION_UNDEFINED,
    @JvmField var insets: Rect = Rect(),
    @JvmField var letterboxInsets: Rect = Rect(),
    @JvmField var reducedResolution: Boolean = false,
    @JvmField var isRealSnapshot: Boolean = true,
    var isTranslucent: Boolean = false,
    @JvmField var windowingMode: Int = WindowConfiguration.WINDOWING_MODE_UNDEFINED,
    @JvmField @Appearance var appearance: Int = 0,
    @JvmField var scale: Float = 1f,
    var snapshotId: Long = 0,
) {
    fun recycleBitmap() {
        thumbnail?.recycle()
    }

    companion object {
        private fun makeThumbnail(snapshot: TaskSnapshot): Bitmap {
            var thumbnail: Bitmap? = null
            try {
                snapshot.hardwareBuffer?.use { buffer ->
                    thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.colorSpace)
                }
            } catch (ex: IllegalArgumentException) {
                // TODO(b/157562905): Workaround for a crash when we get a snapshot without this
                // state
                Log.e(
                    "ThumbnailData",
                    "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: " +
                        "${snapshot.hardwareBuffer}",
                    ex
                )
            }

            return thumbnail
                ?: Bitmap.createBitmap(snapshot.taskSize.x, snapshot.taskSize.y, ARGB_8888).apply {
                    eraseColor(Color.BLACK)
                }
        }

        @JvmStatic
        fun wrap(taskIds: IntArray?, snapshots: Array<TaskSnapshot>?): HashMap<Int, ThumbnailData> {
            return if (taskIds == null || snapshots == null || taskIds.size != snapshots.size) {
                HashMap()
            } else {
                HashMap(taskIds.associateWith { taskId -> fromSnapshot(snapshots[taskId]) })
            }
        }

        @JvmStatic
        fun fromSnapshot(snapshot: TaskSnapshot): ThumbnailData {
            val thumbnail = makeThumbnail(snapshot)
            return ThumbnailData(
                thumbnail = thumbnail,
                insets = Rect(snapshot.contentInsets),
                letterboxInsets = Rect(snapshot.letterboxInsets),
                orientation = snapshot.orientation,
                rotation = snapshot.rotation,
                reducedResolution = snapshot.isLowResolution,
                // TODO(b/149579527): Pass task size instead of computing scale.
                // Assume width and height were scaled the same; compute scale only for width
                scale = thumbnail.width.toFloat() / snapshot.taskSize.x,
                isRealSnapshot = snapshot.isRealSnapshot,
                isTranslucent = snapshot.isTranslucent,
                windowingMode = snapshot.windowingMode,
                appearance = snapshot.appearance,
                snapshotId = snapshot.id,
            )
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -147,7 +147,7 @@ public class ActivityManagerWrapper {
            Log.w(TAG, "Failed to retrieve task snapshot", e);
        }
        if (snapshot != null) {
            return new ThumbnailData(snapshot);
            return ThumbnailData.fromSnapshot(snapshot);
        } else {
            return new ThumbnailData();
        }
@@ -167,7 +167,7 @@ public class ActivityManagerWrapper {
            Log.w(TAG, "Failed to take task snapshot", e);
        }
        if (snapshot != null) {
            return new ThumbnailData(snapshot);
            return ThumbnailData.fromSnapshot(snapshot);
        } else {
            return new ThumbnailData();
        }
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ public class RecentsAnimationControllerCompat {
        try {
            final TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId);
            if (snapshot != null) {
                return new ThumbnailData(snapshot);
                return ThumbnailData.fromSnapshot(snapshot);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to screenshot task", e);
+1 −1
Original line number Diff line number Diff line
@@ -351,7 +351,7 @@ public class TaskStackChangeListeners {
                    case ON_TASK_SNAPSHOT_CHANGED: {
                        Trace.beginSection("onTaskSnapshotChanged");
                        final TaskSnapshot snapshot = (TaskSnapshot) msg.obj;
                        final ThumbnailData thumbnail = new ThumbnailData(snapshot);
                        final ThumbnailData thumbnail = ThumbnailData.fromSnapshot(snapshot);
                        boolean snapshotConsumed = false;
                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                            boolean consumed = mTaskStackListeners.get(i).onTaskSnapshotChanged(
Loading