私聊改造:输入体验优化
This commit is contained in:
@@ -69,8 +69,6 @@ dependencies {
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}"
|
||||
|
||||
implementation project(':library')
|
||||
|
||||
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#F4F4FA" />
|
||||
<corners android:radius="15dp" />
|
||||
<solid android:color="#F2F2F7" />
|
||||
<corners android:radius="25dp" />
|
||||
</shape>
|
@@ -6,13 +6,6 @@
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<View
|
||||
android:id="@+id/top_divider_line"
|
||||
android:layout_height="1px"
|
||||
android:layout_width="match_parent"
|
||||
android:background="#353548"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/scrPlugin"
|
||||
android:layout_width="fill_parent"
|
||||
@@ -30,8 +23,6 @@
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"/>
|
||||
|
||||
<View style="@style/horizontal_light_thin_divider"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -50,6 +41,7 @@
|
||||
android:layout_height="44dp"
|
||||
android:orientation="horizontal">
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
|
||||
<color name="nim_app_color">#FFBC52</color>
|
||||
<color name="nim_app_color_press">#FFBC52</color>
|
||||
<color name="nim_app_color">#5BC8F8</color>
|
||||
<color name="nim_app_color_press">#5BC8F8</color>
|
||||
|
||||
<color name="transparent">#00000000</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
|
@@ -1,61 +0,0 @@
|
||||
package com.netease.nim.uikit;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Created by huangmeng1 on 2018/3/9.
|
||||
*/
|
||||
|
||||
public class AndroidBug5497Workaround {
|
||||
|
||||
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
||||
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
||||
|
||||
public static void assistActivity (Activity activity) {
|
||||
new AndroidBug5497Workaround(activity);
|
||||
}
|
||||
|
||||
private View mChildOfContent;
|
||||
private int usableHeightPrevious;
|
||||
private FrameLayout.LayoutParams frameLayoutParams;
|
||||
|
||||
private AndroidBug5497Workaround(final Activity activity) {
|
||||
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
|
||||
mChildOfContent = content.getChildAt(0);
|
||||
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
possiblyResizeChildOfContent(activity);
|
||||
}
|
||||
});
|
||||
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
||||
}
|
||||
|
||||
private void possiblyResizeChildOfContent(Activity activity) {
|
||||
int usableHeightNow = computeUsableHeight();
|
||||
if (usableHeightNow != usableHeightPrevious) {
|
||||
int usableHeightSansKeyboard = activity.getWindowManager().getDefaultDisplay().getHeight();
|
||||
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
||||
if (heightDifference > (usableHeightSansKeyboard/4)) {
|
||||
// keyboard probably just became visible
|
||||
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
||||
} else {
|
||||
// keyboard probably just became hidden
|
||||
frameLayoutParams.height = usableHeightSansKeyboard;
|
||||
}
|
||||
mChildOfContent.requestLayout();
|
||||
usableHeightPrevious = usableHeightNow;
|
||||
}
|
||||
}
|
||||
|
||||
private int computeUsableHeight() {
|
||||
Rect r = new Rect();
|
||||
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
||||
return (r.bottom - r.top);// 全屏模式下: return r.bottom
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -307,16 +307,6 @@ public class NimUIKit {
|
||||
NimUIKitImpl.startP2PSession(context, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同 {@link NimUIKitImpl#startP2PSession(Context, String)},同时聊天界面打开后,列表跳转至anchor位置
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param account 目标账号
|
||||
* @param anchor 跳转到指定消息的位置,不需要跳转填null
|
||||
*/
|
||||
public static void startP2PSession(Context context, String account, IMMessage anchor) {
|
||||
NimUIKitImpl.startP2PSession(context, account, anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开群聊界面,若开发者未设置 {@link NimUIKitImpl#setCommonTeamSessionCustomization(SessionCustomization)},
|
||||
|
@@ -1,82 +0,0 @@
|
||||
package com.netease.nim.uikit.api.wrapper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.netease.nim.uikit.R;
|
||||
import com.netease.nim.uikit.api.NimUIKit;
|
||||
import com.netease.nim.uikit.business.team.helper.TeamHelper;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.nimlib.sdk.uinfo.UserInfoProvider;
|
||||
import com.netease.nimlib.sdk.uinfo.model.UserInfo;
|
||||
|
||||
/**
|
||||
* 初始化sdk 需要的用户信息提供者,现主要用于内置通知提醒获取昵称和头像
|
||||
* <p>
|
||||
* 注意不要与 IUserInfoProvider 混淆,后者是 UIKit 与 demo 之间的数据共享接口
|
||||
* <p>
|
||||
*/
|
||||
|
||||
public class NimUserInfoProvider implements UserInfoProvider {
|
||||
|
||||
private Context context;
|
||||
|
||||
public NimUserInfoProvider(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo getUserInfo(String account) {
|
||||
return NimUIKit.getUserInfoProvider().getUserInfo(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getAvatarForMessageNotifier(SessionTypeEnum sessionType, String sessionId) {
|
||||
/*
|
||||
* 注意:这里最好从缓存里拿,如果加载时间过长会导致通知栏延迟弹出!该函数在后台线程执行!
|
||||
*/
|
||||
Bitmap bm = null;
|
||||
int defResId = R.drawable.nim_avatar_default;
|
||||
|
||||
if (SessionTypeEnum.P2P == sessionType) {
|
||||
UserInfo user = getUserInfo(sessionId);
|
||||
bm = (user != null) ? NimUIKit.getImageLoaderKit().getNotificationBitmapFromCache(user.getAvatar()) : null;
|
||||
} else if (SessionTypeEnum.Team == sessionType) {
|
||||
Team team = NimUIKit.getTeamProvider().getTeamById(sessionId);
|
||||
bm = (team != null) ? NimUIKit.getImageLoaderKit().getNotificationBitmapFromCache(team.getIcon()) : null;
|
||||
defResId = R.drawable.nim_avatar_group;
|
||||
}
|
||||
|
||||
if (bm == null) {
|
||||
Drawable drawable = context.getResources().getDrawable(defResId);
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
bm = ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
}
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayNameForMessageNotifier(String account, String sessionId, SessionTypeEnum sessionType) {
|
||||
String nick = null;
|
||||
if (sessionType == SessionTypeEnum.P2P) {
|
||||
nick = NimUIKit.getContactProvider().getAlias(account);
|
||||
} else if (sessionType == SessionTypeEnum.Team) {
|
||||
nick = NimUIKit.getContactProvider().getAlias(account);
|
||||
if (TextUtils.isEmpty(nick)) {
|
||||
nick = TeamHelper.getTeamNick(sessionId, account);
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(nick)) {
|
||||
return null; // 返回null,交给sdk处理。如果对方有设置nick,sdk会显示nick
|
||||
}
|
||||
|
||||
return nick;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package com.netease.nim.uikit.business.session.actions;
|
||||
|
||||
import com.netease.nim.uikit.R;
|
||||
import com.netease.nim.uikit.business.session.constant.RequestCode;
|
||||
import com.netease.nim.uikit.business.session.event.ActiveEvent;
|
||||
import com.netease.nim.uikit.common.media.picker.PickImageHelper;
|
||||
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
|
||||
import com.netease.nimlib.sdk.msg.MessageBuilder;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.model.IMMessage;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by hzxuwen on 2015/6/12.
|
||||
*/
|
||||
public class CameraAction extends PickImageAction {
|
||||
|
||||
public CameraAction() {
|
||||
super(R.drawable.chat_icon_photo, R.string.input_panel_photo, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
PickImageHelper.pickCamera(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPicked(File file) {
|
||||
IMMessage message;
|
||||
if (getContainer() != null && getContainer().sessionType == SessionTypeEnum.ChatRoom) {
|
||||
message = ChatRoomMessageBuilder.createChatRoomImageMessage(getAccount(), file, file.getName());
|
||||
} else {
|
||||
message = MessageBuilder.createImageMessage(getAccount(), getSessionType(), file, file.getName());
|
||||
}
|
||||
sendMessage(message);
|
||||
|
||||
EventBus.getDefault().post(new ActiveEvent());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,43 @@
|
||||
package com.netease.nim.uikit.business.session.actions;
|
||||
|
||||
import com.netease.nim.uikit.R;
|
||||
import com.netease.nim.uikit.business.session.constant.RequestCode;
|
||||
import com.netease.nim.uikit.business.session.event.ActiveEvent;
|
||||
import com.netease.nim.uikit.common.media.picker.PickImageHelper;
|
||||
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
|
||||
import com.netease.nimlib.sdk.msg.MessageBuilder;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.model.IMMessage;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by hzxuwen on 2015/6/12.
|
||||
*/
|
||||
public class PhotoAction extends PickImageAction {
|
||||
|
||||
public PhotoAction() {
|
||||
super(R.drawable.chat_icon_photo, R.string.input_panel_photo, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
PickImageHelper.pickPhoto(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPicked(File file) {
|
||||
IMMessage message;
|
||||
if (getContainer() != null && getContainer().sessionType == SessionTypeEnum.ChatRoom) {
|
||||
message = ChatRoomMessageBuilder.createChatRoomImageMessage(getAccount(), file, file.getName());
|
||||
} else {
|
||||
message = MessageBuilder.createImageMessage(getAccount(), getSessionType(), file, file.getName());
|
||||
}
|
||||
sendMessage(message);
|
||||
|
||||
EventBus.getDefault().post(new ActiveEvent());
|
||||
}
|
||||
}
|
||||
|
@@ -25,26 +25,23 @@ import java.io.File;
|
||||
*/
|
||||
public abstract class PickImageAction extends BaseAction {
|
||||
|
||||
private static final int PICK_IMAGE_COUNT = 9;
|
||||
private static final int PORTRAIT_IMAGE_WIDTH = 720;
|
||||
|
||||
public static final String MIME_JPEG = "image/jpeg";
|
||||
public static final String JPG = ".jpg";
|
||||
|
||||
private static final int PICK_IMAGE_COUNT = 9;
|
||||
private static final int PORTRAIT_IMAGE_WIDTH = 720;
|
||||
private boolean multiSelect;
|
||||
private boolean crop = false;
|
||||
|
||||
protected abstract void onPicked(File file);
|
||||
|
||||
protected PickImageAction(int iconResId, int titleId, boolean multiSelect) {
|
||||
super(iconResId, titleId);
|
||||
this.multiSelect = multiSelect;
|
||||
}
|
||||
|
||||
protected abstract void onPicked(File file);
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
int requestCode = makeRequestCode(RequestCode.PICK_IMAGE);
|
||||
showSelector(getTitleId(), requestCode, multiSelect, tempFile());
|
||||
PickImageHelper.pickImage(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
|
||||
}
|
||||
|
||||
private String tempFile() {
|
||||
@@ -52,20 +49,16 @@ public abstract class PickImageAction extends BaseAction {
|
||||
return StorageUtil.getWritePath(filename, StorageType.TYPE_TEMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开图片选择器
|
||||
*/
|
||||
private void showSelector(int titleId, final int requestCode, final boolean multiSelect, final String outPath) {
|
||||
public PickImageHelper.PickImageOption buildOption() {
|
||||
PickImageHelper.PickImageOption option = new PickImageHelper.PickImageOption();
|
||||
option.titleResId = titleId;
|
||||
option.titleResId = getTitleId();
|
||||
option.multiSelect = multiSelect;
|
||||
option.multiSelectMaxCount = PICK_IMAGE_COUNT;
|
||||
option.crop = crop;
|
||||
option.cropOutputImageWidth = PORTRAIT_IMAGE_WIDTH;
|
||||
option.cropOutputImageHeight = PORTRAIT_IMAGE_WIDTH;
|
||||
option.outputPath = outPath;
|
||||
|
||||
PickImageHelper.pickImage(getActivity(), requestCode, option);
|
||||
option.outputPath = tempFile();
|
||||
return option;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,11 +1,8 @@
|
||||
package com.netease.nim.uikit.business.session.emoji;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -15,6 +12,8 @@ import android.widget.HorizontalScrollView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.netease.nim.uikit.R;
|
||||
import com.netease.nim.uikit.common.ui.imageview.CheckedImageButton;
|
||||
import com.netease.nim.uikit.common.util.log.LogUtil;
|
||||
@@ -47,9 +46,14 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
|
||||
private HorizontalScrollView scrollView;
|
||||
|
||||
private LinearLayout tabView;
|
||||
|
||||
// 添加各个tab按钮
|
||||
OnClickListener tabCheckListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onEmoticonBtnChecked(v.getId());
|
||||
}
|
||||
};
|
||||
private int categoryIndex;
|
||||
|
||||
private Handler uiHandler;
|
||||
|
||||
public EmoticonPickerView(Context context) {
|
||||
@@ -64,17 +68,14 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
|
||||
init(context);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public EmoticonPickerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
this.context = context;
|
||||
this.uiHandler = new Handler(context.getMainLooper());
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.nim_emoji_layout, this);
|
||||
}
|
||||
@@ -91,41 +92,26 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
|
||||
}
|
||||
|
||||
public void show(IEmoticonSelectedListener listener) {
|
||||
setListener(listener);
|
||||
|
||||
this.listener = listener;
|
||||
if (loaded)
|
||||
return;
|
||||
loadStickers();
|
||||
loaded = true;
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
public void setListener(IEmoticonSelectedListener listener) {
|
||||
if (listener != null) {
|
||||
this.listener = listener;
|
||||
if (!withSticker) {
|
||||
showEmojiView();
|
||||
} else {
|
||||
LogUtil.i("sticker", "listener is null");
|
||||
onEmoticonBtnChecked(0);
|
||||
setSelectedVisible(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupEmojView() {
|
||||
currentEmojiPage = (ViewPager) findViewById(R.id.scrPlugin);
|
||||
pageNumberLayout = (LinearLayout) findViewById(R.id.layout_scr_bottom);
|
||||
tabView = (LinearLayout) findViewById(R.id.emoj_tab_view);
|
||||
scrollView = (HorizontalScrollView) findViewById(R.id.emoj_tab_view_container);
|
||||
|
||||
findViewById(R.id.top_divider_line).setVisibility(View.VISIBLE);
|
||||
currentEmojiPage = findViewById(R.id.scrPlugin);
|
||||
pageNumberLayout = findViewById(R.id.layout_scr_bottom);
|
||||
tabView = findViewById(R.id.emoj_tab_view);
|
||||
scrollView = findViewById(R.id.emoj_tab_view_container);
|
||||
}
|
||||
|
||||
// 添加各个tab按钮
|
||||
OnClickListener tabCheckListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onEmoticonBtnChecked(v.getId());
|
||||
}
|
||||
};
|
||||
|
||||
private void loadStickers() {
|
||||
if (!withSticker) {
|
||||
scrollView.setVisibility(View.GONE);
|
||||
@@ -151,7 +137,6 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private CheckedImageButton addEmoticonTabBtn(int index, OnClickListener listener) {
|
||||
CheckedImageButton emotBtn = new CheckedImageButton(context);
|
||||
emotBtn.setNormalBkResId(R.drawable.nim_sticker_button_background_normal_layer_list);
|
||||
@@ -232,19 +217,6 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
|
||||
gifView.showEmojis();
|
||||
}
|
||||
|
||||
private void show() {
|
||||
if (listener == null) {
|
||||
LogUtil.i("sticker", "show picker view when listener is null");
|
||||
}
|
||||
if (!withSticker) {
|
||||
showEmojiView();
|
||||
} else {
|
||||
onEmoticonBtnChecked(0);
|
||||
setSelectedVisible(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setSelectedVisible(final int index) {
|
||||
final Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
|
@@ -18,6 +18,60 @@ import org.greenrobot.eventbus.EventBus;
|
||||
*/
|
||||
public class PickImageHelper {
|
||||
|
||||
/**
|
||||
* 打开图片选择器
|
||||
*/
|
||||
public static void pickImage(final Context context, final int requestCode, final PickImageOption option) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomAlertDialog dialog = new CustomAlertDialog(context);
|
||||
dialog.setTitle(option.titleResId);
|
||||
|
||||
dialog.addItem(context.getString(R.string.input_panel_take), () -> pickCamera(context, requestCode, option));
|
||||
|
||||
dialog.addItem(context.getString(R.string.choose_from_photo_album), () -> pickPhoto(context, requestCode, option));
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开图片选择器
|
||||
*/
|
||||
public static void pickPhoto(final Context context, final int requestCode, final PickImageOption option) {
|
||||
NimImageActionEvent event = new NimImageActionEvent();
|
||||
event.setSuccess(o -> {
|
||||
int from = PickImageActivity.FROM_LOCAL;
|
||||
if (!option.crop) {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect,
|
||||
option.multiSelectMaxCount, true, false, 0, 0);
|
||||
} else {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
|
||||
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开相机发送图片
|
||||
*/
|
||||
public static void pickCamera(final Context context, final int requestCode, final PickImageOption option) {
|
||||
NimImageActionEvent event = new NimImageActionEvent();
|
||||
event.setSuccess(o -> {
|
||||
int from = PickImageActivity.FROM_CAMERA;
|
||||
if (!option.crop) {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect, 1,
|
||||
true, false, 0, 0);
|
||||
} else {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
|
||||
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
|
||||
public static class PickImageOption {
|
||||
/**
|
||||
* 图片选择器标题
|
||||
@@ -55,53 +109,5 @@ public class PickImageHelper {
|
||||
public String outputPath = StorageUtil.getWritePath(StringUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开图片选择器
|
||||
*/
|
||||
public static void pickImage(final Context context, final int requestCode, final PickImageOption option) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomAlertDialog dialog = new CustomAlertDialog(context);
|
||||
dialog.setTitle(option.titleResId);
|
||||
|
||||
dialog.addItem(context.getString(R.string.input_panel_take), new CustomAlertDialog.onSeparateItemClickListener() {
|
||||
@Override
|
||||
public void onClick() {
|
||||
NimImageActionEvent event = new NimImageActionEvent();
|
||||
event.setSuccess(o -> {
|
||||
int from = PickImageActivity.FROM_CAMERA;
|
||||
if (!option.crop) {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect, 1,
|
||||
true, false, 0, 0);
|
||||
} else {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
|
||||
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.addItem(context.getString(R.string.choose_from_photo_album), new CustomAlertDialog.onSeparateItemClickListener() {
|
||||
@Override
|
||||
public void onClick() {
|
||||
NimImageActionEvent event = new NimImageActionEvent();
|
||||
event.setSuccess(o -> {
|
||||
int from = PickImageActivity.FROM_LOCAL;
|
||||
if (!option.crop) {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect,
|
||||
option.multiSelectMaxCount, true, false, 0, 0);
|
||||
} else {
|
||||
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
|
||||
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
@@ -1,36 +0,0 @@
|
||||
package com.netease.nim.uikit.impl.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.netease.nim.uikit.api.NimUIKit;
|
||||
|
||||
/**
|
||||
* Created by hzxuwen on 2015/10/21.
|
||||
*/
|
||||
public class UserPreferences {
|
||||
|
||||
private final static String KEY_EARPHONE_MODE = "KEY_EARPHONE_MODE";
|
||||
|
||||
public static void setEarPhoneModeEnable(boolean on) {
|
||||
saveBoolean(KEY_EARPHONE_MODE, on);
|
||||
}
|
||||
|
||||
public static boolean isEarPhoneModeEnable() {
|
||||
return getBoolean(KEY_EARPHONE_MODE, true);
|
||||
}
|
||||
|
||||
private static boolean getBoolean(String key, boolean value) {
|
||||
return getSharedPreferences().getBoolean(key, value);
|
||||
}
|
||||
|
||||
private static void saveBoolean(String key, boolean value) {
|
||||
SharedPreferences.Editor editor = getSharedPreferences().edit();
|
||||
editor.putBoolean(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private static SharedPreferences getSharedPreferences() {
|
||||
return NimUIKit.getContext().getSharedPreferences("UIKit." + NimUIKit.getAccount(), Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
@@ -1,204 +0,0 @@
|
||||
package com.netease.nim.uikit.support.permission;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BaseMPermission {
|
||||
|
||||
private static final String TAG = "MPermission";
|
||||
|
||||
public enum MPermissionResultEnum {
|
||||
GRANTED, DENIED, DENIED_NEVER_ASK_AGAIN
|
||||
}
|
||||
|
||||
static boolean isOverMarshmallow() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
|
||||
}
|
||||
|
||||
static Activity getActivity(Object object) {
|
||||
if (object instanceof Fragment) {
|
||||
return ((Fragment) object).getActivity();
|
||||
} else if (object instanceof Activity) {
|
||||
return (Activity) object;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限请求结果
|
||||
*/
|
||||
public static List<MPermissionResultEnum> getPermissionResult(Activity activity, String[] permissions) {
|
||||
return findPermissionResult(activity, permissions);
|
||||
}
|
||||
|
||||
public static List<MPermissionResultEnum> getPermissionResult(Fragment fragment, String[] permissions) {
|
||||
return findPermissionResult(fragment.getActivity(), permissions);
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
private static List<MPermissionResultEnum> findPermissionResult(Activity activity, String... permissions) {
|
||||
boolean overM = isOverMarshmallow();
|
||||
List<MPermissionResultEnum> result = new ArrayList<>();
|
||||
for (String p : permissions) {
|
||||
if (overM) {
|
||||
if (activity.checkSelfPermission(p) == PackageManager.PERMISSION_GRANTED) {
|
||||
result.add(MPermissionResultEnum.GRANTED);
|
||||
} else {
|
||||
if (!activity.shouldShowRequestPermissionRationale(p)) {
|
||||
result.add(MPermissionResultEnum.DENIED_NEVER_ASK_AGAIN);
|
||||
} else {
|
||||
result.add(MPermissionResultEnum.DENIED);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.add(MPermissionResultEnum.GRANTED);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有被未被授权的权限
|
||||
*/
|
||||
public static List<String> getDeniedPermissions(Activity activity, String[] permissions) {
|
||||
return findDeniedPermissions(activity, permissions);
|
||||
}
|
||||
|
||||
public static List<String> getDeniedPermissions(Fragment fragment, String[] permissions) {
|
||||
return findDeniedPermissions(fragment.getActivity(), permissions);
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
static List<String> findDeniedPermissions(Activity activity, String... permissions) {
|
||||
if (!isOverMarshmallow()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> denyPermissions = new ArrayList<>();
|
||||
for (String value : permissions) {
|
||||
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED) {
|
||||
denyPermissions.add(value);
|
||||
}
|
||||
}
|
||||
return denyPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取被拒绝且勾选不再询问的权限
|
||||
* 请在请求权限结果回调中使用,因为从未请求过的权限也会被认为是该结果集
|
||||
*/
|
||||
public static List<String> getNeverAskAgainPermissions(Activity activity, String[] permissions) {
|
||||
return findNeverAskAgainPermissions(activity, permissions);
|
||||
}
|
||||
|
||||
public static List<String> getNeverAskAgainPermissions(Fragment fragment, String[] permissions) {
|
||||
return findNeverAskAgainPermissions(fragment.getActivity(), permissions);
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
private static List<String> findNeverAskAgainPermissions(Activity activity, String... permissions) {
|
||||
if (!isOverMarshmallow()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> neverAskAgainPermission = new ArrayList<>();
|
||||
for (String value : permissions) {
|
||||
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
|
||||
!activity.shouldShowRequestPermissionRationale(value)) {
|
||||
// 拒绝&不要需要解释了(用户勾选了不再询问)
|
||||
// 坑爹:第一次不做任何设置,返回值也是false。建议在权限授权结果里判断!!!
|
||||
neverAskAgainPermission.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return neverAskAgainPermission;
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
static boolean hasNeverAskAgainPermission(Activity activity, List<String> permission) {
|
||||
if (!isOverMarshmallow()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String value : permission) {
|
||||
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
|
||||
!activity.shouldShowRequestPermissionRationale(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取被拒绝但没有勾选不再询问的权限(可以继续申请,会继续弹框)
|
||||
*/
|
||||
public static List<String> getDeniedPermissionsWithoutNeverAskAgain(Activity activity, String[] permissions) {
|
||||
return findDeniedPermissionWithoutNeverAskAgain(activity, permissions);
|
||||
}
|
||||
|
||||
public static List<String> getDeniedPermissionsWithoutNeverAskAgain(Fragment fragment, String[] permissions) {
|
||||
return findDeniedPermissionWithoutNeverAskAgain(fragment.getActivity(), permissions);
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
private static List<String> findDeniedPermissionWithoutNeverAskAgain(Activity activity, String... permission) {
|
||||
if (!isOverMarshmallow()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> denyPermissions = new ArrayList<>();
|
||||
for (String value : permission) {
|
||||
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
|
||||
activity.shouldShowRequestPermissionRationale(value)) {
|
||||
denyPermissions.add(value); // 上次申请被用户拒绝了
|
||||
}
|
||||
}
|
||||
|
||||
return denyPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log专用
|
||||
*/
|
||||
public static void printMPermissionResult(boolean preRequest, Activity activity, String[] permissions) {
|
||||
Log.i(TAG, "----- MPermission result " + (preRequest ? "before" : "after") + " request:");
|
||||
List<BaseMPermission.MPermissionResultEnum> result = getPermissionResult(activity, permissions);
|
||||
int i = 0;
|
||||
for (BaseMPermission.MPermissionResultEnum p : result) {
|
||||
Log.i(TAG, "* MPermission=" + permissions[i++] + ", result=" + p);
|
||||
}
|
||||
}
|
||||
|
||||
static String toString(List<String> permission) {
|
||||
if (permission == null || permission.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return toString(permission.toArray(new String[permission.size()]));
|
||||
}
|
||||
|
||||
private static String toString(String[] permission) {
|
||||
if (permission == null || permission.length <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String p : permission) {
|
||||
sb.append(p.replaceFirst("android.permission.", ""));
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@@ -1,170 +0,0 @@
|
||||
package com.netease.nim.uikit.support.permission;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionDenied;
|
||||
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionGranted;
|
||||
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionNeverAskAgain;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MPermission extends BaseMPermission {
|
||||
|
||||
private int requestCode;
|
||||
private String[] permissions;
|
||||
private Object object; // activity or fragment
|
||||
|
||||
private MPermission(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public static MPermission with(Activity activity) {
|
||||
return new MPermission(activity);
|
||||
}
|
||||
|
||||
public static MPermission with(Fragment fragment) {
|
||||
return new MPermission(fragment);
|
||||
}
|
||||
|
||||
public MPermission setRequestCode(int requestCode) {
|
||||
this.requestCode = requestCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPermission permissions(String... permissions) {
|
||||
this.permissions = permissions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ********************* request *********************
|
||||
*/
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
public void request() {
|
||||
doRequestPermissions(object, requestCode, permissions);
|
||||
}
|
||||
|
||||
@TargetApi(value = Build.VERSION_CODES.M)
|
||||
private static void doRequestPermissions(Object object, int requestCode, String[] permissions) {
|
||||
if (!isOverMarshmallow()) {
|
||||
doExecuteSuccess(object, requestCode);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> deniedPermissions = findDeniedPermissions(getActivity(object), permissions);
|
||||
if (deniedPermissions != null && deniedPermissions.size() > 0) {
|
||||
if (object instanceof Activity) {
|
||||
((Activity) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
|
||||
} else if (object instanceof Fragment) {
|
||||
((Fragment) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
|
||||
} else {
|
||||
throw new IllegalArgumentException(object.getClass().getName() + " is not supported");
|
||||
}
|
||||
} else {
|
||||
doExecuteSuccess(object, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ********************* on result *********************
|
||||
*/
|
||||
|
||||
public static void onRequestPermissionsResult(Activity activity, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
dispatchResult(activity, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
public static void onRequestPermissionsResult(Fragment fragment, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
dispatchResult(fragment, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private static void dispatchResult(Object obj, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
List<String> deniedPermissions = new ArrayList<>();
|
||||
for (int i = 0; i < grantResults.length; i++) {
|
||||
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
|
||||
deniedPermissions.add(permissions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (deniedPermissions.size() > 0) {
|
||||
if (hasNeverAskAgainPermission(getActivity(obj), deniedPermissions)) {
|
||||
doExecuteFailAsNeverAskAgain(obj, requestCode);
|
||||
} else {
|
||||
doExecuteFail(obj, requestCode);
|
||||
}
|
||||
} else {
|
||||
doExecuteSuccess(obj, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ********************* reflect execute result *********************
|
||||
*/
|
||||
|
||||
private static void doExecuteSuccess(Object activity, int requestCode) {
|
||||
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionGranted.class, requestCode));
|
||||
}
|
||||
|
||||
private static void doExecuteFail(Object activity, int requestCode) {
|
||||
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionDenied.class, requestCode));
|
||||
}
|
||||
|
||||
private static void doExecuteFailAsNeverAskAgain(Object activity, int requestCode) {
|
||||
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionNeverAskAgain.class, requestCode));
|
||||
}
|
||||
|
||||
private static <A extends Annotation> Method findMethodWithRequestCode(Class clazz, Class<A> annotation, int
|
||||
requestCode) {
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.getAnnotation(annotation) != null &&
|
||||
isEqualRequestCodeFromAnnotation(method, annotation, requestCode)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isEqualRequestCodeFromAnnotation(Method m, Class clazz, int requestCode) {
|
||||
if (clazz.equals(OnMPermissionDenied.class)) {
|
||||
return requestCode == m.getAnnotation(OnMPermissionDenied.class).value();
|
||||
} else if (clazz.equals(OnMPermissionGranted.class)) {
|
||||
return requestCode == m.getAnnotation(OnMPermissionGranted.class).value();
|
||||
} else if (clazz.equals(OnMPermissionNeverAskAgain.class)) {
|
||||
return requestCode == m.getAnnotation(OnMPermissionNeverAskAgain.class).value();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ********************* reflect execute method *********************
|
||||
*/
|
||||
|
||||
private static void executeMethod(Object activity, Method executeMethod) {
|
||||
executeMethodWithParam(activity, executeMethod, new Object[]{});
|
||||
}
|
||||
|
||||
private static void executeMethodWithParam(Object activity, Method executeMethod, Object... args) {
|
||||
if (executeMethod != null) {
|
||||
try {
|
||||
if (!executeMethod.isAccessible()) {
|
||||
executeMethod.setAccessible(true);
|
||||
}
|
||||
executeMethod.invoke(activity, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package com.netease.nim.uikit.support.permission.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* register a method invoked when permission requests are denied without check never ask again.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface OnMPermissionDenied {
|
||||
int value();
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package com.netease.nim.uikit.support.permission.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* register a method invoked when permission requests are succeeded.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface OnMPermissionGranted {
|
||||
int value();
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package com.netease.nim.uikit.support.permission.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* register some methods handling the user's choice to permanently deny permissions checking never ask again.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface OnMPermissionNeverAskAgain {
|
||||
int value();
|
||||
}
|
Reference in New Issue
Block a user