add sane default emoji panel size

fixes #3661
Closes #3691
// FREEBIE
This commit is contained in:
Jake McGinty 2015-07-17 12:50:00 -07:00 committed by Moxie Marlinspike
parent cfc9514f89
commit 39c0fc0e5a
6 changed files with 60 additions and 177 deletions

View File

@ -2,8 +2,9 @@
<resources> <resources>
<dimen name="emoji_drawer_size">32sp</dimen> <dimen name="emoji_drawer_size">32sp</dimen>
<dimen name="min_keyboard_size">50dp</dimen> <dimen name="min_keyboard_size">50dp</dimen>
<dimen name="min_emoji_drawer_height">200dp</dimen> <dimen name="default_custom_keyboard_size">220dp</dimen>
<dimen name="min_emoji_drawer_top_margin">170dp</dimen> <dimen name="min_custom_keyboard_size">110dp</dimen>
<dimen name="min_custom_keyboard_top_margin">170dp</dimen>
<dimen name="emoji_drawer_item_padding">5dp</dimen> <dimen name="emoji_drawer_item_padding">5dp</dimen>
<dimen name="emoji_drawer_indicator_height">1.5dp</dimen> <dimen name="emoji_drawer_indicator_height">1.5dp</dimen>
<dimen name="emoji_drawer_left_right_padding">5dp</dimen> <dimen name="emoji_drawer_left_right_padding">5dp</dimen>

View File

@ -29,6 +29,7 @@ import android.view.View;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.Util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashSet; import java.util.HashSet;
@ -46,6 +47,9 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>(); private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>();
private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>(); private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>();
private final int minKeyboardSize; private final int minKeyboardSize;
private final int minCustomKeyboardSize;
private final int defaultCustomKeyboardSize;
private final int minCustomKeyboardTopMargin;
private boolean keyboardOpen = false; private boolean keyboardOpen = false;
private int rotation = -1; private int rotation = -1;
@ -60,7 +64,10 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyle) { public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size); minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size);
minCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_size);
defaultCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.default_custom_keyboard_size);
minCustomKeyboardTopMargin = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin);
} }
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@ -134,10 +141,6 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
notifyHiddenListeners(); notifyHiddenListeners();
} }
public boolean isKeyboardOpen() {
return keyboardOpen;
}
public int getKeyboardHeight() { public int getKeyboardHeight() {
return isLandscape() ? getKeyboardLandscapeHeight() : getKeyboardPortraitHeight(); return isLandscape() ? getKeyboardLandscapeHeight() : getKeyboardPortraitHeight();
} }
@ -156,9 +159,8 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
private int getKeyboardPortraitHeight() { private int getKeyboardPortraitHeight() {
int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext()) int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext())
.getInt("keyboard_height_portrait", .getInt("keyboard_height_portrait", defaultCustomKeyboardSize);
getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height)); return Util.clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMargin);
return Math.min(keyboardHeight, getRootView().getHeight() - getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_top_margin));
} }
private void setKeyboardPortraitHeight(int height) { private void setKeyboardPortraitHeight(int height) {

View File

@ -18,13 +18,12 @@ import android.view.MotionEvent;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager;
import android.widget.ImageButton; import android.widget.ImageButton;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
import org.thoughtcrime.securesms.components.camera.QuickCamera.QuickCameraListener; import org.thoughtcrime.securesms.components.camera.QuickCamera.QuickCameraListener;
import org.thoughtcrime.securesms.util.SoftKeyboardUtil; import org.thoughtcrime.securesms.util.ServiceUtil;
public class QuickAttachmentDrawer extends ViewGroup { public class QuickAttachmentDrawer extends ViewGroup {
private static final String TAG = QuickAttachmentDrawer.class.getSimpleName(); private static final String TAG = QuickAttachmentDrawer.class.getSimpleName();
@ -33,23 +32,23 @@ public class QuickAttachmentDrawer extends ViewGroup {
private final ViewDragHelper dragHelper; private final ViewDragHelper dragHelper;
private QuickCamera quickCamera; private QuickCamera quickCamera;
private int coverViewPosition; private int coverViewPosition;
private View coverView; private KeyboardAwareLinearLayout coverView;
private View controls; private View controls;
private ImageButton fullScreenButton; private ImageButton fullScreenButton;
private ImageButton swapCameraButton; private ImageButton swapCameraButton;
private ImageButton shutterButton; private ImageButton shutterButton;
private float slideOffset; private float slideOffset;
private float initialMotionX; private float initialMotionX;
private float initialMotionY; private float initialMotionY;
private int rotation; private int rotation;
private int slideRange; private int slideRange;
private int baseHalfHeight; private AttachmentDrawerListener listener;
private AttachmentDrawerListener listener; private int halfExpandedHeight;
private float halfExpandedAnchorPoint;
private DrawerState drawerState = DrawerState.COLLAPSED; private DrawerState drawerState = DrawerState.COLLAPSED;
private float halfExpandedAnchorPoint = COLLAPSED_ANCHOR_POINT;
private boolean halfModeUnsupported = VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH; private boolean halfModeUnsupported = VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
private Rect drawChildrenRect = new Rect(); private Rect drawChildrenRect = new Rect();
private boolean paused = false; private boolean paused = false;
@ -64,8 +63,7 @@ public class QuickAttachmentDrawer extends ViewGroup {
public QuickAttachmentDrawer(Context context, AttributeSet attrs, int defStyle) { public QuickAttachmentDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
baseHalfHeight = SoftKeyboardUtil.getKeyboardHeight(getContext()); dragHelper = ViewDragHelper.create(this, 1.f, new ViewDragHelperCallback());
dragHelper = ViewDragHelper.create(this, 1.f, new ViewDragHelperCallback());
initializeView(); initializeView();
updateHalfExpandedAnchorPoint(); updateHalfExpandedAnchorPoint();
onConfigurationChanged(); onConfigurationChanged();
@ -79,10 +77,6 @@ public class QuickAttachmentDrawer extends ViewGroup {
coverViewPosition = getChildCount(); coverViewPosition = getChildCount();
} }
private WindowManager getWindowManager() {
return (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
}
public static boolean isDeviceSupported(Context context) { public static boolean isDeviceSupported(Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) && return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) &&
Camera.getNumberOfCameras() > 0; Camera.getNumberOfCameras() > 0;
@ -101,7 +95,7 @@ public class QuickAttachmentDrawer extends ViewGroup {
} }
public void onConfigurationChanged() { public void onConfigurationChanged() {
int rotation = getWindowManager().getDefaultDisplay().getRotation(); int rotation = ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
final boolean rotationChanged = this.rotation != rotation; final boolean rotationChanged = this.rotation != rotation;
this.rotation = rotation; this.rotation = rotation;
if (rotationChanged) { if (rotationChanged) {
@ -140,24 +134,24 @@ public class QuickAttachmentDrawer extends ViewGroup {
return isLandscape() || halfModeUnsupported; return isLandscape() || halfModeUnsupported;
} }
private void updateHalfExpandedAnchorPoint() { private KeyboardAwareLinearLayout getCoverView() {
Log.w(TAG, "updateHalfExpandedAnchorPoint()"); if (coverView != null) return coverView;
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressWarnings("deprecation") @Override public void onGlobalLayout() {
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
coverView = getChildAt(coverViewPosition); final View coverViewChild = getChildAt(coverViewPosition);
slideRange = getMeasuredHeight(); if (coverViewChild != null && !(coverViewChild instanceof KeyboardAwareLinearLayout)) {
halfExpandedAnchorPoint = computeSlideOffsetFromCoverBottom(slideRange - baseHalfHeight); throw new IllegalStateException("cover view must be a KeyboardAwareLinearLayout");
requestLayout(); }
invalidate();
Log.w(TAG, "updated halfExpandedAnchorPoint!"); coverView = (KeyboardAwareLinearLayout) coverViewChild;
} return coverView;
}); }
private void updateHalfExpandedAnchorPoint() {
if (getCoverView() != null) {
slideRange = getMeasuredHeight();
halfExpandedHeight = coverView.getKeyboardHeight();
halfExpandedAnchorPoint = computeSlideOffsetFromCoverBottom(slideRange - halfExpandedHeight);
}
} }
@Override @Override
@ -165,6 +159,8 @@ public class QuickAttachmentDrawer extends ViewGroup {
final int paddingLeft = getPaddingLeft(); final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop(); final int paddingTop = getPaddingTop();
updateHalfExpandedAnchorPoint();
for (int i = 0; i < getChildCount(); i++) { for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i); final View child = getChildAt(i);
final int childHeight = child.getMeasuredHeight(); final int childHeight = child.getMeasuredHeight();
@ -192,8 +188,8 @@ public class QuickAttachmentDrawer extends ViewGroup {
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec); final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec); final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
@ -477,7 +473,7 @@ public class QuickAttachmentDrawer extends ViewGroup {
clampedOffset = clampedOffset / (FULL_EXPANDED_ANCHOR_POINT - halfExpandedAnchorPoint); clampedOffset = clampedOffset / (FULL_EXPANDED_ANCHOR_POINT - halfExpandedAnchorPoint);
} }
float slidePixelOffset = slideOffset * slideRange + float slidePixelOffset = slideOffset * slideRange +
(quickCamera.getMeasuredHeight() - baseHalfHeight) / 2 * (quickCamera.getMeasuredHeight() - coverView.getKeyboardHeight()) / 2 *
(FULL_EXPANDED_ANCHOR_POINT - clampedOffset); (FULL_EXPANDED_ANCHOR_POINT - clampedOffset);
float marginPixelOffset = (getMeasuredHeight() - quickCamera.getMeasuredHeight()) / 2 * clampedOffset; float marginPixelOffset = (getMeasuredHeight() - quickCamera.getMeasuredHeight()) / 2 * clampedOffset;
return (int) (getMeasuredHeight() - slidePixelOffset + marginPixelOffset); return (int) (getMeasuredHeight() - slidePixelOffset + marginPixelOffset);
@ -528,7 +524,7 @@ public class QuickAttachmentDrawer extends ViewGroup {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean crop = drawerState != DrawerState.FULL_EXPANDED; boolean crop = drawerState != DrawerState.FULL_EXPANDED;
int imageHeight = crop ? baseHalfHeight : quickCamera.getMeasuredHeight(); int imageHeight = crop ? coverView.getKeyboardHeight() : quickCamera.getMeasuredHeight();
Rect previewRect = new Rect(0, 0, quickCamera.getMeasuredWidth(), imageHeight); Rect previewRect = new Rect(0, 0, quickCamera.getMeasuredWidth(), imageHeight);
quickCamera.takePicture(previewRect); quickCamera.takePicture(previewRect);
} }

View File

@ -73,6 +73,7 @@ public class EmojiDrawer extends LinearLayout {
public void show(KeyboardAwareLinearLayout container) { public void show(KeyboardAwareLinearLayout container) {
ViewGroup.LayoutParams params = getLayoutParams(); ViewGroup.LayoutParams params = getLayoutParams();
params.height = container.getKeyboardHeight(); params.height = container.getKeyboardHeight();
Log.w("EmojiDrawer", "showing emoji drawer with height " + params.height);
setLayoutParams(params); setLayoutParams(params);
setVisibility(VISIBLE); setVisibility(VISIBLE);
} }

View File

@ -1,121 +0,0 @@
package org.thoughtcrime.securesms.util;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import org.thoughtcrime.securesms.R;
import java.lang.reflect.Field;
public class SoftKeyboardUtil {
private static final String TAG = SoftKeyboardUtil.class.getSimpleName();
private static final Rect rect = new Rect();
public static int onMeasure(ViewGroup view) {
view.getWindowVisibleDisplayFrame(rect);
final int res = view.getResources().getIdentifier("status_bar_height", "dimen", "android");
final int statusBarHeight = res > 0 ? view.getResources().getDimensionPixelSize(res) : 0;
final int availableHeight = view.getRootView().getHeight() - statusBarHeight - getViewInset(view);
final int keyboardHeight = availableHeight - (rect.bottom - rect.top);
final int minKeyboardHeight = view.getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height);
if (keyboardHeight > minKeyboardHeight) {
onKeyboardShown(view.getContext(), keyboardHeight);
}
return Math.max(keyboardHeight, minKeyboardHeight);
}
private static int getViewInset(ViewGroup view) {
if (Build.VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
return 0;
}
try {
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
attachInfoField.setAccessible(true);
Object attachInfo = attachInfoField.get(view);
if (attachInfo != null) {
Field stableInsetsField = attachInfo.getClass().getDeclaredField("mStableInsets");
stableInsetsField.setAccessible(true);
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);
}
return 0;
}
private static void onKeyboardShown(Context context, int keyboardHeight) {
Log.w(TAG, "keyboard shown, height " + keyboardHeight);
WindowManager wm = (WindowManager)context.getSystemService(Activity.WINDOW_SERVICE);
if (wm == null || wm.getDefaultDisplay() == null) {
return;
}
int rotation = wm.getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_270:
case Surface.ROTATION_90:
setKeyboardLandscapeHeight(context, keyboardHeight);
break;
case Surface.ROTATION_0:
case Surface.ROTATION_180:
setKeyboardPortraitHeight(context, keyboardHeight);
}
}
public static int getKeyboardHeight(Context context) {
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
if (wm == null || wm.getDefaultDisplay() == null) {
throw new AssertionError("WindowManager was null or there is no default display");
}
int rotation = wm.getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_270:
case Surface.ROTATION_90:
return getKeyboardLandscapeHeight(context);
case Surface.ROTATION_0:
case Surface.ROTATION_180:
default:
return getKeyboardPortraitHeight(context);
}
}
private static int getKeyboardLandscapeHeight(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getInt("keyboard_height_landscape",
context.getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
}
private static int getKeyboardPortraitHeight(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getInt("keyboard_height_portrait",
context.getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
}
private static void setKeyboardLandscapeHeight(Context context, int height) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putInt("keyboard_height_landscape", height).apply();
}
private static void setKeyboardPortraitHeight(Context context, int height) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putInt("keyboard_height_portrait", height).apply();
}
}

View File

@ -344,4 +344,8 @@ public class Util {
return (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) || return (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) ||
activityManager.getMemoryClass() <= 64; activityManager.getMemoryClass() <= 64;
} }
public static int clamp(int value, int min, int max) {
return Math.min(Math.max(value, min), max);
}
} }