diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b05db94018..d333d0e4eb 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -3,6 +3,7 @@
32sp
50dp
200dp
+ 170dp
5dp
1.5dp
5dp
diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java
index e585fa15d4..a2f81bf938 100644
--- a/src/org/thoughtcrime/securesms/ConversationActivity.java
+++ b/src/org/thoughtcrime/securesms/ConversationActivity.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
@@ -113,6 +114,7 @@ import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.GroupUtil;
+import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
@@ -264,8 +266,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- Log.w(TAG, String.format("onConfigurationChanged(%d -> %d)", getResources().getConfiguration().orientation, newConfig.orientation));
quickAttachmentDrawer.onConfigurationChanged();
+ hideEmojiPopup(false);
}
@Override
@@ -274,6 +276,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (recipients != null) recipients.removeListener(this);
if (securityUpdateReceiver != null) unregisterReceiver(securityUpdateReceiver);
if (groupUpdateReceiver != null) unregisterReceiver(groupUpdateReceiver);
+ hideEmojiPopup(false);
super.onDestroy();
}
@@ -858,13 +861,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private EmojiPopup getEmojiPopup() {
if (!emojiPopup.isPresent()) {
- EmojiPopup emojiPopup = new EmojiPopup(getWindow().getDecorView());
+ EmojiPopup emojiPopup = new EmojiPopup(container);
emojiPopup.setEmojiEventListener(new EmojiEventListener() {
@Override public void onKeyEvent(KeyEvent keyEvent) {
composeText.dispatchKeyEvent(keyEvent);
}
@Override public void onEmojiSelected(String emoji) {
+ Log.w(TAG, "onEmojiSelected()");
composeText.insertEmoji(emoji);
}
});
@@ -874,17 +878,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void showEmojiPopup() {
- int height = Math.max(getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height),
- container.getKeyboardHeight());
- container.padForCustomKeyboard(height);
- getEmojiPopup().show(height);
+ getEmojiPopup().show();
emojiToggle.setToIme();
}
- private void hideEmojiPopup(boolean expectingKeyboard) {
+ protected void hideEmojiPopup(boolean expectingKeyboard) {
if (isEmojiDrawerOpen()) {
getEmojiPopup().dismiss();
- if (!expectingKeyboard) {
+ if (!expectingKeyboard || container.isLandscape()) {
container.unpadForCustomKeyboard();
}
}
@@ -1330,22 +1331,34 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
+ private void openKeyboardForComposition() {
+ composeText.post(new Runnable() {
+ @Override public void run() {
+ composeText.requestFocus();
+ ServiceUtil.getInputMethodManager(ConversationActivity.this).showSoftInput(composeText, 0);
+ }
+ });
+ }
+
+ private void hideKeyboard() {
+ ServiceUtil.getInputMethodManager(this).hideSoftInputFromWindow(composeText.getWindowToken(), 0);
+ }
+
private class EmojiToggleListener implements OnClickListener {
@Override
public void onClick(View v) {
- InputMethodManager input = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
-
+ Log.w(TAG, "EmojiToggleListener onClick()");
if (isEmojiDrawerOpen()) {
hideEmojiPopup(true);
- input.showSoftInput(composeText, 0);
+ openKeyboardForComposition();
} else {
container.postOnKeyboardClose(new Runnable() {
@Override public void run() {
showEmojiPopup();
}
});
- input.hideSoftInputFromWindow(composeText.getWindowToken(), 0);
- quickAttachmentDrawer.setDrawerStateAndAnimate(DrawerState.COLLAPSED);
+ quickAttachmentDrawer.close();
+ hideKeyboard();
}
}
}
diff --git a/src/org/thoughtcrime/securesms/ConversationPopupActivity.java b/src/org/thoughtcrime/securesms/ConversationPopupActivity.java
index 4c16eb71d9..96d79d7862 100644
--- a/src/org/thoughtcrime/securesms/ConversationPopupActivity.java
+++ b/src/org/thoughtcrime/securesms/ConversationPopupActivity.java
@@ -112,6 +112,11 @@ public class ConversationPopupActivity extends ConversationActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
}
+ @Override
+ protected void hideEmojiPopup(boolean expectingKeyboard) {
+ super.hideEmojiPopup(false);
+ }
+
@Override
protected void sendComplete(long threadId) {
super.sendComplete(threadId);
diff --git a/src/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java b/src/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java
index 5590ac4ba9..264a84c32e 100644
--- a/src/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java
+++ b/src/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java
@@ -16,7 +16,6 @@
*/
package org.thoughtcrime.securesms.components;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
@@ -27,9 +26,9 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.View;
-import android.view.WindowManager;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.util.ServiceUtil;
import java.lang.reflect.Field;
import java.util.HashSet;
@@ -46,9 +45,10 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
private final Rect newRect = new Rect();
private final Set hiddenListeners = new HashSet<>();
private final Set shownListeners = new HashSet<>();
- private final int minKeyboardSize;
+ private final int minKeyboardSize;
- private boolean keyboardOpen;
+ private boolean keyboardOpen = false;
+ private int rotation = -1;
public KeyboardAwareLinearLayout(Context context) {
this(context, null);
@@ -64,16 +64,29 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ updateRotation();
+ updateKeyboardState();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
- int res = getResources().getIdentifier("status_bar_height", "dimen", "android");
+ private void updateRotation() {
+ int oldRotation = rotation;
+ rotation = getDeviceRotation();
+ if (oldRotation != rotation) {
+ onKeyboardClose();
+ oldRect.setEmpty();
+ }
+ }
+
+ private void updateKeyboardState() {
+ int res = getResources().getIdentifier("status_bar_height", "dimen", "android");
int statusBarHeight = res > 0 ? getResources().getDimensionPixelSize(res) : 0;
final int availableHeight = this.getRootView().getHeight() - statusBarHeight - getViewInset();
getWindowVisibleDisplayFrame(newRect);
final int oldKeyboardHeight = availableHeight - (oldRect.bottom - oldRect.top);
- final int keyboardHeight = availableHeight - (newRect.bottom - newRect.top);
+ final int keyboardHeight = availableHeight - (newRect.bottom - newRect.top);
if (keyboardHeight - oldKeyboardHeight > minKeyboardSize && !keyboardOpen) {
onKeyboardOpen(keyboardHeight);
@@ -84,7 +97,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
oldRect.set(newRect);
}
- public void padForCustomKeyboard(int height) {
+ public void padForCustomKeyboard(final int height) {
setPadding(0, 0, 0, height);
}
@@ -117,22 +130,9 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
protected void onKeyboardOpen(int keyboardHeight) {
keyboardOpen = true;
- Log.w(TAG, "onKeyboardOpen(" + keyboardHeight + ")");
- WindowManager wm = (WindowManager) getContext().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(keyboardHeight);
- break;
- case Surface.ROTATION_0:
- case Surface.ROTATION_180:
- setKeyboardPortraitHeight(keyboardHeight);
+ if (!isLandscape()) {
+ setKeyboardPortraitHeight(keyboardHeight);
}
notifyShownListeners();
unpadForCustomKeyboard();
@@ -140,7 +140,6 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
protected void onKeyboardClose() {
keyboardOpen = false;
- Log.w(TAG, "onKeyboardClose()");
notifyHiddenListeners();
}
@@ -149,39 +148,26 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
}
public int getKeyboardHeight() {
- WindowManager wm = (WindowManager) getContext().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();
+ return isLandscape() ? getKeyboardLandscapeHeight() : getKeyboardPortraitHeight();
+ }
- switch (rotation) {
- case Surface.ROTATION_270:
- case Surface.ROTATION_90:
- return getKeyboardLandscapeHeight();
- case Surface.ROTATION_0:
- case Surface.ROTATION_180:
- default:
- return getKeyboardPortraitHeight();
- }
+ public boolean isLandscape() {
+ int rotation = getDeviceRotation();
+ return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
+ }
+ private int getDeviceRotation() {
+ return ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
}
private int getKeyboardLandscapeHeight() {
- return PreferenceManager.getDefaultSharedPreferences(getContext())
- .getInt("keyboard_height_landscape",
- getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
+ return Math.max(getHeight(), getRootView().getHeight()) / 2;
}
private int getKeyboardPortraitHeight() {
- return PreferenceManager.getDefaultSharedPreferences(getContext())
- .getInt("keyboard_height_portrait",
- getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
- }
-
- private void setKeyboardLandscapeHeight(int height) {
- PreferenceManager.getDefaultSharedPreferences(getContext())
- .edit().putInt("keyboard_height_landscape", height).apply();
+ int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext())
+ .getInt("keyboard_height_portrait",
+ getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
+ return Math.min(keyboardHeight, getRootView().getHeight() - getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_top_margin));
}
private void setKeyboardPortraitHeight(int height) {
diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java
index 26695412d4..1e6eb8f16b 100644
--- a/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java
+++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java
@@ -80,6 +80,7 @@ public class EmojiDrawer extends LinearLayoutCompat {
models,
new EmojiSelectionListener() {
@Override public void onEmojiSelected(String emoji) {
+ Log.w("EmojiDrawer", "onEmojiSelected()");
recentModel.onCodePointSelected(emoji);
if (listener != null) listener.onEmojiSelected(emoji);
}
diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java
index 1147c63a77..7046d1ce08 100644
--- a/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java
+++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java
@@ -1,16 +1,12 @@
package org.thoughtcrime.securesms.components.emoji;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.GridView;
@@ -25,24 +21,27 @@ public class EmojiPageView extends FrameLayout {
private GridView grid;
public EmojiPageView(Context context) {
- super(context);
- init();
+ this(context, null);
}
public EmojiPageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
+ this(context, attrs, 0);
}
public EmojiPageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- init();
- }
-
- @TargetApi(VERSION_CODES.LOLLIPOP)
- public EmojiPageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
+ final View view = LayoutInflater.from(getContext()).inflate(R.layout.emoji_grid_layout, this, true);
+ grid = (GridView) view.findViewById(R.id.emoji);
+ grid.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.emoji_drawer_size) + 2 * getResources().getDimensionPixelSize(R.dimen.emoji_drawer_item_padding));
+ grid.setOnTouchListener(new OnTouchListener() {
+ @Override public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ EmojiView emojiView = (EmojiView)grid.getChildAt(grid.pointToPosition((int)event.getX(), (int)event.getY()));
+ if (listener != null && emojiView != null) listener.onEmojiSelected(emojiView.getEmoji());
+ }
+ return false;
+ }
+ });
}
public void onSelected() {
@@ -51,17 +50,6 @@ public class EmojiPageView extends FrameLayout {
}
}
- private void init() {
- final View view = LayoutInflater.from(getContext()).inflate(R.layout.emoji_grid_layout, this, true);
- grid = (GridView) view.findViewById(R.id.emoji);
- grid.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.emoji_drawer_size) + 2 * getResources().getDimensionPixelSize(R.dimen.emoji_drawer_item_padding));
- grid.setOnItemClickListener(new OnItemClickListener() {
- @Override public void onItemClick(AdapterView> parent, View view, int position, long id) {
- if (listener != null) listener.onEmojiSelected((String)view.getTag());
- }
- });
- }
-
public void setModel(EmojiPageModel model) {
this.model = model;
grid.setAdapter(new EmojiGridAdapter(getContext(), model));
@@ -73,9 +61,9 @@ public class EmojiPageView extends FrameLayout {
private static class EmojiGridAdapter extends BaseAdapter {
- protected final Context context;
- private final int emojiSize;
- private final EmojiPageModel model;
+ protected final Context context;
+ private final int emojiSize;
+ private final EmojiPageModel model;
public EmojiGridAdapter(Context context, EmojiPageModel model) {
this.context = context;
@@ -104,14 +92,13 @@ public class EmojiPageView extends FrameLayout {
if (convertView != null && convertView instanceof EmojiView) {
view = (EmojiView)convertView;
} else {
- EmojiView emojiView = new EmojiView(context);
+ final EmojiView emojiView = new EmojiView(context);
emojiView.setPadding(pad, pad, pad, pad);
emojiView.setLayoutParams(new AbsListView.LayoutParams(emojiSize + 2 * pad, emojiSize + 2 * pad));
view = emojiView;
}
view.setEmoji(model.getEmoji()[position]);
- view.setTag(model.getEmoji()[position]);
return view;
}
}
diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPopup.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPopup.java
index 0423844df1..b9ed9c6eef 100644
--- a/src/org/thoughtcrime/securesms/components/emoji/EmojiPopup.java
+++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPopup.java
@@ -1,31 +1,45 @@
package org.thoughtcrime.securesms.components.emoji;
-import android.app.Activity;
-import android.content.Context;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.PopupWindow;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListener;
public class EmojiPopup extends PopupWindow {
- private View parent;
+ private static final String TAG = EmojiPopup.class.getSimpleName();
+ private KeyboardAwareLinearLayout parent;
- public EmojiPopup(View parent) {
+ public EmojiPopup(KeyboardAwareLinearLayout parent) {
super(new EmojiDrawer(parent.getContext()),
parent.getWidth(),
parent.getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
this.parent = parent;
+ Log.w("EmojiPopup", "popup initialized with width " + parent.getWidth());
}
public void setEmojiEventListener(EmojiEventListener listener) {
((EmojiDrawer)getContentView()).setEmojiEventListener(listener);
}
- public void show(int height) {
- setHeight(height);
+ public void show() {
+ setHeight(parent.getKeyboardHeight());
+ setWidth(parent.getWidth());
+ parent.padForCustomKeyboard(getHeight());
+ Log.w(TAG, String.format("show(%d, %d)", getWidth(), getHeight()));
showAtLocation(parent, Gravity.BOTTOM | Gravity.LEFT, 0, 0);
}
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ }
+
+ public void update() {
+ update(parent, 0, 0, parent.getWidth(), -1);
+ }
}
diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java
index 7d35dee120..b464cc52ec 100644
--- a/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java
+++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiView.java
@@ -23,22 +23,17 @@ public class EmojiView extends View implements Drawable.Callback {
private final Rect textBounds = new Rect();
public EmojiView(Context context) {
- super(context);
+ this(context, null);
}
public EmojiView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
}
public EmojiView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
- @TargetApi(VERSION_CODES.LOLLIPOP)
- public EmojiView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
public void setEmoji(String emoji) {
this.emoji = emoji;
this.drawable = EmojiProvider.getInstance(getContext())
@@ -47,6 +42,10 @@ public class EmojiView extends View implements Drawable.Callback {
postInvalidate();
}
+ public String getEmoji() {
+ return emoji;
+ }
+
@Override protected void onDraw(Canvas canvas) {
if (drawable != null) {
drawable.setBounds(getPaddingLeft(),
diff --git a/src/org/thoughtcrime/securesms/util/ServiceUtil.java b/src/org/thoughtcrime/securesms/util/ServiceUtil.java
new file mode 100644
index 0000000000..049433d437
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/util/ServiceUtil.java
@@ -0,0 +1,16 @@
+package org.thoughtcrime.securesms.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+public class ServiceUtil {
+ public static InputMethodManager getInputMethodManager(Context context) {
+ return (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ }
+
+ public static WindowManager getWindowManager(Context context) {
+ return (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE);
+ }
+}