Enable WebP decoding in Signal using libwebp v1.3.2
Co-authored-by: Greyson Parrelli <greyson@signal.org> Co-authored-by: Greyson Parrelli <greyson@pop-os.localdomain>
2
.github/workflows/android.yml
vendored
|
@ -18,6 +18,8 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
|
|
2
.github/workflows/diffuse.yml
vendored
|
@ -15,6 +15,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
ref: ${{ github.event.pull_request.base.sha }}
|
||||
|
||||
- name: set up JDK 17
|
||||
|
@ -45,6 +46,7 @@ jobs:
|
|||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
clean: 'false'
|
||||
|
||||
- name: Build with Gradle
|
||||
|
|
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "libwebp"]
|
||||
path = libwebp
|
||||
url = git@github.com:webmproject/libwebp.git
|
|
@ -15,6 +15,12 @@ Truths which we believe to be self-evident:
|
|||
1. **There is no such thing as time.** Protocol ideas that require synchronized clocks are doomed to failure.
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
1. You'll need to get the `libwebp` submodule after checking out the repository with `git submodule init && git submodule update`
|
||||
1. Most things are pretty straightforward, and opening the project in Android Studio should get you most of the way there.
|
||||
1. Depending on your configuration, you'll also likely need to install additional SDK Tool components, namely the versions of NDK and CMake we are currently using in our [Docker](https://github.com/signalapp/Signal-Android/blob/main/reproducible-builds/Dockerfile#L30) configuration.
|
||||
|
||||
## Issues
|
||||
|
||||
### Useful bug reports
|
||||
|
|
|
@ -520,6 +520,7 @@ dependencies {
|
|||
implementation project(':sms-exporter')
|
||||
implementation project(':sticky-header-grid')
|
||||
implementation project(':photoview')
|
||||
implementation project(':glide-webp')
|
||||
|
||||
implementation libs.libsignal.android
|
||||
|
||||
|
|
|
@ -60,6 +60,4 @@ public class EncryptedBitmapResourceEncoder extends EncryptedCoder implements Re
|
|||
return Bitmap.CompressFormat.JPEG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,14 @@ android {
|
|||
kotlinOptions {
|
||||
jvmTarget = signalKotlinJvmTarget
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -98,6 +98,8 @@ task qa {
|
|||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
// Because gradle is weird, we delete here for glide-webp/lib project so the clean tasks there doesn't barf
|
||||
delete fileTree("glide-webp/lib/.cxx")
|
||||
}
|
||||
|
||||
task format {
|
||||
|
|
|
@ -60,12 +60,21 @@ public final class StreamUtil {
|
|||
}
|
||||
|
||||
public static byte[] readFully(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
return readFully(in, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static byte[] readFully(InputStream in, int maxBytes) throws IOException {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int totalRead = 0;
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
bout.write(buffer, 0, read);
|
||||
totalRead += read;
|
||||
if (totalRead > maxBytes) {
|
||||
throw new IOException("Stream size limit exceeded");
|
||||
}
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
|
|
@ -10,4 +10,6 @@ android {
|
|||
dependencies {
|
||||
implementation libs.glide.glide
|
||||
kapt libs.glide.compiler
|
||||
|
||||
implementation project(':glide-webp')
|
||||
}
|
||||
|
|
1
glide-webp/app/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
25
glide-webp/app/build.gradle.kts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("signal-sample-app")
|
||||
kotlin("kapt")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.signal.glide.webp.app"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":glide-webp"))
|
||||
|
||||
implementation(libs.androidx.fragment.ktx)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.compose.material3)
|
||||
|
||||
implementation(libs.glide.glide)
|
||||
kapt(libs.glide.compiler)
|
||||
}
|
29
glide-webp/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Signal">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Signal">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
glide-webp/app/src/main/assets/test_01.webp
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
glide-webp/app/src/main/assets/test_02.webp
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
glide-webp/app/src/main/assets/test_03.webp
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
glide-webp/app/src/main/assets/test_04.webp
Normal file
After Width: | Height: | Size: 173 KiB |
BIN
glide-webp/app/src/main/assets/test_05.webp
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
glide-webp/app/src/main/assets/test_06_lossless.webp
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
glide-webp/app/src/main/assets/test_06_lossy.webp
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
glide-webp/app/src/main/assets/test_07_lossless.webp
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
glide-webp/app/src/main/assets/test_07_lossy.webp
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
glide-webp/app/src/main/assets/test_08_lossless.webp
Normal file
After Width: | Height: | Size: 149 KiB |
BIN
glide-webp/app/src/main/assets/test_08_lossy.webp
Normal file
After Width: | Height: | Size: 52 KiB |
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp.app
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.GlideBuilder
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import org.signal.core.util.dp
|
||||
|
||||
/**
|
||||
* Main activity for this sample app.
|
||||
*/
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.main_activitiy)
|
||||
|
||||
Glide.init(
|
||||
this,
|
||||
GlideBuilder()
|
||||
.setLogLevel(Log.VERBOSE)
|
||||
)
|
||||
|
||||
val context = this
|
||||
|
||||
findViewById<RecyclerView>(R.id.list).apply {
|
||||
adapter = ImageAdapter()
|
||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
}
|
||||
}
|
||||
|
||||
class ImageAdapter : RecyclerView.Adapter<ImageViewHolder>() {
|
||||
|
||||
private val data: List<String> = listOf(
|
||||
"test_01.webp",
|
||||
"test_02.webp",
|
||||
"test_03.webp",
|
||||
"test_04.webp",
|
||||
"test_05.webp",
|
||||
"test_06_lossless.webp",
|
||||
"test_06_lossy.webp",
|
||||
"test_07_lossless.webp"
|
||||
)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
|
||||
return ImageViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.image_item, parent, false))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
||||
holder.bind(data[position])
|
||||
}
|
||||
}
|
||||
|
||||
class ImageViewHolder(itemView: View) : ViewHolder(itemView) {
|
||||
val image: ImageView by lazy { itemView.findViewById(R.id.image) }
|
||||
|
||||
fun bind(filename: String) {
|
||||
Glide.with(itemView)
|
||||
.load(Uri.parse("file:///android_asset/$filename"))
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.override(250.dp)
|
||||
.into(image)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp.app
|
||||
|
||||
import android.content.Context
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.Registry
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.module.AppGlideModule
|
||||
import org.signal.core.util.logging.Log
|
||||
|
||||
@GlideModule
|
||||
class SampleAppGlideModule : AppGlideModule() {
|
||||
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
||||
Log.e("SPIDERMAN", "AppModule - registerComponents")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp.app.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp.app.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SignalTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colorScheme.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp.app.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
175
glide-webp/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
|
@ -0,0 +1,175 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
12
glide-webp/app/src/main/res/layout/image_item.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<ImageView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp">
|
||||
</ImageView>
|
12
glide-webp/app/src/main/res/layout/main_activitiy.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
glide-webp/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
glide-webp/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
glide-webp/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 982 B |
BIN
glide-webp/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
glide-webp/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
glide-webp/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
glide-webp/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
glide-webp/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
glide-webp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 7.6 KiB |
15
glide-webp/app/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
8
glide-webp/app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">Glide WebP</string>
|
||||
</resources>
|
9
glide-webp/app/src/main/res/values/themes.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<style name="Theme.Signal" parent="Theme.AppCompat.NoActionBar" />
|
||||
</resources>
|
2
glide-webp/lib/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/build
|
||||
.cxx
|
36
glide-webp/lib/build.gradle.kts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("signal-library")
|
||||
kotlin("kapt")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.signal.glide.webp"
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags("-std=c++17", "-fvisibility=hidden")
|
||||
arguments("-DLIBWEBP_PATH=$rootDir/libwebp")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path = file("$projectDir/src/main/cpp/CMakeLists.txt")
|
||||
version = "3.22.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core-util"))
|
||||
|
||||
implementation(libs.glide.glide)
|
||||
kapt(libs.glide.compiler)
|
||||
}
|
24
glide-webp/lib/src/main/cpp/CMakeLists.txt
Executable file
|
@ -0,0 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
project(signal-webp)
|
||||
|
||||
add_compile_options(-Oz)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
set(WEBP_BUILD_ANIM_UTILS OFF)
|
||||
set(WEBP_BUILD_CWEBP OFF)
|
||||
set(WEBP_BUILD_DWEBP OFF)
|
||||
set(WEBP_BUILD_VWEBP OFF)
|
||||
set(WEBP_BUILD_WEBPINFO OFF)
|
||||
set(WEBP_BUILD_LIBWEBPMUX OFF)
|
||||
set(WEBP_BUILD_EXTRAS OFF)
|
||||
set(WEBP_NEAR_LOSSLESS, OFF)
|
||||
|
||||
file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/*.cpp)
|
||||
|
||||
add_subdirectory(${LIBWEBP_PATH} ${CMAKE_CURRENT_BINARY_DIR}/libwebp)
|
||||
|
||||
add_library(signalwebp SHARED ${SOURCES})
|
||||
target_include_directories(signalwebp PRIVATE ${LIBWEBP_PATH}/src)
|
||||
target_link_libraries(signalwebp webpdemux)
|
62
glide-webp/lib/src/main/cpp/signalwebp.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <jni.h>
|
||||
#include <webp/demux.h>
|
||||
|
||||
jobject createBitmap(JNIEnv *env, int width, int height, const uint8_t *pixels) {
|
||||
static auto jbitmapConfigClass = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass("android/graphics/Bitmap$Config")));
|
||||
static jfieldID jbitmapConfigARGB8888Field = env->GetStaticFieldID(jbitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
|
||||
static auto jbitmapClass = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass("android/graphics/Bitmap")));
|
||||
static jmethodID jbitmapCreateBitmapMethod = env->GetStaticMethodID(jbitmapClass, "createBitmap", "([IIIIILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
|
||||
|
||||
jintArray intArray = env->NewIntArray(width * height);
|
||||
env->SetIntArrayRegion(intArray, 0, width * height, reinterpret_cast<const jint *>(pixels));
|
||||
|
||||
jobject argb8888Config = env->GetStaticObjectField(jbitmapConfigClass, jbitmapConfigARGB8888Field);
|
||||
jobject jbitmap = env->CallStaticObjectMethod(jbitmapClass, jbitmapCreateBitmapMethod, intArray, 0, width, width, height, argb8888Config);
|
||||
env->DeleteLocalRef(argb8888Config);
|
||||
|
||||
return jbitmap;
|
||||
}
|
||||
|
||||
jobject nativeDecodeBitmap(JNIEnv *env, jobject, jbyteArray data) {
|
||||
jbyte *javaBytes = env->GetByteArrayElements(data, nullptr);
|
||||
auto *buffer = reinterpret_cast<uint8_t *>(javaBytes);
|
||||
jsize bufferLength = env->GetArrayLength(data);
|
||||
|
||||
WebPBitstreamFeatures features;
|
||||
WebPGetFeatures(buffer, bufferLength, &features);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
uint8_t *pixels = WebPDecodeBGRA(buffer, bufferLength, &width, &height);
|
||||
jobject jbitmap = createBitmap(env, width, height, pixels);
|
||||
|
||||
WebPFree(pixels);
|
||||
env->ReleaseByteArrayElements(data, javaBytes, 0);
|
||||
|
||||
return jbitmap;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
jclass c = env->FindClass("org/signal/glide/webp/WebpDecoder");
|
||||
if (c == nullptr) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nativeDecodeBitmap", "([B)Landroid/graphics/Bitmap;", reinterpret_cast<void *>(nativeDecodeBitmap)}
|
||||
};
|
||||
|
||||
int rc = env->RegisterNatives(c, methods, sizeof(methods) / sizeof(JNINativeMethod));
|
||||
|
||||
if (rc != JNI_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp
|
||||
|
||||
import android.graphics.Bitmap
|
||||
|
||||
class WebpDecoder {
|
||||
|
||||
init {
|
||||
System.loadLibrary("signalwebp")
|
||||
}
|
||||
|
||||
external fun nativeDecodeBitmap(data: ByteArray): Bitmap?
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.ResourceDecoder
|
||||
import com.bumptech.glide.load.engine.Resource
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapResource
|
||||
import org.signal.core.util.StreamUtil
|
||||
import org.signal.core.util.logging.Log
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
class WebpInputStreamResourceDecoder(private val bitmapPool: BitmapPool) : ResourceDecoder<InputStream, Bitmap> {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "WebpResourceDecoder" // Name > 23 characters
|
||||
|
||||
private val MAGIC_NUMBER_P1 = byteArrayOf(0x52, 0x49, 0x46, 0x46) // "RIFF"
|
||||
private val MAGIC_NUMBER_P2 = byteArrayOf(0x57, 0x45, 0x42, 0x50) // "WEBP"
|
||||
|
||||
private const val MAX_WEBP_COMPRESSED_SIZE = 10 * 1024 * 1024; // 10mb
|
||||
}
|
||||
|
||||
/**
|
||||
* The "magic number" for a WEBP file is in the first 12 bytes. The layout is:
|
||||
*
|
||||
* [0-3]: "RIFF"
|
||||
* [4-7]: File length
|
||||
* [8-11]: "WEBP"
|
||||
*
|
||||
* We're not verifying the file length here, so we just need to check the first and last
|
||||
*/
|
||||
override fun handles(source: InputStream, options: Options): Boolean {
|
||||
return try {
|
||||
val magicNumberP1 = ByteArray(4)
|
||||
StreamUtil.readFully(source, magicNumberP1)
|
||||
|
||||
val fileLength = ByteArray(4)
|
||||
StreamUtil.readFully(source, fileLength)
|
||||
|
||||
val magicNumberP2 = ByteArray(4)
|
||||
StreamUtil.readFully(source, magicNumberP2)
|
||||
|
||||
magicNumberP1.contentEquals(MAGIC_NUMBER_P1) && magicNumberP2.contentEquals(MAGIC_NUMBER_P2)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Failed to read magic number from stream!", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(source: InputStream, width: Int, height: Int, options: Options): Resource<Bitmap>? {
|
||||
Log.d(TAG, "decode()")
|
||||
|
||||
val webp: ByteArray = try {
|
||||
StreamUtil.readFully(source, MAX_WEBP_COMPRESSED_SIZE)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Unexpected IOException hit while reading image data", e)
|
||||
throw e
|
||||
}
|
||||
|
||||
|
||||
val bitmap: Bitmap? = WebpDecoder().nativeDecodeBitmap(webp)
|
||||
return BitmapResource.obtain(bitmap, bitmapPool)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.glide.webp
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.Registry
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.module.LibraryGlideModule
|
||||
import org.signal.core.util.logging.Log
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Registers a custom handler for webp images.
|
||||
*/
|
||||
@GlideModule
|
||||
class WebpLibraryGlideModule : LibraryGlideModule() {
|
||||
companion object {
|
||||
private val TAG = Log.tag(WebpLibraryGlideModule::class.java)
|
||||
}
|
||||
|
||||
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
||||
Log.d(TAG, "registerComponents()")
|
||||
registry.prepend(InputStream::class.java, Bitmap::class.java, WebpInputStreamResourceDecoder(glide.bitmapPool))
|
||||
}
|
||||
}
|
|
@ -426,6 +426,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="95357e17469bed6ba57588baa55a6579633b6d02143878c4351bad04006c0295" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.compiler" name="compiler" version="1.3.2">
|
||||
<artifact name="compiler-1.3.2.jar">
|
||||
<sha256 value="d19beb5fc48395e1730acad2f654daa49a17f6b44a2a45a2e23a0dec806a6931" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="compiler-1.3.2.module">
|
||||
<sha256 value="fa7fc38c46d9440fb2673e6a128057d75bb896d0a991fe701cb07825b17f18a7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.compiler" name="compiler" version="1.4.3">
|
||||
<artifact name="compiler-1.4.3.jar">
|
||||
<sha256 value="43fcad86835221accdc8c4043fa52d2dfcc8d66442498d298c6404376d18d17c" origin="Generated by Gradle"/>
|
||||
|
|
1
libwebp
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit ca332209cb5567c9b249c86788cb2dbf8847e760
|
|
@ -27,7 +27,7 @@ RUN unzip ${ANDROID_COMMAND_LINE_TOOLS_FILENAME} -d /usr/local/android-sdk-linux
|
|||
RUN rm ${ANDROID_COMMAND_LINE_TOOLS_FILENAME}
|
||||
|
||||
RUN yes | sdkmanager --update --sdk_root="${ANDROID_HOME}"
|
||||
RUN yes | sdkmanager --sdk_root="${ANDROID_HOME}" "platforms;${ANDROID_API_LEVELS}" "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" "extras;google;m2repository" "extras;android;m2repository" "extras;google;google_play_services"
|
||||
RUN yes | sdkmanager --sdk_root="${ANDROID_HOME}" "platforms;${ANDROID_API_LEVELS}" "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" "extras;google;m2repository" "extras;android;m2repository" "extras;google;google_play_services" "ndk;25.1.8937393" "cmake;3.22.1"
|
||||
|
||||
RUN yes | sdkmanager --licenses --sdk_root="${ANDROID_HOME}"
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ include ':core-ui'
|
|||
include ':benchmark'
|
||||
include ':microbenchmark'
|
||||
include ':video-app'
|
||||
include ':glide-webp'
|
||||
include ':glide-webp-app'
|
||||
|
||||
project(':app').name = 'Signal-Android'
|
||||
project(':paging').projectDir = file('paging/lib')
|
||||
|
@ -85,6 +87,9 @@ project(':contacts-app').projectDir = file('contacts/app')
|
|||
project(':qr').projectDir = file('qr/lib')
|
||||
project(':qr-app').projectDir = file('qr/app')
|
||||
|
||||
project(':glide-webp').projectDir = file('glide-webp/lib')
|
||||
project(':glide-webp-app').projectDir = file('glide-webp/app')
|
||||
|
||||
rootProject.name='Signal'
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
apply from: 'dependencies.gradle'
|
||||
|
|