1 /*
<lambda>null2  * Copyright 2021 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 
17 package androidx.camera.integration.extensions.validation
18 
19 import android.app.Activity
20 import android.content.ContentResolver
21 import android.graphics.Bitmap
22 import android.graphics.BitmapFactory
23 import android.graphics.Matrix
24 import android.net.Uri
25 import android.os.Bundle
26 import android.view.LayoutInflater
27 import android.view.MotionEvent
28 import android.view.ScaleGestureDetector
29 import android.view.View
30 import android.view.ViewGroup
31 import android.widget.ImageView
32 import androidx.camera.integration.extensions.R
33 import androidx.fragment.app.Fragment
34 import androidx.viewpager2.widget.ViewPager2
35 
36 /** Fragment used for each individual page showing a photo inside [ImageValidationActivity]. */
37 class PhotoFragment constructor() : Fragment() {
38     private lateinit var imageUri: Uri
39     private var rotationDegrees: Int = 0
40     private var scaleGestureListener: ScaleGestureDetector.SimpleOnScaleGestureListener? = null
41 
42     /**
43      * Fragment used for each individual page showing a photo inside [ImageValidationActivity]
44      *
45      * @param imageUri The image uri to be displayed in this photo fragment
46      * @param rotationDegrees The rotation degrees to rotate the image to the upright direction
47      * @param scaleGestureListener The scale gesture listener which allow the caller activity to
48      *   receive the scale events to switch to another photo view which supports the translation
49      *   function in the X direction. It is because this fragment will be put inside a [ViewPager2]
50      *   and it will eat the X direction movement events for the [ViewPager2]'s page switch
51      *   function. But we'll need the translation function in X direction after the photo is zoomed
52      *   in.
53      */
54     constructor(
55         imageUri: Uri,
56         rotationDegrees: Int,
57         scaleGestureListener: ScaleGestureDetector.SimpleOnScaleGestureListener?
58     ) : this() {
59         this.imageUri = imageUri
60         this.rotationDegrees = rotationDegrees
61         this.scaleGestureListener = scaleGestureListener
62     }
63 
64     override fun onCreateView(
65         inflater: LayoutInflater,
66         container: ViewGroup?,
67         savedInstanceState: Bundle?
68     ): View = inflater.inflate(R.layout.single_photo_viewer, container, false)
69 
70     private lateinit var photoViewer: ImageView
71 
72     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
73         super.onViewCreated(view, savedInstanceState)
74 
75         if (!::imageUri.isInitialized) {
76             return
77         }
78 
79         photoViewer = view.findViewById(R.id.imageView)
80         photoViewer.setImageBitmap(
81             decodeImageToBitmap(
82                 (requireActivity() as Activity).contentResolver,
83                 imageUri,
84                 rotationDegrees
85             )
86         )
87 
88         setPhotoViewerScaleGestureListener()
89     }
90 
91     private fun setPhotoViewerScaleGestureListener() {
92         scaleGestureListener?.let {
93             val scaleDetector = ScaleGestureDetector(requireContext(), scaleGestureListener!!)
94             photoViewer.setOnTouchListener { _, e: MotionEvent -> scaleDetector.onTouchEvent(e) }
95         }
96     }
97 
98     companion object {
99         fun decodeImageToBitmap(
100             contentResolver: ContentResolver,
101             imageUri: Uri,
102             rotationDegrees: Int
103         ): Bitmap {
104             val parcelFileDescriptor = contentResolver.openFileDescriptor(imageUri, "r")
105             val bitmap = BitmapFactory.decodeFileDescriptor(parcelFileDescriptor?.fileDescriptor)
106             parcelFileDescriptor?.close()
107 
108             // Rotates the bitmap to the correct orientation
109             val matrix = Matrix()
110             matrix.postRotate(rotationDegrees.toFloat())
111             return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
112         }
113     }
114 }
115