1 /*
<lambda>null2 * Copyright (C) 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.google.jetpackcamera.core.common
17
18 import android.content.ContentUris
19 import android.content.Context
20 import android.graphics.Bitmap
21 import android.graphics.ImageDecoder
22 import android.graphics.Matrix
23 import android.net.Uri
24 import android.provider.MediaStore
25 import java.io.File
26 import java.io.FileNotFoundException
27
28 /**
29 * Retrieves the URI for the most recently added image whose filename starts with "JCA".
30 *
31 * @param context The application context.
32 * @return The content URI of the matching image, or null if none is found.
33 */
34 fun getLastImageUri(context: Context): Uri? {
35 val projection = arrayOf(
36 MediaStore.Images.Media._ID,
37 MediaStore.Images.Media.DATE_ADDED
38 )
39
40 // Filter by filenames starting with "JCA"
41 val selection = "${MediaStore.Images.Media.DISPLAY_NAME} LIKE ?"
42 val selectionArgs = arrayOf("JCA%")
43
44 // Sort the results so that the most recently added image appears first.
45 val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
46
47 // Perform the query on the MediaStore.
48 context.contentResolver.query(
49 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
50 projection,
51 selection,
52 selectionArgs,
53 sortOrder
54 )?.use { cursor ->
55 if (cursor.moveToFirst()) {
56 val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
57 val id = cursor.getLong(idColumn)
58
59 return ContentUris.withAppendedId(
60 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
61 id
62 )
63 }
64 }
65 return null
66 }
67
68 /**
69 * Loads a Bitmap from a given URI and rotates it by the specified degrees.
70 *
71 * @param context The application context.
72 * @param uri The URI of the image to load.
73 * @param degrees The number of degrees to rotate the image by.
74 */
loadAndRotateBitmapnull75 fun loadAndRotateBitmap(context: Context, uri: Uri?, degrees: Float): Bitmap? {
76 uri ?: return null
77
78 if (uri.scheme == "file") {
79 val file = File(uri.path ?: "")
80 if (!file.exists()) {
81 return null
82 }
83 }
84
85 return try {
86 val bitmap = if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
87 MediaStore.Images.Media.getBitmap(context.contentResolver, uri)
88 } else {
89 val imageDecoderSource = ImageDecoder.createSource(context.contentResolver, uri)
90 ImageDecoder.decodeBitmap(imageDecoderSource)
91 }
92
93 bitmap?.let {
94 val matrix = Matrix().apply { postRotate(degrees) }
95 Bitmap.createBitmap(it, 0, 0, it.width, it.height, matrix, true)
96 }
97 } catch (e: FileNotFoundException) {
98 null
99 }
100 }
101