mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-01 19:56:47 +01:00
Add ability to install APK from directly from Element (#2381)
And cleanup `data class OpenFile`
This commit is contained in:
parent
195bc8e914
commit
c40476aa94
@ -5,7 +5,7 @@ Features ✨:
|
||||
-
|
||||
|
||||
Improvements 🙌:
|
||||
-
|
||||
- Add ability to install APK from directly from Element (#2381)
|
||||
|
||||
Bugfix 🐛:
|
||||
- Message states cosmetic changes (#3007)
|
||||
|
@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
|
||||
object MimeTypes {
|
||||
const val Any: String = "*/*"
|
||||
const val OctetStream = "application/octet-stream"
|
||||
const val Apk = "application/vnd.android.package-archive"
|
||||
|
||||
const val Images = "image/*"
|
||||
|
||||
|
@ -28,6 +28,9 @@
|
||||
<!-- Needed for incoming calls -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<!-- To be able to install APK from the application -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<!-- Jitsi libs adds CALENDAR permissions, but we can remove them safely according to https://github.com/jitsi/jitsi-meet/issues/4068#issuecomment-480482481 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_CALENDAR"
|
||||
|
@ -29,6 +29,7 @@ import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.fragment.app.Fragment
|
||||
@ -132,6 +133,17 @@ fun startAddGoogleAccountIntent(context: Context, activityResultLauncher: Activi
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun startInstallFromSourceIntent(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
|
||||
.setData(Uri.parse(String.format("package:%s", context.packageName)))
|
||||
activityResultLauncher.launch(intent)
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
context.toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
}
|
||||
|
||||
fun startSharePlainTextIntent(fragment: Fragment,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
||||
chooserTitle: String?,
|
||||
|
@ -113,6 +113,7 @@ import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.core.utils.saveMedia
|
||||
import im.vector.app.core.utils.shareMedia
|
||||
import im.vector.app.core.utils.shareText
|
||||
import im.vector.app.core.utils.startInstallFromSourceIntent
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.DialogReportContentBinding
|
||||
import im.vector.app.databinding.FragmentRoomDetailBinding
|
||||
@ -197,6 +198,7 @@ import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||
@ -589,20 +591,53 @@ class RoomDetailFragment @Inject constructor(
|
||||
}
|
||||
|
||||
private fun startOpenFileIntent(action: RoomDetailViewEvents.OpenFile) {
|
||||
if (action.uri != null) {
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndTypeAndNormalize(action.uri, action.mimeType)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
if (intent.resolveActivity(requireActivity().packageManager) != null) {
|
||||
requireActivity().startActivity(intent)
|
||||
} else {
|
||||
requireActivity().toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
if (action.mimeType == MimeTypes.Apk) {
|
||||
installApk(action)
|
||||
} else {
|
||||
openFile(action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFile(action: RoomDetailViewEvents.OpenFile) {
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndTypeAndNormalize(action.uri, action.mimeType)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
if (intent.resolveActivity(requireActivity().packageManager) != null) {
|
||||
requireActivity().startActivity(intent)
|
||||
} else {
|
||||
requireActivity().toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
}
|
||||
|
||||
private fun installApk(action: RoomDetailViewEvents.OpenFile) {
|
||||
val safeContext = context ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (!safeContext.packageManager.canRequestPackageInstalls()) {
|
||||
roomDetailViewModel.pendingEvent = action
|
||||
startInstallFromSourceIntent(safeContext, installApkActivityResultLauncher)
|
||||
} else {
|
||||
openFile(action)
|
||||
}
|
||||
} else {
|
||||
openFile(action)
|
||||
}
|
||||
}
|
||||
|
||||
private val installApkActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
roomDetailViewModel.pendingEvent?.let {
|
||||
if (it is RoomDetailViewEvents.OpenFile) {
|
||||
openFile(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User cancelled
|
||||
}
|
||||
roomDetailViewModel.pendingEvent = null
|
||||
}
|
||||
|
||||
private fun displayPromptForIntegrationManager() {
|
||||
// The Sticker picker widget is not installed yet. Propose the user to install it
|
||||
val builder = AlertDialog.Builder(requireContext())
|
||||
|
@ -67,9 +67,8 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
||||
) : RoomDetailViewEvents()
|
||||
|
||||
data class OpenFile(
|
||||
val mimeType: String?,
|
||||
val uri: Uri?,
|
||||
val throwable: Throwable?
|
||||
val uri: Uri,
|
||||
val mimeType: String?
|
||||
) : RoomDetailViewEvents()
|
||||
|
||||
abstract class SendMessageResult : RoomDetailViewEvents()
|
||||
|
@ -141,6 +141,9 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
// Slot to keep a pending action during permission request
|
||||
var pendingAction: RoomDetailAction? = null
|
||||
|
||||
// Slot to keep a pending event during permission request
|
||||
var pendingEvent: RoomDetailViewEvents? = null
|
||||
|
||||
private var trackUnreadMessages = AtomicBoolean(false)
|
||||
private var mostRecentDisplayedEvent: TimelineEvent? = null
|
||||
|
||||
@ -1142,9 +1145,8 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
if (isLocalSendingFile) {
|
||||
tryOrNull { Uri.parse(mxcUrl) }?.let {
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenFile(
|
||||
action.messageFileContent.mimeType,
|
||||
it,
|
||||
null
|
||||
action.messageFileContent.mimeType
|
||||
))
|
||||
}
|
||||
} else {
|
||||
@ -1169,9 +1171,8 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
// We can now open the file
|
||||
session.fileService().getTemporarySharableURI(action.messageFileContent)?.let { uri ->
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenFile(
|
||||
action.messageFileContent.mimeType,
|
||||
uri,
|
||||
null
|
||||
action.messageFileContent.mimeType
|
||||
))
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user