diff --git a/BUILDING.md b/BUILDING.md
index cea307ad07..5e837e528c 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -30,6 +30,18 @@ The following steps should help you (re)build TextSecure from the command line.
./gradlew build
+Visual assets
+----------------------
+
+Source assets tend to be large binary blobs, which are best stored outside of git repositories. We host ours in a [Pixelapse repository](https://www.pixelapse.com/openwhispersystems/projects/signal-android/). Some source files are SVGs that can be auto-colored and sized using a tool like [android-res-utils](https://github.com/sebkur/android-res-utils).
+
+Sample command for generating our audio placeholder image:
+
+```bash
+pngs_from_svg.py ic_audio.svg /path/to/TextSecure/res/ 150 "#000" 0.54 _light
+pngs_from_svg.py ic_audio.svg /path/to/TextSecure/res/ 150 "#fff" 1.0 _dark
+```
+
Setting up a development environment
------------------------------------
diff --git a/res/drawable-hdpi/ic_audio_dark.png b/res/drawable-hdpi/ic_audio_dark.png
new file mode 100644
index 0000000000..6b865ebd6d
Binary files /dev/null and b/res/drawable-hdpi/ic_audio_dark.png differ
diff --git a/res/drawable-hdpi/ic_audio_light.png b/res/drawable-hdpi/ic_audio_light.png
new file mode 100644
index 0000000000..45c439e07f
Binary files /dev/null and b/res/drawable-hdpi/ic_audio_light.png differ
diff --git a/res/drawable-hdpi/ic_video_dark.png b/res/drawable-hdpi/ic_video_dark.png
new file mode 100644
index 0000000000..ae43e5f842
Binary files /dev/null and b/res/drawable-hdpi/ic_video_dark.png differ
diff --git a/res/drawable-hdpi/ic_video_light.png b/res/drawable-hdpi/ic_video_light.png
new file mode 100644
index 0000000000..90830d1102
Binary files /dev/null and b/res/drawable-hdpi/ic_video_light.png differ
diff --git a/res/drawable-mdpi/ic_audio_dark.png b/res/drawable-mdpi/ic_audio_dark.png
new file mode 100644
index 0000000000..256c04bab6
Binary files /dev/null and b/res/drawable-mdpi/ic_audio_dark.png differ
diff --git a/res/drawable-mdpi/ic_audio_light.png b/res/drawable-mdpi/ic_audio_light.png
new file mode 100644
index 0000000000..fd2d3d06da
Binary files /dev/null and b/res/drawable-mdpi/ic_audio_light.png differ
diff --git a/res/drawable-mdpi/ic_video_dark.png b/res/drawable-mdpi/ic_video_dark.png
new file mode 100644
index 0000000000..4390851edd
Binary files /dev/null and b/res/drawable-mdpi/ic_video_dark.png differ
diff --git a/res/drawable-mdpi/ic_video_light.png b/res/drawable-mdpi/ic_video_light.png
new file mode 100644
index 0000000000..da0a760d39
Binary files /dev/null and b/res/drawable-mdpi/ic_video_light.png differ
diff --git a/res/drawable-xhdpi/ic_audio_dark.png b/res/drawable-xhdpi/ic_audio_dark.png
new file mode 100644
index 0000000000..907ff68a1f
Binary files /dev/null and b/res/drawable-xhdpi/ic_audio_dark.png differ
diff --git a/res/drawable-xhdpi/ic_audio_light.png b/res/drawable-xhdpi/ic_audio_light.png
new file mode 100644
index 0000000000..3fe1d58cb0
Binary files /dev/null and b/res/drawable-xhdpi/ic_audio_light.png differ
diff --git a/res/drawable-xhdpi/ic_video_dark.png b/res/drawable-xhdpi/ic_video_dark.png
new file mode 100644
index 0000000000..76c3e88833
Binary files /dev/null and b/res/drawable-xhdpi/ic_video_dark.png differ
diff --git a/res/drawable-xhdpi/ic_video_light.png b/res/drawable-xhdpi/ic_video_light.png
new file mode 100644
index 0000000000..12c8a6d12a
Binary files /dev/null and b/res/drawable-xhdpi/ic_video_light.png differ
diff --git a/res/drawable-xxhdpi/ic_audio_dark.png b/res/drawable-xxhdpi/ic_audio_dark.png
new file mode 100644
index 0000000000..85f9998417
Binary files /dev/null and b/res/drawable-xxhdpi/ic_audio_dark.png differ
diff --git a/res/drawable-xxhdpi/ic_audio_light.png b/res/drawable-xxhdpi/ic_audio_light.png
new file mode 100644
index 0000000000..d53eef6ff6
Binary files /dev/null and b/res/drawable-xxhdpi/ic_audio_light.png differ
diff --git a/res/drawable-xxhdpi/ic_video_dark.png b/res/drawable-xxhdpi/ic_video_dark.png
new file mode 100644
index 0000000000..b7e9e10faf
Binary files /dev/null and b/res/drawable-xxhdpi/ic_video_dark.png differ
diff --git a/res/drawable-xxhdpi/ic_video_light.png b/res/drawable-xxhdpi/ic_video_light.png
new file mode 100644
index 0000000000..caedec8259
Binary files /dev/null and b/res/drawable-xxhdpi/ic_video_light.png differ
diff --git a/res/drawable/ic_launcher_video_player.png b/res/drawable/ic_launcher_video_player.png
deleted file mode 100644
index 6e231be17f..0000000000
Binary files a/res/drawable/ic_launcher_video_player.png and /dev/null differ
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 349ad60842..d88f3706ba 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -51,6 +51,9 @@
+
+
+
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 96bd3b3055..f73e52a8db 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -94,6 +94,9 @@
- @drawable/ic_forward_white_24dp
- @drawable/ic_save_white_24dp
+ - @drawable/ic_audio_light
+ - @drawable/ic_video_light
+
- #ff1d85d7
- @drawable/ic_push_black
@@ -193,6 +196,9 @@
- @drawable/ic_forward_white_24dp
- @drawable/ic_save_white_24dp
+ - @drawable/ic_audio_dark
+ - @drawable/ic_video_dark
+
- @color/textsecure_primary_dark
- @drawable/ic_push_gray
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index 1aa779e2c4..87525fe6ef 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -394,7 +394,7 @@ public class ConversationItem extends LinearLayout {
public void run() {
for (Slide slide : result.getSlides()) {
if (slide.hasImage()) {
- slide.setThumbnailOn(mmsThumbnail);
+ slide.setThumbnailOn(context, mmsThumbnail);
mmsThumbnail.setOnClickListener(new ThumbnailClickListener(slide));
mmsThumbnail.setVisibility(View.VISIBLE);
return;
diff --git a/src/org/thoughtcrime/securesms/ImageMediaAdapter.java b/src/org/thoughtcrime/securesms/ImageMediaAdapter.java
index c6753b7868..74a7f501f7 100644
--- a/src/org/thoughtcrime/securesms/ImageMediaAdapter.java
+++ b/src/org/thoughtcrime/securesms/ImageMediaAdapter.java
@@ -80,7 +80,7 @@ public class ImageMediaAdapter extends CursorRecyclerViewAdapter {
part.setId(imageRecord.getPartId());
Slide slide = MediaUtil.getSlideForPart(getContext(), masterSecret, part, imageRecord.getContentType());
- if (slide != null) slide.setThumbnailOn(imageView, gridSize, gridSize, new ColorDrawable(0x11ffffff));
+ if (slide != null) slide.setThumbnailOn(getContext(), imageView, gridSize, gridSize, new ColorDrawable(0x11ffffff));
imageView.setOnClickListener(new OnMediaClickListener(imageRecord));
}
diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
index 3beb1f002c..25951162d2 100644
--- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
+++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
@@ -83,7 +83,7 @@ public class AttachmentManager {
@Override
protected Drawable doInBackground(Void... params) {
- return slide.getThumbnail(thumbnailWidth, thumbnailHeight);
+ return slide.getThumbnail(context, thumbnailWidth, thumbnailHeight);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/mms/AudioSlide.java b/src/org/thoughtcrime/securesms/mms/AudioSlide.java
index b32c57f150..e25adf3bcf 100644
--- a/src/org/thoughtcrime/securesms/mms/AudioSlide.java
+++ b/src/org/thoughtcrime/securesms/mms/AudioSlide.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.SmilUtil;
+import org.thoughtcrime.securesms.util.ThemeUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
@@ -28,6 +29,7 @@ import org.w3c.dom.smil.SMILRegionMediaElement;
import ws.com.google.android.mms.pdu.PduPart;
import android.content.Context;
+import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -64,8 +66,8 @@ public class AudioSlide extends Slide {
}
@Override
- public Drawable getThumbnail(int maxWidth, int maxHeight) {
- return context.getResources().getDrawable(R.drawable.ic_menu_add_sound);
+ public Drawable getThumbnail(Context context, int maxWidth, int maxHeight) {
+ return ThemeUtil.resolveIcon(context, R.attr.conversation_icon_attach_audio);
}
public static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException {
diff --git a/src/org/thoughtcrime/securesms/mms/ImageSlide.java b/src/org/thoughtcrime/securesms/mms/ImageSlide.java
index c3cbf6dc61..3533b58c47 100644
--- a/src/org/thoughtcrime/securesms/mms/ImageSlide.java
+++ b/src/org/thoughtcrime/securesms/mms/ImageSlide.java
@@ -70,7 +70,7 @@ public class ImageSlide extends Slide {
}
@Override
- public Drawable getThumbnail(int maxWidth, int maxHeight) {
+ public Drawable getThumbnail(Context context, int maxWidth, int maxHeight) {
Drawable thumbnail = getCachedThumbnail();
if (thumbnail != null) {
@@ -111,12 +111,12 @@ public class ImageSlide extends Slide {
}
@Override
- public void setThumbnailOn(ImageView imageView) {
- setThumbnailOn(imageView, imageView.getWidth(), imageView.getHeight(), new ColorDrawable(Color.TRANSPARENT));
+ public void setThumbnailOn(Context context, ImageView imageView) {
+ setThumbnailOn(context, imageView, imageView.getWidth(), imageView.getHeight(), new ColorDrawable(Color.TRANSPARENT));
}
@Override
- public void setThumbnailOn(ImageView imageView, final int width, final int height, final Drawable placeholder) {
+ public void setThumbnailOn(Context context, ImageView imageView, final int width, final int height, final Drawable placeholder) {
Drawable thumbnail = getCachedThumbnail();
if (thumbnail != null) {
@@ -125,6 +125,7 @@ public class ImageSlide extends Slide {
return;
}
+ final WeakReference weakContext = new WeakReference<>(context);
final WeakReference weakImageView = new WeakReference<>(imageView);
final Handler handler = new Handler();
@@ -136,7 +137,13 @@ public class ImageSlide extends Slide {
MmsDatabase.slideResolver.execute(new Runnable() {
@Override
public void run() {
- final Drawable bitmap = getThumbnail(width, height);
+ final Context context = weakContext.get();
+ if (context == null) {
+ Log.w(TAG, "context SoftReference was null, leaving");
+ return;
+ }
+
+ final Drawable bitmap = getThumbnail(context, width, height);
final ImageView destination = weakImageView.get();
Log.w(TAG, "slide resolved, destination available? " + (destination == null));
diff --git a/src/org/thoughtcrime/securesms/mms/Slide.java b/src/org/thoughtcrime/securesms/mms/Slide.java
index 0c9008243b..4a1fd2076b 100644
--- a/src/org/thoughtcrime/securesms/mms/Slide.java
+++ b/src/org/thoughtcrime/securesms/mms/Slide.java
@@ -30,6 +30,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
+import android.util.TypedValue;
import android.widget.ImageView;
import ws.com.google.android.mms.pdu.PduPart;
@@ -70,16 +71,16 @@ public abstract class Slide {
return part.getDataUri();
}
- public Drawable getThumbnail(int maxWidth, int maxHeight) {
+ public Drawable getThumbnail(Context context, int maxWidth, int maxHeight) {
throw new AssertionError("getThumbnail() called on non-thumbnail producing slide!");
}
- public void setThumbnailOn(ImageView imageView) {
- imageView.setImageDrawable(getThumbnail(imageView.getWidth(), imageView.getHeight()));
+ public void setThumbnailOn(Context context, ImageView imageView) {
+ imageView.setImageDrawable(getThumbnail(context, imageView.getWidth(), imageView.getHeight()));
}
- public void setThumbnailOn(ImageView imageView, int height, int width, Drawable placeholder) {
- imageView.setImageDrawable(getThumbnail(width, height));
+ public void setThumbnailOn(Context context, ImageView imageView, int height, int width, Drawable placeholder) {
+ imageView.setImageDrawable(getThumbnail(context, width, height));
}
public Bitmap getGeneratedThumbnail() { return null; }
diff --git a/src/org/thoughtcrime/securesms/mms/VideoSlide.java b/src/org/thoughtcrime/securesms/mms/VideoSlide.java
index c383257358..fd19f9493f 100644
--- a/src/org/thoughtcrime/securesms/mms/VideoSlide.java
+++ b/src/org/thoughtcrime/securesms/mms/VideoSlide.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.SmilUtil;
+import org.thoughtcrime.securesms.util.ThemeUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
@@ -28,6 +29,7 @@ import org.w3c.dom.smil.SMILRegionElement;
import ws.com.google.android.mms.pdu.PduPart;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -45,8 +47,8 @@ public class VideoSlide extends Slide {
}
@Override
- public Drawable getThumbnail(int width, int height) {
- return context.getResources().getDrawable(R.drawable.ic_launcher_video_player);
+ public Drawable getThumbnail(Context context, int width, int height) {
+ return ThemeUtil.resolveIcon(context, R.attr.conversation_icon_attach_video);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/util/ThemeUtil.java b/src/org/thoughtcrime/securesms/util/ThemeUtil.java
new file mode 100644
index 0000000000..d48621916c
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/util/ThemeUtil.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2015 Open Whisper Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.thoughtcrime.securesms.util;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+
+public class ThemeUtil {
+ public static Drawable resolveIcon(Context c, int iconAttr)
+ {
+ TypedValue out = new TypedValue();
+ c.getTheme().resolveAttribute(iconAttr, out, true);
+ return c.getResources().getDrawable(out.resourceId);
+ }
+}