diff --git a/briar-android/res/layout/fragment_forum_list.xml b/briar-android/res/layout/fragment_forum_list.xml index d078aebb2b4214f905dccb0277747176275721e7..ca4fb452052bd7180b1b4c9dc4e9f63a454e97de 100644 --- a/briar-android/res/layout/fragment_forum_list.xml +++ b/briar-android/res/layout/fragment_forum_list.xml @@ -10,6 +10,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_behavior="org.briarproject.android.util.BriarRecyclerViewBehavior"/> + app:layout_behavior="org.briarproject.android.view.BriarRecyclerViewBehavior"/> </android.support.design.widget.CoordinatorLayout> diff --git a/briar-android/src/org/thoughtcrime/securesms/components/KeyboardAwareRelativeLayout.java b/briar-android/src/org/thoughtcrime/securesms/components/KeyboardAwareRelativeLayout.java index f762d1cb69de71774b401d28b80b8cf9a0b13ec3..5217078252324fab5d8e0ce730cbfca0e5ec25f3 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/KeyboardAwareRelativeLayout.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/KeyboardAwareRelativeLayout.java @@ -1,33 +1,14 @@ -/** - * Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. - */ package org.thoughtcrime.securesms.components; import android.annotation.TargetApi; -import android.app.Activity; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Rect; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.widget.RelativeLayout; @@ -37,15 +18,23 @@ import org.briarproject.R; import java.lang.reflect.Field; import java.util.HashSet; import java.util.Set; +import java.util.logging.Logger; + +import static android.content.Context.WINDOW_SERVICE; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; /** - * RelativeLayout that, when a view container, will report back when it thinks a soft keyboard - * has been opened and what its height would be. + * RelativeLayout that, when a view container, will report back when it thinks + * a soft keyboard has been opened and what its height would be. */ @UiThread public class KeyboardAwareRelativeLayout extends RelativeLayout { - private static final String TAG = - KeyboardAwareRelativeLayout.class.getSimpleName(); + + private static final Logger LOG = + Logger.getLogger(KeyboardAwareRelativeLayout.class.getName()); private final Rect rect = new Rect(); private final Set<OnKeyboardHiddenListener> hiddenListeners = @@ -100,7 +89,7 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { int oldRotation = rotation; rotation = getDeviceRotation(); if (oldRotation != rotation) { - Log.w(TAG, "rotation changed"); + LOG.info("Rotation changed"); onKeyboardClose(); } } @@ -111,13 +100,13 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { return; } - if (viewInset == 0 && Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) + if (viewInset == 0 && Build.VERSION.SDK_INT >= 21) viewInset = getViewInset(); - final int availableHeight = - this.getRootView().getHeight() - statusBarHeight - viewInset; + int availableHeight = + getRootView().getHeight() - statusBarHeight - viewInset; getWindowVisibleDisplayFrame(rect); - final int keyboardHeight = availableHeight - (rect.bottom - rect.top); + int keyboardHeight = availableHeight - (rect.bottom - rect.top); if (keyboardHeight > minKeyboardSize) { if (getKeyboardHeight() != keyboardHeight) @@ -128,7 +117,7 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { } } - @TargetApi(VERSION_CODES.LOLLIPOP) + @TargetApi(21) private int getViewInset() { try { Field attachInfoField = View.class.getDeclaredField("mAttachInfo"); @@ -141,25 +130,26 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { Rect insets = (Rect) stableInsetsField.get(attachInfo); return insets.bottom; } - } catch (NoSuchFieldException nsfe) { - Log.w(TAG, "field reflection error when measuring view inset", - nsfe); - } catch (IllegalAccessException iae) { - Log.w(TAG, "access reflection error when measuring view inset", - iae); + } catch (NoSuchFieldException e) { + LOG.log(WARNING, + "field reflection error when measuring view inset", e); + } catch (IllegalAccessException e) { + LOG.log(WARNING, + "access reflection error when measuring view inset", e); } return 0; } protected void onKeyboardOpen(int keyboardHeight) { - Log.w(TAG, "onKeyboardOpen(" + keyboardHeight + ")"); + if (LOG.isLoggable(INFO)) + LOG.info("onKeyboardOpen(" + keyboardHeight + ")"); keyboardOpen = true; notifyShownListeners(); } protected void onKeyboardClose() { - Log.w(TAG, "onKeyboardClose()"); + LOG.info("onKeyboardClose()"); keyboardOpen = false; notifyHiddenListeners(); } @@ -175,13 +165,12 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { public boolean isLandscape() { int rotation = getDeviceRotation(); - return rotation == Surface.ROTATION_90 || - rotation == Surface.ROTATION_270; + return rotation == ROTATION_90 || rotation == ROTATION_270; } private int getDeviceRotation() { - WindowManager windowManager = (WindowManager) getContext() - .getSystemService(Activity.WINDOW_SERVICE); + WindowManager windowManager = + (WindowManager) getContext().getSystemService(WINDOW_SERVICE); return windowManager.getDefaultDisplay().getRotation(); } @@ -190,10 +179,10 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { } private int getKeyboardPortraitHeight() { - int keyboardHeight = - PreferenceManager.getDefaultSharedPreferences(getContext()) - .getInt("keyboard_height_portrait", - defaultCustomKeyboardSize); + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(getContext()); + int keyboardHeight = prefs.getInt("keyboard_height_portrait", + defaultCustomKeyboardSize); return clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMargin); } @@ -203,8 +192,9 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { } private void setKeyboardPortraitHeight(int height) { - PreferenceManager.getDefaultSharedPreferences(getContext()) - .edit().putInt("keyboard_height_portrait", height).apply(); + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(getContext()); + prefs.edit().putInt("keyboard_height_portrait", height).apply(); } public void postOnKeyboardClose(final Runnable runnable) { @@ -254,7 +244,8 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { } private void notifyHiddenListeners() { - final Set<OnKeyboardHiddenListener> listeners = + // Make a copy as listeners may remove themselves when called + Set<OnKeyboardHiddenListener> listeners = new HashSet<>(hiddenListeners); for (OnKeyboardHiddenListener listener : listeners) { listener.onKeyboardHidden(); @@ -262,8 +253,8 @@ public class KeyboardAwareRelativeLayout extends RelativeLayout { } private void notifyShownListeners() { - final Set<OnKeyboardShownListener> listeners = - new HashSet<>(shownListeners); + // Make a copy as listeners may remove themselves when called + Set<OnKeyboardShownListener> listeners = new HashSet<>(shownListeners); for (OnKeyboardShownListener listener : listeners) { listener.onKeyboardShown(); } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/RepeatableImageKey.java b/briar-android/src/org/thoughtcrime/securesms/components/RepeatableImageKey.java index f1802bd348c7c292f77111dcd0b54b2edda38d24..453f82f8cf0d79feeca1b74fd27625f30c74ac4c 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/RepeatableImageKey.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/RepeatableImageKey.java @@ -1,16 +1,18 @@ package org.thoughtcrime.securesms.components; import android.content.Context; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.support.annotation.UiThread; import android.util.AttributeSet; -import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.ImageButton; +import static android.view.HapticFeedbackConstants.KEYBOARD_TAP; +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_UP; + @UiThread public class RepeatableImageKey extends ImageButton { @@ -42,7 +44,7 @@ public class RepeatableImageKey extends ImageButton { } private void notifyListener() { - if (this.listener != null) this.listener.onKeyEvent(); + if (listener != null) listener.onKeyEvent(); } private class RepeaterClickListener implements OnClickListener { @@ -56,31 +58,28 @@ public class RepeatableImageKey extends ImageButton { @Override public void run() { notifyListener(); - postDelayed(this, VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1 - ? ViewConfiguration.getKeyRepeatDelay() - : 50); + postDelayed(this, ViewConfiguration.getKeyRepeatDelay()); } } private class RepeaterTouchListener implements OnTouchListener { - private Repeater repeater; + + private final Repeater repeater; private RepeaterTouchListener() { - this.repeater = new Repeater(); + repeater = new Repeater(); } @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { - case MotionEvent.ACTION_DOWN: + case ACTION_DOWN: view.postDelayed(repeater, - VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1 - ? ViewConfiguration.getKeyRepeatTimeout() - : ViewConfiguration.getLongPressTimeout()); - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + ViewConfiguration.getKeyRepeatTimeout()); + performHapticFeedback(KEYBOARD_TAP); return false; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: + case ACTION_CANCEL: + case ACTION_UP: view.removeCallbacks(repeater); return false; default: diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java index 7f06aff49bdd7e783b9792e9177dab2c632d3ed5..28a71933f274d115dbf4e438a4db2c79ffcc257f 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java @@ -6,8 +6,9 @@ import android.support.annotation.UiThread; import android.text.style.ImageSpan; @UiThread -public class AnimatingImageSpan extends ImageSpan { - public AnimatingImageSpan(Drawable drawable, Callback callback) { +class AnimatingImageSpan extends ImageSpan { + + AnimatingImageSpan(Drawable drawable, Callback callback) { super(drawable, ALIGN_BOTTOM); drawable.setCallback(callback); } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java index 2b78041d0f79ef073ce218a07b4bef0b0219ee5b..69234600f6b1c5e70799b4cf7b30edf0bc98d791 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java @@ -12,7 +12,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import com.astuetz.PagerSlidingTabStrip; @@ -27,15 +26,18 @@ import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; +import static android.view.KeyEvent.ACTION_DOWN; +import static android.view.KeyEvent.KEYCODE_DEL; +import static android.widget.ImageView.ScaleType.CENTER_INSIDE; import static java.util.logging.Level.INFO; @UiThread public class EmojiDrawer extends LinearLayout { - private static final String TAG = EmojiDrawer.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); + private static final Logger LOG = + Logger.getLogger(EmojiDrawer.class.getName()); private static final KeyEvent DELETE_KEY_EVENT = - new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); + new KeyEvent(ACTION_DOWN, KEYCODE_DEL); private ViewPager pager; private List<EmojiPageModel> models; @@ -70,7 +72,6 @@ public class EmojiDrawer extends LinearLayout { } private void initializeResources(View v) { - LOG.info("initializeResources()"); this.pager = (ViewPager) v.findViewById(R.id.emoji_pager); this.strip = (PagerSlidingTabStrip) v.findViewById(R.id.tabs); @@ -93,7 +94,7 @@ public class EmojiDrawer extends LinearLayout { ViewGroup.LayoutParams params = getLayoutParams(); params.height = height; if (LOG.isLoggable(INFO)) - LOG.info("showing emoji drawer with height " + params.height); + LOG.info("Showing emoji drawer with height " + params.height); setLayoutParams(params); setVisibility(VISIBLE); if (drawerListener != null) drawerListener.onShown(); @@ -102,7 +103,6 @@ public class EmojiDrawer extends LinearLayout { public void hide() { setVisibility(GONE); if (drawerListener != null) drawerListener.onHidden(); - LOG.info("hide()"); } private void initializeEmojiGrid() { @@ -111,7 +111,6 @@ public class EmojiDrawer extends LinearLayout { new EmojiSelectionListener() { @Override public void onEmojiSelected(String emoji) { - LOG.info("onEmojiSelected()"); recentModel.onCodePointSelected(emoji); if (listener != null) listener.onEmojiSelected(emoji); } @@ -174,7 +173,7 @@ public class EmojiDrawer extends LinearLayout { @Override public View getCustomTabView(ViewGroup viewGroup, int i) { ImageView image = new ImageView(context); - image.setScaleType(ScaleType.CENTER_INSIDE); + image.setScaleType(CENTER_INSIDE); image.setImageResource(pages.get(i).getIcon()); return image; } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java index 6e9b751cffd514216b95e1540c8f5d761c3152cd..603544869f954448a22f35059f34b61198853e17 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java @@ -9,7 +9,7 @@ import android.text.TextUtils; import android.widget.TextView; @UiThread -public class EmojiFilter implements InputFilter { +class EmojiFilter implements InputFilter { private final TextView view; diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java index 3b3861b1926c026e00d2687b0ee667305c7697ae..2e0b899d54fddb7cb928a081515a018d482469e5 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java @@ -4,7 +4,8 @@ import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -public interface EmojiPageModel { +interface EmojiPageModel { + @DrawableRes int getIcon(); diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java index d101a9daa18e5642c18715415b4c1f1bce9d9797..fa5e97c8eef6983e1fda830c524c5eb2ee3345ae 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java @@ -20,6 +20,7 @@ import org.briarproject.R; public class EmojiPageView extends FrameLayout { private final GridView grid; + private EmojiSelectionListener listener; public EmojiPageView(Context context) { @@ -60,15 +61,15 @@ public class EmojiPageView extends FrameLayout { private static class EmojiGridAdapter extends BaseAdapter { - protected final Context context; - private final int emojiSize; + private final Context context; private final EmojiPageModel model; + private final int emojiSize; private EmojiGridAdapter(Context context, EmojiPageModel model) { this.context = context; - this.emojiSize = (int) context.getResources() - .getDimension(R.dimen.emoji_drawer_size); this.model = model; + emojiSize = (int) context.getResources() + .getDimension(R.dimen.emoji_drawer_size); } @Override @@ -88,15 +89,14 @@ public class EmojiPageView extends FrameLayout { } @Override - public View getView(final int position, final View convertView, - final ViewGroup parent) { - final EmojiView view; - final int pad = context.getResources() + public View getView(int position, View convertView, ViewGroup parent) { + EmojiView view; + int pad = context.getResources() .getDimensionPixelSize(R.dimen.emoji_drawer_item_padding); if (convertView != null && convertView instanceof EmojiView) { view = (EmojiView) convertView; } else { - final EmojiView emojiView = new EmojiView(context); + EmojiView emojiView = new EmojiView(context); emojiView.setPadding(pad, pad, pad, pad); emojiView.setLayoutParams( new AbsListView.LayoutParams(emojiSize + 2 * pad, @@ -109,7 +109,7 @@ public class EmojiPageView extends FrameLayout { } } - public interface EmojiSelectionListener { + interface EmojiSelectionListener { void onEmojiSelected(String emoji); } } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java index 9ad5f429b5b203b889179ff06d3e421d5d1dfd3a..0544de13af91fd1374ce81b5e0033bb151b4115f 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java @@ -8,12 +8,14 @@ import java.util.Arrays; import java.util.List; class EmojiPages { + static List<EmojiPageModel> getPages(Context ctx) { return Arrays.<EmojiPageModel>asList( new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_smiley_people, R.array.emoji_smiley_people, "emoji_smiley_people.png"), - new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_animals_nature, + new StaticEmojiPageModel(ctx, + R.drawable.ic_emoji_animals_nature, R.array.emoji_animals_nature, "emoji_animals_nature.png"), new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_food_drink, diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java index f53a087d00cf74656162a04623469a82c5e4cc59..2ea99864e9755732f8555d27c481f06fc3436afb 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java @@ -5,7 +5,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.AsyncTask; @@ -34,25 +33,30 @@ import java.util.regex.Pattern; import javax.inject.Inject; +import static android.graphics.PixelFormat.TRANSLUCENT; +import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; public class EmojiProvider { - private static final String TAG = EmojiProvider.class.getSimpleName(); - private static volatile EmojiProvider instance = null; - private static final Paint paint = + + private static volatile EmojiProvider INSTANCE = null; + + private static final Paint PAINT = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); @Inject AndroidExecutor androidExecutor; - private static final Logger LOG = Logger.getLogger(TAG); + private static final Logger LOG = + Logger.getLogger(EmojiProvider.class.getName()); private final SparseArray<DrawInfo> offsets = new SparseArray<>(); private static final Pattern EMOJI_RANGE = Pattern.compile( - // 0x203c,0x2049 0x20a0-0x32ff 0x1f00-0x1fff 0xfe4e5-0xfe4ee - // |=== !!, ?! ===||==== misc ===||========= emoticons =======||========== flags ==========| - "[\\u203c\\u2049\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83f\\udfff\\udbb9\\udce5-\\udbb9\\udcee]"); + // 0x203c,0x2049 0x20a0-0x32ff 0x1f00-0x1fff 0xfe4e5-0xfe4ee + // |=== !!, ?! ===||==== misc ===||========= emoticons =======||========== flags ==========| + "[\\u203c\\u2049\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83f\\udfff\\udbb9\\udce5-\\udbb9\\udcee]"); private static final int EMOJI_RAW_HEIGHT = 64; private static final int EMOJI_RAW_WIDTH = 64; @@ -60,30 +64,29 @@ public class EmojiProvider { private static final int EMOJI_PER_ROW = 32; private final Context context; - private final float decodeScale; - private final float verticalPad; + private final float decodeScale, verticalPad; private final List<EmojiPageModel> staticPages; - public static EmojiProvider getInstance(Context context) { - if (instance == null) { + static EmojiProvider getInstance(Context context) { + if (INSTANCE == null) { synchronized (EmojiProvider.class) { - if (instance == null) { + if (INSTANCE == null) { LOG.info("Creating new instance of EmojiProvider"); - instance = new EmojiProvider(context); + INSTANCE = new EmojiProvider(context); ((BaseActivity) context).getActivityComponent() - .inject(instance); + .inject(INSTANCE); } } } - return instance; + return INSTANCE; } private EmojiProvider(Context context) { this.context = context.getApplicationContext(); - this.decodeScale = Math.min(1f, - context.getResources().getDimension(R.dimen.emoji_drawer_size) / - EMOJI_RAW_HEIGHT); - this.verticalPad = EMOJI_VERT_PAD * this.decodeScale; + float drawerSize = + context.getResources().getDimension(R.dimen.emoji_drawer_size); + decodeScale = Math.min(1f, drawerSize / EMOJI_RAW_HEIGHT); + verticalPad = EMOJI_VERT_PAD * this.decodeScale; staticPages = EmojiPages.getPages(context); for (EmojiPageModel page : staticPages) { if (page.hasSpriteMap()) { @@ -97,7 +100,8 @@ public class EmojiProvider { } @Nullable - public Spannable emojify(@Nullable CharSequence text, @NonNull TextView tv) { + Spannable emojify(@Nullable CharSequence text, + @NonNull TextView tv) { if (text == null) return null; Matcher matches = EMOJI_RANGE.matcher(text); SpannableStringBuilder builder = new SpannableStringBuilder(text); @@ -107,15 +111,14 @@ public class EmojiProvider { Drawable drawable = getEmojiDrawable(codePoint); if (drawable != null) { builder.setSpan(new EmojiSpan(drawable, tv), matches.start(), - matches.end(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + matches.end(), SPAN_EXCLUSIVE_EXCLUSIVE); } } return builder; } @Nullable - public Drawable getEmojiDrawable(int emojiCode) { + Drawable getEmojiDrawable(int emojiCode) { return getEmojiDrawable(offsets.get(emojiCode)); } @@ -139,22 +142,30 @@ public class EmojiProvider { @Override public void onFailure(Throwable error) { - LOG.log(WARNING, error.toString(), error); + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, error.toString(), error); } }); return drawable; } - public List<EmojiPageModel> getStaticPages() { + List<EmojiPageModel> getStaticPages() { return staticPages; } - public class EmojiDrawable extends Drawable { + class EmojiDrawable extends Drawable { + private final DrawInfo info; + private final float intrinsicWidth, intrinsicHeight; + private Bitmap bmp; - private float intrinsicWidth; - private float intrinsicHeight; + + private EmojiDrawable(DrawInfo info, float decodeScale) { + this.info = info; + intrinsicWidth = EMOJI_RAW_WIDTH * decodeScale; + intrinsicHeight = EMOJI_RAW_HEIGHT * decodeScale; + } @Override public int getIntrinsicWidth() { @@ -166,32 +177,25 @@ public class EmojiProvider { return (int) intrinsicHeight; } - private EmojiDrawable(DrawInfo info, float decodeScale) { - this.info = info; - this.intrinsicWidth = EMOJI_RAW_WIDTH * decodeScale; - this.intrinsicHeight = EMOJI_RAW_HEIGHT * decodeScale; - } - @Override public void draw(@NonNull Canvas canvas) { if (bmp == null) { return; } - final int row = info.index / EMOJI_PER_ROW; - final int row_index = info.index % EMOJI_PER_ROW; - - canvas.drawBitmap(bmp, - new Rect((int) (row_index * intrinsicWidth), - (int) (row * intrinsicHeight + row * verticalPad), - (int) ((row_index + 1) * intrinsicWidth), - (int) ((row + 1) * intrinsicHeight + - row * verticalPad)), - getBounds(), - paint); + int row = info.index / EMOJI_PER_ROW; + int rowIndex = info.index % EMOJI_PER_ROW; + + int left = (int) (rowIndex * intrinsicWidth); + int top = (int) (row * intrinsicHeight + row * verticalPad); + int right = (int) ((rowIndex + 1) * intrinsicWidth); + int bottom = + (int) ((row + 1) * intrinsicHeight + row * verticalPad); + canvas.drawBitmap(bmp, new Rect(left, top, right, bottom), + getBounds(), PAINT); } - public void setBitmap(Bitmap bitmap) { + void setBitmap(Bitmap bitmap) { if (bmp == null || !bmp.sameAs(bitmap)) { bmp = bitmap; invalidateSelf(); @@ -200,7 +204,7 @@ public class EmojiProvider { @Override public int getOpacity() { - return PixelFormat.TRANSLUCENT; + return TRANSLUCENT; } @Override @@ -214,26 +218,29 @@ public class EmojiProvider { private static class DrawInfo { - private EmojiPageBitmap page; - int index; - private DrawInfo(final EmojiPageBitmap page, final int index) { + private final EmojiPageBitmap page; + private final int index; + + private DrawInfo(EmojiPageBitmap page, int index) { this.page = page; this.index = index; } @Override public String toString() { - return "DrawInfo{ " +"page = " + page +", index = " + index + '}'; + return "DrawInfo{ " + "page = " + page + ", index = " + index + '}'; } } - private class EmojiPageBitmap { - private EmojiPageModel model; - private SoftReference<Bitmap> bitmapReference; + + private final EmojiPageModel model; + private ListenableFutureTask<Bitmap> task; + private volatile SoftReference<Bitmap> bitmapReference; + private EmojiPageBitmap(EmojiPageModel model) { this.model = model; } @@ -249,7 +256,8 @@ public class EmojiProvider { @Nullable public Bitmap call() throws Exception { try { - LOG.info("loading page " + model.getSprite()); + if (LOG.isLoggable(INFO)) + LOG.info("Loading page " + model.getSprite()); return loadPage(); } catch (IOException ioe) { LOG.log(WARNING, ioe.toString(), ioe); @@ -283,7 +291,8 @@ public class EmojiProvider { "file:///android_asset/" + model.getSprite(), decodeScale); bitmapReference = new SoftReference<>(bitmap); - LOG.info("onPageLoaded(" + model.getSprite() + ")"); + if (LOG.isLoggable(INFO)) + LOG.info("Loaded page " + model.getSprite()); return bitmap; } catch (BitmapDecodingException e) { LOG.log(WARNING, e.toString(), e); diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java index 47269d09549ea78bd0e777e15cca15fdd478a533..6168ee2733501703687499453ff3f0725a8679ff 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java @@ -10,11 +10,12 @@ import android.widget.TextView; import org.briarproject.R; @UiThread -public class EmojiSpan extends AnimatingImageSpan { +class EmojiSpan extends AnimatingImageSpan { + private final int size; private final FontMetricsInt fm; - public EmojiSpan(@NonNull Drawable drawable, @NonNull TextView tv) { + EmojiSpan(@NonNull Drawable drawable, @NonNull TextView tv) { super(drawable, tv); fm = tv.getPaint().getFontMetricsInt(); size = fm != null ? Math.abs(fm.descent) + Math.abs(fm.ascent) diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java index df354c193823d39dc5ed1352b3215e82def6d440..7d10a6393df448b2655151033c635c8e277a7f39 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -7,12 +7,16 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.text.TextUtils; -import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.widget.TextView; import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; +import static android.text.TextUtils.TruncateAt.END; +import static android.view.View.MeasureSpec.AT_MOST; +import static android.view.View.MeasureSpec.EXACTLY; +import static android.widget.TextView.BufferType.SPANNABLE; + @UiThread public class EmojiTextView extends TextView { @@ -41,9 +45,7 @@ public class EmojiTextView extends TextView { } private void setTextEllipsized(final @Nullable CharSequence source) { - super.setText( - needsEllipsizing ? ellipsize(source) : source, - BufferType.SPANNABLE); + super.setText(needsEllipsizing ? ellipsize(source) : source, SPANNABLE); } @Override @@ -56,18 +58,16 @@ public class EmojiTextView extends TextView { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int size = MeasureSpec.getSize(widthMeasureSpec); final int mode = MeasureSpec.getMode(widthMeasureSpec); - if (getEllipsize() == TruncateAt.END && + if (getEllipsize() == END && !TextUtils.isEmpty(source) && - (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) && + (mode == AT_MOST || mode == EXACTLY) && getPaint().breakText(source, 0, source.length() - 1, true, size, null) != source.length()) { needsEllipsizing = true; FontMetricsInt font = getPaint().getFontMetricsInt(); - super.onMeasure( - MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), - MeasureSpec - .makeMeasureSpec(Math.abs(font.top - font.bottom), - MeasureSpec.EXACTLY)); + int height = Math.abs(font.top - font.bottom); + super.onMeasure(MeasureSpec.makeMeasureSpec(size, EXACTLY), + MeasureSpec.makeMeasureSpec(height, EXACTLY)); } else { needsEllipsizing = false; super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -84,13 +84,11 @@ public class EmojiTextView extends TextView { @Nullable public CharSequence ellipsize(@Nullable CharSequence text) { if (TextUtils.isEmpty(text) || getWidth() == 0 || - getEllipsize() != TruncateAt.END) { + getEllipsize() != END) { return text; } else { - return TextUtils.ellipsize(text, - getPaint(), - getWidth() - getPaddingRight() - getPaddingLeft(), - TruncateAt.END); + return TextUtils.ellipsize(text, getPaint(), + getWidth() - getPaddingRight() - getPaddingLeft(), END); } } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java index 1126f034a09ad1aaaf142e06467bf86aa0907994..c4f064d2ad9e5e2300d7730323ceb80934d30202 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java @@ -13,14 +13,18 @@ import android.view.View; import org.briarproject.R; +import static android.graphics.Paint.ANTI_ALIAS_FLAG; +import static android.graphics.Paint.Align.CENTER; +import static android.graphics.Paint.FILTER_BITMAP_FLAG; + @UiThread public class EmojiView extends View implements Drawable.Callback { + + private final Paint paint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); + private String emoji; private Drawable drawable; - private final Paint paint = - new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - public EmojiView(Context context) { this(context, null); } @@ -60,7 +64,7 @@ public class EmojiView extends View implements Drawable.Callback { paint.setTextSize(targetFontSize); paint.setColor(ContextCompat .getColor(getContext(), R.color.emoji_text_color)); - paint.setTextAlign(Paint.Align.CENTER); + paint.setTextAlign(CENTER); int xPos = (canvas.getWidth() / 2); int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2)); @@ -81,9 +85,4 @@ public class EmojiView extends View implements Drawable.Callback { super.invalidateDrawable(drawable); postInvalidate(); } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java index 312d8372919ca38b89ff0c98d4faeeb81f9fe6ab..1c16d9c87732d8b3c1101f375bcba91fdab2d287 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java @@ -20,16 +20,14 @@ import java.util.logging.Logger; import javax.inject.Inject; -import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.android.fragment.SettingsFragment.SETTINGS_NAMESPACE; @UiThread public class RecentEmojiPageModel implements EmojiPageModel { - private static final String TAG = - RecentEmojiPageModel.class.getSimpleName(); - private static final Logger LOG = Logger.getLogger(TAG); + private static final Logger LOG = + Logger.getLogger(RecentEmojiPageModel.class.getName()); private static final String EMOJI_LRU_PREFERENCE = "pref_emoji_recent"; private static final int EMOJI_LRU_SIZE = 50; @@ -38,11 +36,11 @@ public class RecentEmojiPageModel implements EmojiPageModel { private Settings settings; @Inject - protected SettingsManager settingsManager; + SettingsManager settingsManager; @Inject - protected DbController dbController; + DbController dbController; - public RecentEmojiPageModel(Context context) { + RecentEmojiPageModel(Context context) { if (!(context instanceof BaseActivity)) { throw new IllegalArgumentException( "Needs to be created from BaseActivity"); @@ -85,9 +83,7 @@ public class RecentEmojiPageModel implements EmojiPageModel { return null; } - public void onCodePointSelected(String emoji) { - if (LOG.isLoggable(INFO)) - LOG.info("onCodePointSelected(" + emoji + ")"); + void onCodePointSelected(String emoji) { recentlyUsed.remove(emoji); recentlyUsed.add(emoji); @@ -105,7 +101,7 @@ public class RecentEmojiPageModel implements EmojiPageModel { result += emoji + ";"; } if (!emojis.isEmpty()) - result = result.substring(0, result.length()-1); + result = result.substring(0, result.length() - 1); return result; } diff --git a/briar-android/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java b/briar-android/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java index 7c359c8315b66002d46a997f067fc3109215a87d..688ee3ae7a4f778c4c79bd30e3b8616679252082 100644 --- a/briar-android/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java +++ b/briar-android/src/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java @@ -8,7 +8,7 @@ import android.support.annotation.Nullable; import android.support.annotation.UiThread; @UiThread -public class StaticEmojiPageModel implements EmojiPageModel { +class StaticEmojiPageModel implements EmojiPageModel { @DrawableRes private final int icon; @@ -17,14 +17,14 @@ public class StaticEmojiPageModel implements EmojiPageModel { @Nullable private final String sprite; - public StaticEmojiPageModel(@DrawableRes int icon, @NonNull String[] emoji, + StaticEmojiPageModel(@DrawableRes int icon, @NonNull String[] emoji, @Nullable String sprite) { this.icon = icon; this.emoji = emoji; this.sprite = sprite; } - public StaticEmojiPageModel(Context ctx, @DrawableRes int icon, + StaticEmojiPageModel(Context ctx, @DrawableRes int icon, @ArrayRes int res, @Nullable String sprite) { this(icon, getEmoji(ctx, res), sprite); } @@ -35,6 +35,7 @@ public class StaticEmojiPageModel implements EmojiPageModel { return icon; } + @Override @NonNull public String[] getEmoji() { return emoji; diff --git a/briar-android/src/org/thoughtcrime/securesms/util/BitmapDecodingException.java b/briar-android/src/org/thoughtcrime/securesms/util/BitmapDecodingException.java index 5a4b414623e57dd75ab0f9610d243dcca799ca32..777fdfb2ead9fe8cc8c140432cbc35ff522281c4 100644 --- a/briar-android/src/org/thoughtcrime/securesms/util/BitmapDecodingException.java +++ b/briar-android/src/org/thoughtcrime/securesms/util/BitmapDecodingException.java @@ -2,11 +2,11 @@ package org.thoughtcrime.securesms.util; public class BitmapDecodingException extends Exception { - public BitmapDecodingException(String s) { + BitmapDecodingException(String s) { super(s); } - public BitmapDecodingException(Exception nested) { + BitmapDecodingException(Exception nested) { super(nested); } } diff --git a/briar-android/src/org/thoughtcrime/securesms/util/BitmapUtil.java b/briar-android/src/org/thoughtcrime/securesms/util/BitmapUtil.java index 92a8425fc8e82bfcdf7199d5406c39cff84c9237..0bc0ed00f95d93721f923863bc475303fb086f01 100644 --- a/briar-android/src/org/thoughtcrime/securesms/util/BitmapUtil.java +++ b/briar-android/src/org/thoughtcrime/securesms/util/BitmapUtil.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.util; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.util.Log; import android.util.Pair; import com.bumptech.glide.Glide; @@ -17,10 +16,14 @@ import com.bumptech.glide.load.resource.bitmap.FitCenter; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.logging.Logger; + +import static java.util.logging.Level.WARNING; public class BitmapUtil { - private static final String TAG = BitmapUtil.class.getSimpleName(); + private static final Logger LOG = + Logger.getLogger(BitmapUtil.class.getName()); private static <T> InputStream getInputStreamForModel(Context context, T model) @@ -40,8 +43,7 @@ public class BitmapUtil { final Bitmap rough = Downsampler.AT_LEAST .decode(getInputStreamForModel(context, model), Glide.get(context).getBitmapPool(), - width, height, - DecodeFormat.PREFER_RGB_565); + width, height, DecodeFormat.PREFER_RGB_565); final Resource<Bitmap> resource = BitmapResource .obtain(rough, Glide.get(context).getBitmapPool()); @@ -55,8 +57,7 @@ public class BitmapUtil { } public static <T> Bitmap createScaledBitmap(Context context, T model, - float scale) - throws BitmapDecodingException { + float scale) throws BitmapDecodingException { Pair<Integer, Integer> dimens = getDimensions(getInputStreamForModel(context, model)); return createScaledBitmapInto(context, model, @@ -72,9 +73,8 @@ public class BitmapUtil { BitmapFactory.decodeStream(fis, null, options); try { fis.close(); - } catch (IOException ioe) { - Log.w(TAG, - "failed to close the InputStream after reading image dimensions"); + } catch (IOException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } if (options.outWidth == -1 || options.outHeight == -1) { diff --git a/briar-android/test/java/org/briarproject/android/forum/ForumActivityTest.java b/briar-android/test/java/org/briarproject/android/forum/ForumActivityTest.java index 38f64c5b25241af34913ec05aa92559f324a3add..e61b557beb392dbfedac9dd9620f0fd5ade0417b 100644 --- a/briar-android/test/java/org/briarproject/android/forum/ForumActivityTest.java +++ b/briar-android/test/java/org/briarproject/android/forum/ForumActivityTest.java @@ -29,6 +29,8 @@ import java.util.List; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; +import static org.briarproject.api.identity.Author.Status.UNKNOWN; +import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -77,11 +79,12 @@ public class ForumActivityTest { private List<ForumEntry> getDummyData() { ForumEntry[] forumEntries = new ForumEntry[6]; for (int i = 0; i < forumEntries.length; i++) { - forumEntries[i] = - new ForumEntry(new MessageId(TestUtils.getRandomId()), - AUTHORS[i], LEVELS[i], System.currentTimeMillis(), - AUTHORS[i], new AuthorId(TestUtils.getRandomId()), - Author.Status.UNKNOWN); + AuthorId authorId = new AuthorId(TestUtils.getRandomId()); + byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + Author author = new Author(authorId, AUTHORS[i], publicKey); + forumEntries[i] = new ForumEntry( + new MessageId(TestUtils.getRandomId()), AUTHORS[i], + LEVELS[i], System.currentTimeMillis(), author, UNKNOWN); } return new ArrayList<>(Arrays.asList(forumEntries)); }