How to display a 360 panorama from android application - android

I want to display a panorama from my android application, this panorama is online and I have its url I load it on a webview but it won't work properly. It just appears a portion of it, and it won't turn or move upside down. I have no idea where to start with this, can you point me at the right direction? thank you in advance

After a lot of research I found out this library it is still pretty new but sure can help you start with something. I'm posting it just to save time for other searchers! cheers
PanoramaGl

I had a similar situation in Kotlin, but I needed to get the image from a URL. I resolved it using Picasso. I leave this here for future reference:
val options = VrPanoramaView.Options()
val url = "https://urltoyourimage.com/image.jpg"
Picasso.get().load(url)
.into(object : Target {
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
options.inputType = VrPanoramaView.Options.TYPE_MONO
vrPanoramaView.loadImageFromBitmap(bitmap, options)
}
override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {
print(e?.localizedMessage)
}
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
print(placeHolderDrawable)
}
})

Add dependency in gradle (app-level)
compile 'com.google.vr:sdk-panowidget:1.80.0'
Add VrPanoramaView in your xml and get a reference via findViewById() method in android
Below is the code for loading the image from asset.
VrPanoramaView takes input as Bitmap so we need to first
convert it into right format. Here, the loadPhotoSphere functions
in called in onCreate()
private void loadPhotoSphere() {
VrPanoramaView.Options options = new VrPanoramaView.Options();
InputStream inputStream = null;
try {
inputStream = assetManager.open("image.jpg");
options.inputType = VrPanoramaView.Options.TYPE_MONO;
mVRPanoramaView.loadImageFromBitmap(BitmapFactory.decodeStream(inputStream), options);
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Read about Google VR SDK for Android here

Related

Uploading image to firebase storage (KOTLIN)

To retrieve an image in the gallery, most tutorials show the usage of
startActivityForResult()
It is currently deprecated, I have found this Basics of Intents as a substitute. The code block does return a URI, however, when I use that uri to set an image or to upload to firebase storage, it does not work.
Flow of getting and uploading the image:
Click the profile picture
Pick from file storage or gallery
After choosing, it would automatically set the image in the view and upload it to firebase storage associated with the auth ID of the current logged in user.
I have this in a fragment:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
CoroutineScope(Dispatchers.IO).launch {
sharedViewModel.uploadImage(uri)
}
binding.ivProfilePic.setImageURI(uri)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.ivProfilePic.setOnClickListener{
getContent.launch("image/*")
}
}
while this is the code for uploading to firebase:
private val storageRef = Firebase.storage.reference
fun uploadImage(path: Uri?){
val file = Uri.fromFile(File(path?.path!!))
storageRef.child("images/${UUID.randomUUID()}").putFile(file)
}
I think I am missing something here.
I appreciate the help.
I've found the solution!
for the registerActivity, I've used the photo picker support library link
I also added this dependency implementation 'androidx.activity:activity-ktx:1.6.1' as discussed in the documentation.
for the uploading to firebase I think I was just confused with the usage the File class and Uris. I could've passed the Uri at first, I was probably confused with the new keywords (File and Uri) and just jumped and the copy pasted the code.
this is the code I arrived at:
I've moved the registerForActivityResult code outside the onCreate() and just a child of the Fragment class.
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
binding.ivProfilePic.setImageURI(uri)
sharedViewModel.uploadImage(uri)
} else {
// insert code for toast showing no media selected
}
}
on onViewCreated():
binding.ivProfilePic.setOnClickListener{
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
and for uploading to firebase:
I've just passed the Uri
fun uploadImage(path: Uri){
storageRef.child("images/${UUID.randomUUID()}").putFile(path)
.addOnSuccessListener {
// Display upload complete
}
}
thank you for the help

Picasso Fetching Images in Activity, then show them into Fragment's ImageView

I am trying to fetch multiple images in an Activity with FragmentStateAdapter in it.
Then I need to show them into some Fragment's ImageView.
I want to preload them into the cache ( after I receive an API response with the info about images like imageID's)
Do I need to use do something else after .fetch() in Activity and do I need to create again same URL request and then load it into the right image view?
Currently, I am seeing images normally but I guess that they are not preloaded in Activity and I fetch them in the Fragment. I am not sure, how to check it?
Thank you for your help in advance!
class FavouriteActivity: - here I want to preload them:
#Subscribe
fun onCoolingImageInfoEvent(coolingEvent: FreezerImageEvent) {
viewModel.retrieveCoolingImage(coolingEvent.data)
val applianceID = viewModel.haID
viewModel.shownCoolingImages.value?.forEach {
picasso.load("https:/.../api/$applianceID/images/${it.imagekey}")
?.fetch() // does I need to do something else?
}
This is my adapter in which I have some fragments (for each image different one)
class FavouriteAdapter(
activity: BaseWearActivity,
private val viewModel: FavouriteViewModel
) : FragmentStateAdapter(activity) {
enum class FavouriteFragmentsEnum(
val position: Int,
val fragment: Fragment
) {
FAVOURITES(0, FavouritesFragment()),
COOLING_IMAGE(1, CoolingImageFragment(imageIndex = 0)),
COOLING_IMAGE_2(2, CoolingImageFragment(imageIndex = 1)),
//(...)
and Fragment code with images where I need to load already fetched images with Picaso
private fun initPicassoImage(coolingImageData: List<CoolingImageData>) {
applianceID = viewModel.haID
imageID = viewModel.getImageIDByIndex(imageIndex)
picasso.load("https:/.../api/$applianceID/images/$imageID")
?.into(current_image, object : Callback {
// (...)
} // does I need to do something else?
)
}
Your code seemed to me ok.
However, you are fetching images from your server. Picasso may invalidate the cache for that URL whenever your server change http headers such as etag, document size, etc in future for that URL.
You may use picasso.setIndicatorsEnabled(true) to see if an image loaded from cache. This adds a little indicator at top left of your image.
Color
Picasso loaded from
Red
Network
Green
Memory
Blue
Disk
I did it like that:
In Activity:
#Subscribe
fun onCoolingImageInfoEvent(coolingEvent: FreezerImageEvent?) {
(...)
viewModel.shownCoolingImages.forEach {
picasso
.load("https://(...)/$applianceID/images/${
viewModel.getImageIDByIndex(index)
}")
.priority(Picasso.Priority.HIGH)
?.fetch()
}
(...)
}
And in fragment:
private fun initPicassoImage() {
(...)
val imageUrl = "https://(...)/$applianceID/images/$imageID"
picasso
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(current_image, object : Callback {
override fun onSuccess() {
Log.d("PICASSO", "success load image from memory")
}
override fun onError(e: Exception?) {
//Try again online if cache failed
picasso
.load(imageUrl)
.into(current_image, object : Callback {
override fun onSuccess() {
Log.d("PICASSO", "load image from network")
}
override fun onError(e: Exception?) {
Log.e("Picasso", "Could not fetch image")
}
});
}
})
}
Take a Note: as #ocos said, you can check if it loads Image from Memory/Network.
However, you are fetching images from your server. Picasso may
invalidate the cache for that URL whenever your server change http headers such as etag, document size, etc in future for that URL.
You may use picasso.setIndicatorsEnabled(true) to see if an image
loaded from cache. This adds a little indicator at top left of your
image.
Color
Picasso loaded from
Red
Network
Green
Memory
Blue
Disk

kotlin androidpdfviewer lib doesn't seem to load

I am working with android pdfviewer lib to open and read a pdf, found at : https://github.com/barteksc/AndroidPdfViewer
But i got an error when i try to launch the pdf :
E/zygote64: No implementation found for long com.shockwave.pdfium.PdfiumCore.nativeOpenDocument(int, java.lang.String) (tried Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument and Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument__ILjava_lang_String_2)
E/PDFView: load pdf error
java.lang.UnsatisfiedLinkError: No implementation found for long com.shockwave.pdfium.PdfiumCore.nativeOpenDocument(int, java.lang.String) (tried Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument and Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument__ILjava_lang_String_2)
i tried with differents implementation of the dependency but none worked :
implementation 'com.github.barteksc:pdfium-android:1.9.0'
implementation "com.github.barteksc:android-pdf-viewer:3.2.0-beta.1"
implementation "com.github.barteksc:android-pdf-viewer:2.8.2"
The error is found here :
public PdfDocument newDocument(ParcelFileDescriptor fd, String password) throws IOException {
PdfDocument document = new PdfDocument();
document.parcelFileDescriptor = fd;
synchronized (lock) {
document.mNativeDocPtr = nativeOpenDocument(getNumFd(fd), password);
}
return document;
}
The fonction nativeOpenDocument from the lib doesn't seem to load.
I found some topic on github talking about it : https://github.com/barteksc/AndroidPdfViewer/issues/538
https://github.com/barteksc/PdfiumAndroid/issues/54
https://github.com/mshockwave/PdfiumAndroid/issues/13
But no solution found, as suggested i tried to change the dependency, tried to shut down my computer and my phone, tried to invalide cache and restart, tried on emulator but nothing work.
It would be very nice if someone could help me with that?
I just found out that in my case i had an app and a module where is my own library aar where i use the androidpdfviewer.
Probleme was that i had the dependency only on the lib and not the app.
To solve the probleme i had to add the dependency in both the app and the library. It's seem obvious now that i see that i have 2 build.gradle. Now it's working fine.
Add classpath 'com.github.barteksc:pdfium-android:1.9.0' in you build.gradle but the project not the module.
This is how I'm loading pdf url:
fragment_pdf_reader.xml:
<androidx.constraintlayout.widget.ConstraintLayout
//....
<com.github.barteksc.pdfviewer.PDFView
android:id="#+id/pdfView"
android:layout_width="match_parent"
android:layout_height="#dimen/zeroDp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="#+id/tvFeedback"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/view" />
//...
</androidx.constraintlayout.widget.ConstraintLayout>
Now inside your fragment get pdf url and make Http request with that pdf url and get ResponseBody pass it to the below method:
private fun downloadFile(responseBody: ResponseBody) {// get responseBody after making Http req . I'm using retrofit
binding?.let {
//it.pdfView.removeAllViews()
it.pdfView.fromBytes(responseBody.bytes())
.defaultPage(pageNumber)
.onPageChange(this#PdfReaderFragment)
.enableAnnotationRendering(true)
.onLoad(this#PdfReaderFragment)
.spacing(10) // in dp
.onPageError(this#PdfReaderFragment)
.onError { onError("File not in PDF format or corrupted") }
.load()
}
}
Implement these call backs :
OnPageChangeListener
OnLoadCompleteListener
OnPageErrorListener
implementation of above call backs are:
override fun loadComplete(nbPages: Int) {
binding?.let {
printBookmarksTree(it.pdfView.tableOfContents, "-")
}
}
override fun onPageError(page: Int, t: Throwable?) {
Log.d("PDF", t?.message)
}
override fun onPageChanged(page: Int, pageCount: Int) {
pageNumber = page
Log.d("PDF", "Page number $pageNumber $pageCount")
setTitleMessageBackArrow(String.format("%s %s / %s", "your fragment title", page + 1, pageCount))
}
private fun printBookmarksTree(tree: List<Bookmark>, sep: String) {
for (b in tree) {
Log.e("PDF", String.format("%s %s, p %d", sep, b.title, b.pageIdx))
if (b.hasChildren()) {
printBookmarksTree(b.children, "$sep-")
}
}
}

Create coroutine inside onBindViewHolder creates a mess

I am developing a chat application and there is a specific API so some things i must implement them with a specific way. For example (and the case that i have a problem...)
When i have to display an Image the API says that i have to split the Image in small chunks and store them as a message with a byteArray content. There is also a header message that its body is the messageIds of the fileChunks. So in the RecyclerView inside the onBindViewHolder, when i see a header file message (msgType == 1) then i start a coroutine to fetch the chunkFile messages by the ids, construct the File and then switch to the MainDispatcher, and so the Image with Glide using a BitmapFactory.decodeByteArray. The code is shown below
messageItem.message?.msgType == MSG_TYPE_FILE -> {
holder.sntBody.text = "Loading file"
val fileInfo = Gson().fromJson(URLDecoder.decode(messageItem.message?.body, "UTF-8"), FileInformation::class.java)
job = chatRoomAdapterScope.launch(Dispatchers.IO) {
// i get the messageIds of the chunks from Header message
val segSequence = fileInfo.seg.split(",").map { it.toLong() }
// i get the fileChunks from Database
val fileChunks = AppDatabase.invoke(mContext).messageDao().getMessageById(segSequence)
val compactFile = ByteArrayOutputStream()
// Reconstruct the file
for (chunk in fileChunks)
compactFile.write(Base64.decode(chunk.fileBody, Base64.DEFAULT))
withContext(Dispatchers.Main) {
val bitmapOptions = BitmapFactory.Options().apply {
inSampleSize = 8
}
Glide.with(mContext).asBitmap()
.load(BitmapFactory.decodeByteArray(compactFile.toByteArray(), 0, compactFile.size(), bitmapOptions)!!)
.fitCenter()
.into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
holder.sntImageView.setImageBitmap(resource)
holder.sntImageView.visibility = View.VISIBLE
}
})
holder.sntBody.text = fileInfo.filename
}
}
}
My problem is that when i scroll fast the image that is supposed to be loaded in an item appears in another item. My first guess is that the Coroutine that started from a specific item didnt complete as soon as the item was recycled so when the coroutine finished it had a reference to a new item, so i added the
holder.itemView.addOnAttachStateChangeListener method as some people commented. However i didn't work.
Is there any idea of why that may happens and if there is a better implementation of the proccess according to the specific API...?
You can cancel the coroutine in override fun onViewRecycled(holder: EventViewHolder).

FFmpegMediaMetadataRetriever from External Storage? Android Studio/Kotlin

So I'm making my first Android app and I'm trying to get it to allow the user to pick a video from their gallery before seeing the video and the video's current details in the next activity.
My problem is that when I use FFmpegMediaMetadataRetriever and pass it the video's filepath, I receive the error java.lang.IllegalArgumentException: setDataSource failed: status = 0xFFFFFFFF.
I've heard through the grapevine that this means my filepath is invalid. When I Log.d the filepath, I get content://media/external/file/3565, which to me looks like a proper filepath!
I hope somebody can help me figure this out.
Here is my activity class for context:
class NewProject : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_project)
val videoPath = intent.getStringExtra("video")
initVideo(videoPath)
backButtonText.setOnClickListener{ goBack() }
}
private fun goBack() {
val intent = Intent(this,MainActivity::class.java)
startActivity(intent)
}
private fun initVideo(videoPath:String) {
newProjVideoView.setVideoPath(videoPath)
newProjVideoView.start()
newProjVideoView.setOnCompletionListener {
newProjVideoView.pause()
}
getVideoMetadata(videoPath)
}
private fun getVideoMetadata(videoPath: String) {
try {
e("videoPath", videoPath)
val receiver = FFmpegMediaMetadataRetriever()
receiver.setDataSource(videoPath)
} catch (e:IOException) {
e("retrieve1","There was an issue", e)
}
}
}
I'm also happy to hear any constructive feedback on my code!
Please, thank you and have a nice day!
So, I think my issue stemmed from trying to pass the video through an intent and then running the MetadataRetriever. I solved it by getting all the info in the previous activity before passing each value as an extra to be used on the next screen.

Categories

Resources