From db594bbda25fe4d78cbec7ca36c0e01fd7f05eeb Mon Sep 17 00:00:00 2001 From: Ulysse Widmer Date: Fri, 1 May 2020 09:01:13 +0200 Subject: [PATCH] share pictures across apps (#129) * share implemented * added test for share intent --- .../java/com/h/pixeldroid/PostTest.kt | 69 +++++++++++++++++- .../java/com/h/pixeldroid/ImageFragment.kt | 4 + .../java/com/h/pixeldroid/objects/Status.kt | 17 ++++- .../java/com/h/pixeldroid/utils/ImageUtils.kt | 73 ++++++++++++------- app/src/main/res/menu/image_popup_menu.xml | 2 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 136 insertions(+), 30 deletions(-) diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt index 573a34ba..430cec6f 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt @@ -4,19 +4,27 @@ import android.content.Context import android.content.Intent import androidx.test.core.app.ActivityScenario import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.longClick import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.matcher.IntentMatchers +import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.espresso.matcher.RootMatchers import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule import com.h.pixeldroid.objects.Account import com.h.pixeldroid.objects.Attachment import com.h.pixeldroid.objects.Status import com.h.pixeldroid.testUtility.MockServer +import org.hamcrest.CoreMatchers +import org.hamcrest.Matcher +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test @@ -43,6 +51,7 @@ class PostTest { Context.MODE_PRIVATE) preferences.edit().putString("accessToken", "azerty").apply() preferences.edit().putString("domain", baseUrl.toString()).apply() + Intents.init() } @Test @@ -100,4 +109,62 @@ class PostTest { ).check(matches(isDisplayed())) Thread.sleep(5000) } -} \ No newline at end of file + + @Test + fun shareTestSimplePost() { + val expectedIntent: Matcher = IntentMatchers.hasAction(Intent.ACTION_CHOOSER) + val attachment = Attachment( + id = "12", + url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png" + ) + val post = Status( + id = "12", + account = Account( + id = "12", + username = "douze" + ), + media_attachments = listOf(attachment) + ) + val intent = Intent(context, PostActivity::class.java) + intent.putExtra(Status.POST_TAG, post) + ActivityScenario.launch(intent) + onView(withId(R.id.postPicture)).perform(longClick()) + onView(withText(R.string.share_picture)).inRoot(RootMatchers.isPlatformPopup()).perform(click()) + Thread.sleep(2000) + Intents.intended(expectedIntent) + } + + @Test + fun shareIntentAlbumTest() { + val expectedIntent: Matcher = IntentMatchers.hasAction(Intent.ACTION_CHOOSER) + val attachment1 = Attachment( + id = "12", + url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png" + ) + val attachment2 = Attachment( + id = "13", + url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png" + ) + val post = Status( + id = "12", + account = Account( + id = "12", + username = "douze" + ), + media_attachments = listOf(attachment1, attachment2) + ) + val intent = Intent(context, PostActivity::class.java) + intent.putExtra(Status.POST_TAG, post) + ActivityScenario.launch(intent) + onView(withId(R.id.imageImageView)).perform(longClick()) + onView(withText(R.string.share_picture)).inRoot(RootMatchers.isPlatformPopup()).perform(click()) + Thread.sleep(2000) + Intents.intended(expectedIntent) + } + + @After + fun after() { + Intents.release() + } + +} diff --git a/app/src/main/java/com/h/pixeldroid/ImageFragment.kt b/app/src/main/java/com/h/pixeldroid/ImageFragment.kt index 1a31ab49..55f9298c 100644 --- a/app/src/main/java/com/h/pixeldroid/ImageFragment.kt +++ b/app/src/main/java/com/h/pixeldroid/ImageFragment.kt @@ -51,6 +51,10 @@ class ImageFragment : Fragment() { ImageUtils.downloadImage(requireActivity(), view.context, imgUrl) true } + R.id.image_popup_menu_share_picture -> { + ImageUtils.downloadImage(requireActivity(), view.context, imgUrl, share = true) + true + } else -> false } } diff --git a/app/src/main/java/com/h/pixeldroid/objects/Status.kt b/app/src/main/java/com/h/pixeldroid/objects/Status.kt index bffd04a4..a957136c 100644 --- a/app/src/main/java/com/h/pixeldroid/objects/Status.kt +++ b/app/src/main/java/com/h/pixeldroid/objects/Status.kt @@ -1,9 +1,13 @@ package com.h.pixeldroid.objects -import android.app.Activity +import android.content.ContentValues import android.content.Context +import android.content.Intent +import android.graphics.Bitmap import android.graphics.Typeface import android.graphics.drawable.Drawable +import android.net.Uri +import android.provider.MediaStore import android.text.Spanned import android.text.method.LinkMovementMethod import android.util.Log @@ -16,15 +20,15 @@ import android.widget.LinearLayout import android.widget.PopupMenu import android.widget.TextView import android.widget.Toast +import androidx.core.content.ContextCompat.startActivity import androidx.core.text.toSpanned +import androidx.core.view.drawToBitmap import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter -import androidx.viewpager2.widget.ViewPager2 import com.bumptech.glide.RequestBuilder import com.google.android.material.tabs.TabLayoutMediator import com.h.pixeldroid.ImageFragment -import com.h.pixeldroid.MainActivity import com.h.pixeldroid.R import com.h.pixeldroid.api.PixelfedAPI import com.h.pixeldroid.fragments.feeds.PostViewHolder @@ -42,7 +46,10 @@ import kotlinx.android.synthetic.main.post_fragment.view.postPager import kotlinx.android.synthetic.main.post_fragment.view.postPicture import kotlinx.android.synthetic.main.post_fragment.view.postTabs import kotlinx.android.synthetic.main.post_fragment.view.profilePic +import retrofit2.http.Url +import java.io.OutputStream import java.io.Serializable +import java.net.URL /* Represents a status posted by an account. @@ -316,6 +323,10 @@ data class Status( downloadImage(activity, view.context, getPostUrl()!!) true } + R.id.image_popup_menu_share_picture -> { + downloadImage(activity, view.context, getPostUrl()!!, share = true) + true + } else -> false } } diff --git a/app/src/main/java/com/h/pixeldroid/utils/ImageUtils.kt b/app/src/main/java/com/h/pixeldroid/utils/ImageUtils.kt index 48b8274f..7dfe4f4f 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/ImageUtils.kt +++ b/app/src/main/java/com/h/pixeldroid/utils/ImageUtils.kt @@ -1,19 +1,24 @@ package com.h.pixeldroid.utils import android.app.DownloadManager +import android.content.ContentValues import android.content.Context +import android.content.Intent import android.database.Cursor +import android.graphics.Bitmap +import android.graphics.BitmapFactory import android.net.Uri import android.os.Environment -import android.provider.Settings.Global.getString +import android.provider.MediaStore.Images import android.widget.Toast import androidx.fragment.app.FragmentActivity import com.h.pixeldroid.R import java.io.File + class ImageUtils { companion object { - fun downloadImage(activity: FragmentActivity, context: Context, url: String) { + fun downloadImage(activity: FragmentActivity, context: Context, url: String, share: Boolean = false) { var msg = "" var lastMsg = "" val directory = File(Environment.DIRECTORY_PICTURES) @@ -24,6 +29,7 @@ class ImageUtils { as DownloadManager val downloadUri = Uri.parse(url) val title = url.substring(url.lastIndexOf("/") + 1) + val ext = url.substring(url.lastIndexOf(".")) val request = DownloadManager.Request(downloadUri).apply { setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE) @@ -43,35 +49,50 @@ class ImageUtils { downloading = false } val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) - msg = when (status) { - DownloadManager.STATUS_FAILED -> - context.getString(R.string.image_download_failed) - DownloadManager.STATUS_RUNNING -> - context.getString(R.string.image_download_downloading) - DownloadManager.STATUS_SUCCESSFUL -> - context.getString(R.string.image_download_success) - else -> "" - } - if (msg != lastMsg && msg != "") { - activity.runOnUiThread { - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() + if(!share) { + msg = when (status) { + DownloadManager.STATUS_FAILED -> + context.getString(R.string.image_download_failed) + DownloadManager.STATUS_RUNNING -> + context.getString(R.string.image_download_downloading) + DownloadManager.STATUS_SUCCESSFUL -> + context.getString(R.string.image_download_success) + else -> "" } - lastMsg = msg + if (msg != lastMsg && msg != "") { + activity.runOnUiThread { + Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() + } + lastMsg = msg + } + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + val icon: Bitmap = BitmapFactory.decodeFile( + Uri.parse(cursor.getString( + cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) + )).path + ) + val intentShare = Intent(Intent.ACTION_SEND) + intentShare.type = "image/$ext" + val values = ContentValues() + values.put(Images.Media.TITLE, title) + values.put(Images.Media.MIME_TYPE, "image/$ext") + val uri: Uri = context.contentResolver.insert( + Images.Media.EXTERNAL_CONTENT_URI, + values + )!! + try { + val outstream = context.contentResolver.openOutputStream(uri)!! + icon.compress(Bitmap.CompressFormat.JPEG, 100, outstream) + outstream.close() + } catch(e: Exception) { + e.printStackTrace() + } + intentShare.putExtra(Intent.EXTRA_STREAM, uri) + context.startActivity(Intent.createChooser(intentShare, "Share Image")) } cursor.close() } }).start() } - - private fun statusMessage(url: String, directory: File, status: Int, context: Context): String { - return when (status) { - DownloadManager.STATUS_FAILED -> context.getString(R.string.image_download_failed) - DownloadManager.STATUS_RUNNING -> "Downloading..." - DownloadManager.STATUS_SUCCESSFUL -> "Image downloaded successfully in $directory" + File.separator + url.substring( - url.lastIndexOf("/") + 1 - ) - else -> "" - } - } } } \ No newline at end of file diff --git a/app/src/main/res/menu/image_popup_menu.xml b/app/src/main/res/menu/image_popup_menu.xml index 69cbbea0..77c62e31 100644 --- a/app/src/main/res/menu/image_popup_menu.xml +++ b/app/src/main/res/menu/image_popup_menu.xml @@ -2,4 +2,6 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b5135e95..cd11a79b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,4 +49,5 @@ Download has been failed, please try again Downloading… Image downloaded successfully + Share picture...