Commit 2e7fb8e9 by zhengnw@sobot.com

google 分支使用特制的widget 版本1.2.8.3

parent 04b868ae
...@@ -293,13 +293,7 @@ public class MainActivity extends SobotBaseActivity { ...@@ -293,13 +293,7 @@ public class MainActivity extends SobotBaseActivity {
// openAlbum(); // openAlbum();
// } // }
// }; // };
if (checkIsShowPermissionPop(getString(R.string.sobot_memory_card), getString(R.string.sobot_memory_card_yongtu), 1, 4)) {
return;
}
if (!checkStoragePermission(4)) {
return;
}
openAlbum();
// selectPicFromLocal(); // selectPicFromLocal();
// preview(); // preview();
......
...@@ -12,7 +12,7 @@ task androidSourcesJar(type: Jar) { ...@@ -12,7 +12,7 @@ task androidSourcesJar(type: Jar) {
ext { ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名 PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'widget_x' //项目名 PUBLISH_ARTIFACT_ID = 'widget_x' //项目名
PUBLISH_VERSION = '1.2.9' //版本号 PUBLISH_VERSION = '1.2.8.3' //版本号
} }
......
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
<!-- 访问权限 --> <!-- 访问权限 -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS" /> <uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
......
package androidx.lifecycle;
import androidx.annotation.NonNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static androidx.lifecycle.Lifecycle.State.CREATED;
import static androidx.lifecycle.Lifecycle.State.DESTROYED;
/**
* Created by liaohailiang on 2019/3/7.
*/
public class ExternalLiveData<T> extends MutableLiveData<T> {
public static final int START_VERSION = LiveData.START_VERSION;
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
try {
//use ExternalLifecycleBoundObserver instead of LifecycleBoundObserver
LifecycleBoundObserver wrapper = new ExternalLifecycleBoundObserver(owner, observer);
LifecycleBoundObserver existing = (LifecycleBoundObserver) callMethodPutIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
public int getVersion() {
return super.getVersion();
}
/**
* determine when the observer is active, means the observer can receive message
* the default value is CREATED, means if the observer's state is above create,
* for example, the onCreate() of activity is called
* you can change this value to CREATED/STARTED/RESUMED
* determine on witch state, you can receive message
*
* @return Lifecycle.State
*/
protected Lifecycle.State observerActiveLevel() {
return CREATED;
}
class ExternalLifecycleBoundObserver extends LifecycleBoundObserver {
ExternalLifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(owner, observer);
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(observerActiveLevel());
}
}
private Object getFieldObservers() throws Exception {
Field fieldObservers = LiveData.class.getDeclaredField("mObservers");
fieldObservers.setAccessible(true);
return fieldObservers.get(this);
}
private Object callMethodPutIfAbsent(Object observer, Object wrapper) throws Exception {
Object mObservers = getFieldObservers();
Class<?> classOfSafeIterableMap = mObservers.getClass();
Method putIfAbsent = classOfSafeIterableMap.getDeclaredMethod("putIfAbsent",
Object.class, Object.class);
putIfAbsent.setAccessible(true);
return putIfAbsent.invoke(mObservers, observer, wrapper);
}
}
package com.sobot.widget.livedatabus;
import androidx.annotation.NonNull;
import com.sobot.widget.livedatabus.core.Config;
import com.sobot.widget.livedatabus.core.LiveEvent;
import com.sobot.widget.livedatabus.core.LiveEventBusCore;
import com.sobot.widget.livedatabus.core.Observable;
import com.sobot.widget.livedatabus.core.ObservableConfig;
public class SobotLiveEventBus {
/**
* get observable by key with type
*
* @param key key
* @param type type
* @param <T> T
* @return Observable
*/
public static <T> Observable<T> get(@NonNull String key, @NonNull Class<T> type) {
return LiveEventBusCore.get().with(key, type);
}
/**
* get observable by key
*
* @param key String
* @param <T> T
* @return Observable
*/
public static <T> Observable<T> get(@NonNull String key) {
return (Observable<T>) get(key, Object.class);
}
/**
* get observable from eventType
*
* @param eventType Class
* @param <T> T
* @return Observable
*/
public static <T extends LiveEvent> Observable<T> get(@NonNull Class<T> eventType) {
return get(eventType.getName(), eventType);
}
/**
* use the inner class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
* @return Config
*/
public static Config config() {
return LiveEventBusCore.get().config();
}
/**
* use the inner class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
* @param key String
* @return Config
*/
public static ObservableConfig config(@NonNull String key) {
return LiveEventBusCore.get().config(key);
}
}
\ No newline at end of file
package com.sobot.widget.livedatabus.core;
import android.content.Context;
import androidx.annotation.NonNull;
import com.sobot.widget.livedatabus.logger.Logger;
import com.sobot.widget.livedatabus.utils.AppUtils;
public class Config {
/**
* lifecycleObserverAlwaysActive
* set if then observer can always receive message
* true: observer can always receive message
* false: observer can only receive message when resumed
*
* @param active boolean
* @return Config
*/
public Config lifecycleObserverAlwaysActive(boolean active) {
LiveEventBusCore.get().setLifecycleObserverAlwaysActive(active);
return this;
}
/**
* @param clear boolean
* @return true: clear livedata when no observer observe it
* false: not clear livedata unless app was killed
*/
public Config autoClear(boolean clear) {
LiveEventBusCore.get().setAutoClear(clear);
return this;
}
/**
* config broadcast
* only if you called this method, you can use broadcastValue() to send broadcast message
*
* @param context Context
* @return Config
*/
public Config setContext(Context context) {
AppUtils.init(context);
LiveEventBusCore.get().registerReceiver();
return this;
}
/**
* setLogger, if not set, use DefaultLogger
*
* @param logger Logger
* @return Config
*/
public Config setLogger(@NonNull Logger logger) {
LiveEventBusCore.get().setLogger(logger);
return this;
}
/**
* set logger enable or disable, default enable
*
* @param enable boolean
* @return Config
*/
public Config enableLogger(boolean enable) {
LiveEventBusCore.get().enableLogger(enable);
return this;
}
}
package com.sobot.widget.livedatabus.core;
/**
* 调试信息控制台
*/
public final class Console {
private Console() {
}
/**
* 获取控制台信息
*
* @return 调试信息
*/
public static String getInfo() {
return LiveEventBusCore.get().console.getConsoleInfo();
}
}
package com.sobot.widget.livedatabus.core;
import java.io.Serializable;
public interface LiveEvent extends Serializable {
}
package com.sobot.widget.livedatabus.core;
import static android.content.Context.RECEIVER_EXPORTED;
import android.annotation.SuppressLint;
import android.app.Application;
import androidx.lifecycle.ExternalLiveData;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import com.sobot.widget.livedatabus.ipc.core.ProcessorManager;
import com.sobot.widget.livedatabus.ipc.receiver.LebIpcReceiver;
import com.sobot.widget.livedatabus.logger.DefaultLogger;
import com.sobot.widget.livedatabus.logger.Logger;
import com.sobot.widget.livedatabus.logger.LoggerManager;
import com.sobot.widget.livedatabus.utils.AppUtils;
import com.sobot.widget.livedatabus.utils.ThreadUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
/**
* LiveEventBusCore
*/
public final class LiveEventBusCore {
/**
* 单例模式实现
*/
private static class SingletonHolder {
private static final LiveEventBusCore DEFAULT_BUS = new LiveEventBusCore();
}
public static LiveEventBusCore get() {
return SingletonHolder.DEFAULT_BUS;
}
/**
* 存放LiveEvent
*/
private final Map<String, LiveEvent<Object>> bus;
/**
* 可配置的项
*/
private final Config config = new Config();
private boolean lifecycleObserverAlwaysActive;
private boolean autoClear;
private LoggerManager logger;
private final Map<String, ObservableConfig> observableConfigs;
/**
* 跨进程通信
*/
private LebIpcReceiver receiver;
private boolean isRegisterReceiver = false;
/**
* 调试
*/
final InnerConsole console = new InnerConsole();
private LiveEventBusCore() {
bus = new HashMap<>();
observableConfigs = new HashMap<>();
lifecycleObserverAlwaysActive = true;
autoClear = false;
logger = new LoggerManager(new DefaultLogger());
receiver = new LebIpcReceiver();
registerReceiver();
}
public synchronized <T> Observable<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new LiveEvent<>(key));
}
return (Observable<T>) bus.get(key);
}
/**
* use the class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
*
* @return Config
*/
public Config config() {
return config;
}
public ObservableConfig config(String key) {
if (!observableConfigs.containsKey(key)) {
observableConfigs.put(key, new ObservableConfig());
}
return observableConfigs.get(key);
}
void setLogger(@NonNull Logger logger) {
this.logger.setLogger(logger);
}
void enableLogger(boolean enable) {
this.logger.setEnable(enable);
}
@SuppressLint("WrongConstant")
void registerReceiver() {
if (isRegisterReceiver) {
return;
}
Application application = AppUtils.getApp();
if (application != null) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(IpcConst.ACTION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
application.registerReceiver(receiver, intentFilter, RECEIVER_EXPORTED);
}
else {
// api <= 32
application.registerReceiver(receiver, intentFilter);
}
isRegisterReceiver = true;
}
}
void setLifecycleObserverAlwaysActive(boolean lifecycleObserverAlwaysActive) {
this.lifecycleObserverAlwaysActive = lifecycleObserverAlwaysActive;
}
void setAutoClear(boolean autoClear) {
this.autoClear = autoClear;
}
private class LiveEvent<T> implements Observable<T> {
@NonNull
private final String key;
private final LifecycleLiveData<T> liveData;
private final Map<Observer, ObserverWrapper<T>> observerMap = new HashMap<>();
private final Handler mainHandler = new Handler(Looper.getMainLooper());
LiveEvent(@NonNull String key) {
this.key = key;
this.liveData = new LifecycleLiveData<>(key);
}
/**
* 进程内发送消息
*
* @param value 发送的消息
*/
@Override
public void post(T value) {
if (ThreadUtils.isMainThread()) {
postInternal(value);
} else {
mainHandler.post(new PostValueTask(value));
}
}
/**
* App内发送消息,跨进程使用
*
* @param value 发送的消息
*/
@Override
public void postAcrossProcess(T value) {
broadcast(value, false, true);
}
/**
* App之间发送消息
*
* @param value 发送的消息
*/
@Override
public void postAcrossApp(T value) {
broadcast(value, false, false);
}
/**
* 进程内发送消息,延迟发送
*
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
@Override
public void postDelay(T value, long delay) {
mainHandler.postDelayed(new PostValueTask(value), delay);
}
/**
* 进程内发送消息,延迟发送,带生命周期
* 如果延时发送消息的时候sender处于非激活状态,消息取消发送
*
* @param owner 消息发送者
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
@Override
public void postDelay(LifecycleOwner owner, final T value, long delay) {
mainHandler.postDelayed(new PostLifeValueTask(value, owner), delay);
}
/**
* 进程内发送消息
* 强制接收到消息的顺序和发送顺序一致
*
* @param value 发送的消息
*/
@Override
public void postOrderly(T value) {
mainHandler.post(new PostValueTask(value));
}
/**
* App之间发送消息
*
* @param value 发送的消息
*/
@Override
@Deprecated
public void broadcast(T value) {
broadcast(value, false, false);
}
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
*
* @param value 发送的消息
* @param foreground true:前台广播、false:后台广播
* @param onlyInApp true:只在APP内有效、false:全局有效
*/
@Override
public void broadcast(final T value, final boolean foreground, final boolean onlyInApp) {
if (AppUtils.getApp() != null) {
if (ThreadUtils.isMainThread()) {
broadcastInternal(value, foreground, onlyInApp);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
broadcastInternal(value, foreground, onlyInApp);
}
});
}
} else {
post(value);
}
}
/**
* 注册一个Observer,生命周期感知,自动取消订阅
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
@Override
public void observe(@NonNull final LifecycleOwner owner, @NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeInternal(owner, observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeInternal(owner, observer);
}
});
}
}
/**
* 注册一个Observer,生命周期感知,自动取消订阅
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
@Override
public void observeSticky(@NonNull final LifecycleOwner owner, @NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeStickyInternal(owner, observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeStickyInternal(owner, observer);
}
});
}
}
/**
* 注册一个Observer,需手动解除绑定
*
* @param observer 观察者
*/
@Override
public void observeForever(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeForeverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeForeverInternal(observer);
}
});
}
}
/**
* 注册一个Observer,需手动解除绑定
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param observer 观察者
*/
@Override
public void observeStickyForever(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeStickyForeverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeStickyForeverInternal(observer);
}
});
}
}
/**
* 通过observeForever或observeStickyForever注册的,需要调用该方法取消订阅
*
* @param observer 观察者
*/
@Override
public void removeObserver(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
removeObserverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
removeObserverInternal(observer);
}
});
}
}
@MainThread
private void postInternal(T value) {
logger.log(Level.INFO, "post: " + value + " with key: " + key);
liveData.setValue(value);
}
@MainThread
private void broadcastInternal(T value, boolean foreground, boolean onlyInApp) {
logger.log(Level.INFO, "broadcast: " + value + " foreground: " + foreground +
" with key: " + key);
Application application = AppUtils.getApp();
if (application == null) {
logger.log(Level.WARNING, "application is null, you can try setContext() when config");
return;
}
Intent intent = new Intent(IpcConst.ACTION);
if (foreground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
}
if (onlyInApp) {
intent.setPackage(application.getPackageName());
}
intent.putExtra(IpcConst.KEY, key);
boolean handle = ProcessorManager.getManager().writeTo(intent, value);
try {
if (handle) {
application.sendBroadcast(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@MainThread
private void observeInternal(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerWrapper.preventNextEvent = liveData.getVersion() > ExternalLiveData.START_VERSION;
liveData.observe(owner, observerWrapper);
logger.log(Level.INFO, "observe observer: " + observerWrapper + "(" + observer + ")"
+ " on owner: " + owner + " with key: " + key);
}
@MainThread
private void observeStickyInternal(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
liveData.observe(owner, observerWrapper);
logger.log(Level.INFO, "observe sticky observer: " + observerWrapper + "(" + observer + ")"
+ " on owner: " + owner + " with key: " + key);
}
@MainThread
private void observeForeverInternal(@NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerWrapper.preventNextEvent = liveData.getVersion() > ExternalLiveData.START_VERSION;
observerMap.put(observer, observerWrapper);
liveData.observeForever(observerWrapper);
logger.log(Level.INFO, "observe forever observer: " + observerWrapper + "(" + observer + ")"
+ " with key: " + key);
}
@MainThread
private void observeStickyForeverInternal(@NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerMap.put(observer, observerWrapper);
liveData.observeForever(observerWrapper);
logger.log(Level.INFO, "observe sticky forever observer: " + observerWrapper + "(" + observer + ")"
+ " with key: " + key);
}
@MainThread
private void removeObserverInternal(@NonNull Observer<T> observer) {
Observer<T> realObserver;
if (observerMap.containsKey(observer)) {
realObserver = observerMap.remove(observer);
} else {
realObserver = observer;
}
liveData.removeObserver(realObserver);
}
private class LifecycleLiveData<T> extends ExternalLiveData<T> {
private final String key;
public LifecycleLiveData(String key) {
this.key = key;
}
@Override
protected Lifecycle.State observerActiveLevel() {
return lifecycleObserverAlwaysActive() ? Lifecycle.State.CREATED : Lifecycle.State.STARTED;
}
@Override
public void removeObserver(@NonNull Observer<? super T> observer) {
super.removeObserver(observer);
if (autoClear() && !liveData.hasObservers()) {
LiveEventBusCore.get().bus.remove(key);
}
logger.log(Level.INFO, "observer removed: " + observer);
}
private boolean lifecycleObserverAlwaysActive() {
if (observableConfigs.containsKey(key)) {
ObservableConfig config = observableConfigs.get(key);
if (config.lifecycleObserverAlwaysActive != null) {
return config.lifecycleObserverAlwaysActive;
}
}
return lifecycleObserverAlwaysActive;
}
private boolean autoClear() {
if (observableConfigs.containsKey(key)) {
ObservableConfig config = observableConfigs.get(key);
if (config.autoClear != null) {
return config.autoClear;
}
}
return autoClear;
}
}
private class PostValueTask implements Runnable {
private Object newValue;
public PostValueTask(@NonNull Object newValue) {
this.newValue = newValue;
}
@Override
public void run() {
postInternal((T) newValue);
}
}
private class PostLifeValueTask implements Runnable {
private Object newValue;
private LifecycleOwner owner;
public PostLifeValueTask(@NonNull Object newValue, @Nullable LifecycleOwner owner) {
this.newValue = newValue;
this.owner = owner;
}
@Override
public void run() {
if (owner != null) {
if (owner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
postInternal((T) newValue);
}
}
}
}
}
private class ObserverWrapper<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
private boolean preventNextEvent = false;
ObserverWrapper(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (preventNextEvent) {
preventNextEvent = false;
return;
}
logger.log(Level.INFO, "message received: " + t);
try {
observer.onChanged(t);
} catch (ClassCastException e) {
logger.log(Level.WARNING, "class cast error on message received: " + t, e);
} catch (Exception e) {
logger.log(Level.WARNING, "error on message received: " + t, e);
}
}
}
class InnerConsole {
String getConsoleInfo() {
StringBuilder sb = new StringBuilder();
sb.append("*********Base info*********").append("\n");
sb.append(getBaseInfo());
sb.append("*********Event info*********").append("\n");
sb.append(getBusInfo());
return sb.toString();
}
String getBaseInfo() {
StringBuilder sb = new StringBuilder();
sb.append("lifecycleObserverAlwaysActive: ").append(lifecycleObserverAlwaysActive).append("\n")
.append("autoClear: ").append(autoClear).append("\n")
.append("logger enable: ").append(logger.isEnable()).append("\n")
.append("logger: ").append(logger.getLogger()).append("\n")
.append("Receiver register: ").append(isRegisterReceiver).append("\n")
.append("Application: ").append(AppUtils.getApp()).append("\n");
return sb.toString();
}
String getBusInfo() {
StringBuilder sb = new StringBuilder();
for (String key : bus.keySet()) {
sb.append("Event name: " + key).append("\n");
ExternalLiveData liveData = bus.get(key).liveData;
sb.append("\tversion: " + liveData.getVersion()).append("\n");
sb.append("\thasActiveObservers: " + liveData.hasActiveObservers()).append("\n");
sb.append("\thasObservers: " + liveData.hasObservers()).append("\n");
sb.append("\tActiveCount: " + getActiveCount(liveData)).append("\n");
sb.append("\tObserverCount: " + getObserverCount(liveData)).append("\n");
sb.append("\tObservers: ").append("\n");
sb.append("\t\t" + getObserverInfo(liveData)).append("\n");
}
return sb.toString();
}
private int getActiveCount(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mActiveCount");
field.setAccessible(true);
return (int) field.get(liveData);
} catch (Exception e) {
return -1;
}
}
private int getObserverCount(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mObservers");
field.setAccessible(true);
Object mObservers = field.get(liveData);
Class<?> classOfSafeIterableMap = mObservers.getClass();
Method size = classOfSafeIterableMap.getDeclaredMethod("size");
size.setAccessible(true);
return (int) size.invoke(mObservers);
} catch (Exception e) {
return -1;
}
}
private String getObserverInfo(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mObservers");
field.setAccessible(true);
Object mObservers = field.get(liveData);
return mObservers.toString();
} catch (Exception e) {
return "";
}
}
}
}
package com.sobot.widget.livedatabus.core;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.annotation.NonNull;
public interface Observable<T> {
/**
* 进程内发送消息
*
* @param value 发送的消息
*/
void post(T value);
/**
* App内发送消息,跨进程使用
*
* @param value 发送的消息
*/
void postAcrossProcess(T value);
/**
* App之间发送消息
*
* @param value 发送的消息
*/
void postAcrossApp(T value);
/**
* 进程内发送消息,延迟发送
*
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
void postDelay(T value, long delay);
/**
* 进程内发送消息,延迟发送,带生命周期
* 如果延时发送消息的时候sender处于非激活状态,消息取消发送
*
* @param sender 消息发送者
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
void postDelay(LifecycleOwner sender, T value, long delay);
/**
* 进程内发送消息
* 强制接收到消息的顺序和发送顺序一致
*
* @param value 发送的消息
*/
void postOrderly(T value);
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
* 可使用postAcrossProcess or postAcrossApp代替
*
* @param value 发送的消息
*/
@Deprecated
void broadcast(T value);
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
*
* @param value 发送的消息
* @param foreground true:前台广播、false:后台广播
* @param onlyInApp true:只在APP内有效、false:全局有效
*/
void broadcast(T value, boolean foreground, boolean onlyInApp);
/**
* 注册一个Observer,生命周期感知,自动取消订阅
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);
/**
* 注册一个Observer,生命周期感知,自动取消订阅
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);
/**
* 注册一个Observer,需手动解除绑定
*
* @param observer 观察者
*/
void observeForever(@NonNull Observer<T> observer);
/**
* 注册一个Observer,需手动解除绑定
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param observer 观察者
*/
void observeStickyForever(@NonNull Observer<T> observer);
/**
* 通过observeForever或observeStickyForever注册的,需要调用该方法取消订阅
*
* @param observer 观察者
*/
void removeObserver(@NonNull Observer<T> observer);
}
package com.sobot.widget.livedatabus.core;
public class ObservableConfig {
Boolean lifecycleObserverAlwaysActive = null;
Boolean autoClear = null;
/**
* lifecycleObserverAlwaysActive
* set if then observer can always receive message
* true: observer can always receive message
* false: observer can only receive message when resumed
*
* @param active boolean
* @return ObservableConfig
*/
public ObservableConfig lifecycleObserverAlwaysActive(boolean active) {
lifecycleObserverAlwaysActive = active;
return this;
}
/**
* @param clear boolean
* @return true: clear livedata when no observer observe it
* false: not clear livedata unless app was killed
*/
public ObservableConfig autoClear(boolean clear) {
autoClear = clear;
return this;
}
}
package com.sobot.widget.livedatabus.ipc.annotation;
import com.sobot.widget.livedatabus.ipc.core.Processor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IpcConfig {
Class<? extends Processor> processor();
}
package com.sobot.widget.livedatabus.ipc.consts;
public class IpcConst {
public static final String ACTION = "intent.action.ACTION_LEB_IPC";
public static final String KEY = "leb_ipc_key";
public static final String KEY_VALUE = "leb_ipc_value";
public static final String KEY_PROCESSOR_NAME = "leb_ipc_processor_name";
public static final String KEY_BUNDLE = "leb_ipc_bundle";
public static final String KEY_CLASS_NAME = "leb_ipc_class_name";
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class BooleanProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Boolean)) {
return false;
}
bundle.putBoolean(IpcConst.KEY_VALUE, (boolean) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getBoolean(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class DoubleProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Double)) {
return false;
}
bundle.putDouble(IpcConst.KEY_VALUE, (Double) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getDouble(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class FloatProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Float)) {
return false;
}
bundle.putFloat(IpcConst.KEY_VALUE, (float) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getFloat(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class IntProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Integer)) {
return false;
}
bundle.putInt(IpcConst.KEY_VALUE, (int) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getInt(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class LongProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Long)) {
return false;
}
bundle.putLong(IpcConst.KEY_VALUE, (long) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getLong(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import android.os.Parcelable;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class ParcelableProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Parcelable)) {
return false;
}
bundle.putParcelable(IpcConst.KEY_VALUE, (Parcelable) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getParcelable(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
public interface Processor {
boolean writeToBundle(Bundle bundle, Object value) throws Exception;
Object createFromBundle(Bundle bundle) throws Exception;
}
package com.sobot.widget.livedatabus.ipc.core;
import android.content.Intent;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.annotation.IpcConfig;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ProcessorManager {
private static class SingletonHolder {
private static final ProcessorManager INSTANCE = new ProcessorManager();
}
public static ProcessorManager getManager() {
return SingletonHolder.INSTANCE;
}
private final List<Processor> baseProcessors;
private final Map<String, Processor> processorMap;
{
baseProcessors = new LinkedList<>(Arrays.asList(
new StringProcessor(),
new IntProcessor(),
new BooleanProcessor(),
new DoubleProcessor(),
new FloatProcessor(),
new LongProcessor(),
new SerializableProcessor(),
new ParcelableProcessor()));
processorMap = new HashMap<>();
for (Processor processor : baseProcessors) {
processorMap.put(processor.getClass().getName(), processor);
}
}
private ProcessorManager() {
}
public boolean writeTo(Intent intent, Object value) {
if (intent == null || value == null) {
return false;
}
Bundle bundle = new Bundle();
boolean processed = false;
//用指定的processor处理
IpcConfig config = value.getClass().getAnnotation(IpcConfig.class);
if (config != null) {
Class<? extends Processor> processorType = config.processor();
String processorTypeName = processorType.getName();
if (!processorMap.containsKey(processorTypeName)) {
try {
processorMap.put(processorTypeName, processorType.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
Processor processor = processorMap.get(processorTypeName);
if (processor != null) {
try {
boolean handle = processor.writeToBundle(bundle, value);
if (handle) {
intent.putExtra(IpcConst.KEY_PROCESSOR_NAME, processor.getClass().getName());
intent.putExtra(IpcConst.KEY_BUNDLE, bundle);
processed = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (processed) {
return true;
}
}
//用默认的processor处理
for (Processor processor : baseProcessors) {
try {
boolean handle = processor.writeToBundle(bundle, value);
if (handle) {
intent.putExtra(IpcConst.KEY_PROCESSOR_NAME, processor.getClass().getName());
intent.putExtra(IpcConst.KEY_BUNDLE, bundle);
processed = true;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return processed;
}
public Object createFrom(Intent intent) {
if (intent == null) {
return null;
}
String processorName = intent.getStringExtra(IpcConst.KEY_PROCESSOR_NAME);
Bundle bundle = intent.getBundleExtra(IpcConst.KEY_BUNDLE);
if (processorName == null || processorName.length() == 0 || bundle == null) {
return null;
}
if (!processorMap.containsKey(processorName)) {
try {
processorMap.put(processorName, (Processor) Class.forName(processorName).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
Processor processor = processorMap.get(processorName);
if (processor == null) {
return null;
}
try {
return processor.createFromBundle(bundle);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import java.io.Serializable;
public class SerializableProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Serializable)) {
return false;
}
bundle.putSerializable(IpcConst.KEY_VALUE, (Serializable) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getSerializable(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class StringProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof String)) {
return false;
}
bundle.putString(IpcConst.KEY_VALUE, (String) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getString(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.sobot.widget.livedatabus.SobotLiveEventBus;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import com.sobot.widget.livedatabus.ipc.core.ProcessorManager;
public class LebIpcReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (IpcConst.ACTION.equals(intent.getAction())) {
try {
String key = intent.getStringExtra(IpcConst.KEY);
Object value = ProcessorManager.getManager().createFrom(intent);
if (key != null && value != null) {
SobotLiveEventBus.get(key).post(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.sobot.widget.livedatabus.logger;
import android.util.Log;
import java.util.logging.Level;
public class DefaultLogger implements Logger {
private static final String TAG = "[LiveEventBus]";
@Override
public void log(Level level, String msg) {
if (level == Level.SEVERE) {
Log.e(TAG, msg);
} else if (level == Level.WARNING) {
Log.w(TAG, msg);
} else if (level == Level.INFO) {
Log.i(TAG, msg);
} else if (level == Level.CONFIG) {
Log.d(TAG, msg);
} else if (level != Level.OFF) {
Log.v(TAG, msg);
}
}
@Override
public void log(Level level, String msg, Throwable th) {
if (level == Level.SEVERE) {
Log.e(TAG, msg, th);
} else if (level == Level.WARNING) {
Log.w(TAG, msg, th);
} else if (level == Level.INFO) {
Log.i(TAG, msg, th);
} else if (level == Level.CONFIG) {
Log.d(TAG, msg, th);
} else if (level != Level.OFF) {
Log.v(TAG, msg, th);
}
}
}
package com.sobot.widget.livedatabus.logger;
import java.util.logging.Level;
public interface Logger {
void log(Level level, String msg);
void log(Level level, String msg, Throwable th);
}
package com.sobot.widget.livedatabus.logger;
import java.util.logging.Level;
public class LoggerManager implements Logger {
private Logger logger;
private boolean enable = true;
public LoggerManager(Logger logger) {
this.logger = logger;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Logger getLogger() {
return logger;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
@Override
public void log(Level level, String msg) {
if (enable) {
logger.log(level, msg);
}
}
@Override
public void log(Level level, String msg, Throwable th) {
if (enable) {
logger.log(level, msg, th);
}
}
}
package com.sobot.widget.livedatabus.utils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.os.Bundle;
import androidx.core.content.FileProvider;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* from Github: https://github.com/Blankj/AndroidUtilCode
*/
public final class AppUtils {
private static final String PERMISSION_ACTIVITY_CLASS_NAME =
"com.blankj.utilcode.util.PermissionUtils$PermissionActivity";
private static final ActivityLifecycleImpl ACTIVITY_LIFECYCLE = new ActivityLifecycleImpl();
@SuppressLint("StaticFieldLeak")
private static Application sApplication;
private AppUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param context context
*/
public static void init(final Context context) {
if (context == null) {
init(getApplicationByReflect());
return;
}
init((Application) context.getApplicationContext());
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param app application
*/
public static void init(final Application app) {
if (sApplication == null) {
if (app == null) {
sApplication = getApplicationByReflect();
} else {
sApplication = app;
}
sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
} else {
if (app != null && app.getClass() != sApplication.getClass()) {
sApplication.unregisterActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
ACTIVITY_LIFECYCLE.mActivityList.clear();
sApplication = app;
sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
}
}
}
/**
* Return the context of Application object.
*
* @return the context of Application object
*/
public static Application getApp() {
if (sApplication != null) return sApplication;
Application app = getApplicationByReflect();
init(app);
return app;
}
private static Application getApplicationByReflect() {
try {
@SuppressLint("PrivateApi")
Class<?> activityThread = Class.forName("android.app.ActivityThread");
Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
Object app = activityThread.getMethod("getApplication").invoke(thread);
if (app == null) {
throw new NullPointerException("u should init first");
}
return (Application) app;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new NullPointerException("u should init first");
}
static ActivityLifecycleImpl getActivityLifecycle() {
return ACTIVITY_LIFECYCLE;
}
static LinkedList<Activity> getActivityList() {
return ACTIVITY_LIFECYCLE.mActivityList;
}
static Context getTopActivityOrApp() {
if (isAppForeground()) {
Activity topActivity = ACTIVITY_LIFECYCLE.getTopActivity();
return topActivity == null ? AppUtils.getApp() : topActivity;
} else {
return AppUtils.getApp();
}
}
static boolean isAppForeground() {
ActivityManager am = (ActivityManager) AppUtils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) return false;
List<ActivityManager.RunningAppProcessInfo> info = am.getRunningAppProcesses();
if (info == null || info.size() == 0) return false;
for (ActivityManager.RunningAppProcessInfo aInfo : info) {
if (aInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return aInfo.processName.equals(AppUtils.getApp().getPackageName());
}
}
return false;
}
static class ActivityLifecycleImpl implements ActivityLifecycleCallbacks {
final LinkedList<Activity> mActivityList = new LinkedList<>();
final Map<Object, OnAppStatusChangedListener> mStatusListenerMap = new HashMap<>();
final Map<Activity, Set<OnActivityDestroyedListener>> mDestroyedListenerMap = new HashMap<>();
private int mForegroundCount = 0;
private int mConfigCount = 0;
private boolean mIsBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
setTopActivity(activity);
}
@Override
public void onActivityStarted(Activity activity) {
if (!mIsBackground) {
setTopActivity(activity);
}
if (mConfigCount < 0) {
++mConfigCount;
} else {
++mForegroundCount;
}
}
@Override
public void onActivityResumed(Activity activity) {
setTopActivity(activity);
if (mIsBackground) {
mIsBackground = false;
postStatus(true);
}
}
@Override
public void onActivityPaused(Activity activity) {/**/
}
@Override
public void onActivityStopped(Activity activity) {
if (activity.isChangingConfigurations()) {
--mConfigCount;
} else {
--mForegroundCount;
if (mForegroundCount <= 0) {
mIsBackground = true;
postStatus(false);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {/**/}
@Override
public void onActivityDestroyed(Activity activity) {
mActivityList.remove(activity);
consumeOnActivityDestroyedListener(activity);
fixSoftInputLeaks(activity);
}
Activity getTopActivity() {
if (!mActivityList.isEmpty()) {
final Activity topActivity = mActivityList.getLast();
if (topActivity != null) {
return topActivity;
}
}
Activity topActivityByReflect = getTopActivityByReflect();
if (topActivityByReflect != null) {
setTopActivity(topActivityByReflect);
}
return topActivityByReflect;
}
void addOnAppStatusChangedListener(final Object object,
final OnAppStatusChangedListener listener) {
mStatusListenerMap.put(object, listener);
}
void removeOnAppStatusChangedListener(final Object object) {
mStatusListenerMap.remove(object);
}
void removeOnActivityDestroyedListener(final Activity activity) {
if (activity == null) return;
mDestroyedListenerMap.remove(activity);
}
void addOnActivityDestroyedListener(final Activity activity,
final OnActivityDestroyedListener listener) {
if (activity == null || listener == null) return;
Set<OnActivityDestroyedListener> listeners;
if (!mDestroyedListenerMap.containsKey(activity)) {
listeners = new HashSet<>();
mDestroyedListenerMap.put(activity, listeners);
} else {
listeners = mDestroyedListenerMap.get(activity);
if (listeners.contains(listener)) return;
}
listeners.add(listener);
}
private void postStatus(final boolean isForeground) {
if (mStatusListenerMap.isEmpty()) return;
for (OnAppStatusChangedListener onAppStatusChangedListener : mStatusListenerMap.values()) {
if (onAppStatusChangedListener == null) return;
if (isForeground) {
onAppStatusChangedListener.onForeground();
} else {
onAppStatusChangedListener.onBackground();
}
}
}
private void setTopActivity(final Activity activity) {
if (PERMISSION_ACTIVITY_CLASS_NAME.equals(activity.getClass().getName())) return;
if (mActivityList.contains(activity)) {
if (!mActivityList.getLast().equals(activity)) {
mActivityList.remove(activity);
mActivityList.addLast(activity);
}
} else {
mActivityList.addLast(activity);
}
}
private void consumeOnActivityDestroyedListener(Activity activity) {
Iterator<Map.Entry<Activity, Set<OnActivityDestroyedListener>>> iterator
= mDestroyedListenerMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Activity, Set<OnActivityDestroyedListener>> entry = iterator.next();
if (entry.getKey() == activity) {
Set<OnActivityDestroyedListener> value = entry.getValue();
for (OnActivityDestroyedListener listener : value) {
listener.onActivityDestroyed(activity);
}
iterator.remove();
}
}
}
private Activity getTopActivityByReflect() {
try {
@SuppressLint("PrivateApi")
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Object currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field mActivityListField = activityThreadClass.getDeclaredField("mActivityList");
mActivityListField.setAccessible(true);
Map activities = (Map) mActivityListField.get(currentActivityThreadMethod);
if (activities == null) return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
return (Activity) activityField.get(activityRecord);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
private static void fixSoftInputLeaks(final Activity activity) {
if (activity == null) return;
InputMethodManager imm =
(InputMethodManager) AppUtils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
String[] leakViews = new String[]{"mLastSrvView", "mCurRootView", "mServedView", "mNextServedView"};
for (String leakView : leakViews) {
try {
Field leakViewField = InputMethodManager.class.getDeclaredField(leakView);
if (leakViewField == null) continue;
if (!leakViewField.isAccessible()) {
leakViewField.setAccessible(true);
}
Object obj = leakViewField.get(imm);
if (!(obj instanceof View)) continue;
View view = (View) obj;
if (view.getRootView() == activity.getWindow().getDecorView().getRootView()) {
leakViewField.set(imm, null);
}
} catch (Throwable ignore) { /**/ }
}
}
}
public static final class FileProvider4UtilCode extends FileProvider {
@Override
public boolean onCreate() {
AppUtils.init(getContext());
return true;
}
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
public interface OnAppStatusChangedListener {
void onForeground();
void onBackground();
}
public interface OnActivityDestroyedListener {
void onActivityDestroyed(Activity activity);
}
}
package com.sobot.widget.livedatabus.utils;
import android.os.Looper;
public final class ThreadUtils {
public static boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}
package com.sobot.widget.ui.base; package com.sobot.widget.ui.base;
import android.Manifest;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Rect; import android.graphics.Rect;
...@@ -25,30 +22,20 @@ import android.widget.RelativeLayout; ...@@ -25,30 +22,20 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import com.sobot.utils.SobotSharedPreferencesUtil; import com.sobot.utils.SobotSharedPreferencesUtil;
import com.sobot.utils.SobotSystemUtils;
import com.sobot.widget.R; import com.sobot.widget.R;
import com.sobot.widget.SobotWidgetApi; import com.sobot.widget.SobotWidgetApi;
import com.sobot.widget.ui.SobotBaseConstant;
import com.sobot.widget.ui.SobotMarkConfig; import com.sobot.widget.ui.SobotMarkConfig;
import com.sobot.widget.ui.base.picandroidvideo.SobotSelectPicAndVideoActivity;
import com.sobot.widget.ui.image.SobotRCImageView; import com.sobot.widget.ui.image.SobotRCImageView;
import com.sobot.widget.ui.notchlib.SobotINotchScreen; import com.sobot.widget.ui.notchlib.SobotINotchScreen;
import com.sobot.widget.ui.notchlib.SobotNotchScreenManager; import com.sobot.widget.ui.notchlib.SobotNotchScreenManager;
import com.sobot.widget.ui.permission.SobotPermissionListener; import com.sobot.widget.ui.permission.SobotPermissionListener;
import com.sobot.widget.ui.permission.SobotPermissionListenerImpl;
import com.sobot.widget.ui.permission.SobotPermissionTipDialog;
import com.sobot.widget.ui.statusbar.SobotStatusBarUtils; import com.sobot.widget.ui.statusbar.SobotStatusBarUtils;
import com.sobot.widget.ui.toast.SobotToastUtil;
import com.sobot.widget.ui.utils.SobotResourceUtils; import com.sobot.widget.ui.utils.SobotResourceUtils;
import com.sobot.widget.ui.utils.SobotWidgetUtils;
import java.io.File; import java.io.File;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
/** /**
...@@ -514,476 +501,4 @@ public abstract class SobotBaseActivity extends FragmentActivity { ...@@ -514,476 +501,4 @@ public abstract class SobotBaseActivity extends FragmentActivity {
protected boolean isFullScreen() { protected boolean isFullScreen() {
return (getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN; return (getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
} }
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case SobotBaseConstant.REQUEST_CODE_PICTURE:
try {
//单独处理android 14 部分权限,如果允许是部分权限,跳转到回显界面
if (grantResults.length > 1 && permissions.length > 0) {
//是否有全部权限
boolean isAllGranted = true;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
}
}
if (!isAllGranted) {
for (int i = 0; i < grantResults.length; i++) {
if (permissions[i] != null && permissions[i].equals(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED) && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
int selectType;
if (Arrays.asList(permissions).contains(Manifest.permission.READ_MEDIA_IMAGES) && Arrays.asList(permissions).contains(Manifest.permission.READ_MEDIA_VIDEO)) {
selectType = 3;//部分视频和图片
} else if (Arrays.asList(permissions).contains(Manifest.permission.READ_MEDIA_VIDEO)) {
selectType = 2;//部分视频
} else {
selectType = 1;//部分图片
}
openSelectPic(selectType);
return;
}
}
}
}
for (int i = 0; i < grantResults.length; i++) {
//判断权限的结果,如果有被拒绝,就return
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
String permissionTitle = getResources().getString(R.string.sobot_no_permission_text);
if (permissions[i] != null && permissions[i].equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {
permissionTitle = getResources().getString(R.string.sobot_no_write_external_storage_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getResources().getString(R.string.sobot_memory_card) + " , " + getResources().getString(R.string.sobot_memory_card_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(this, permissionTitle);
}
}
} else if (permissions[i] != null && permissions[i].equals(Manifest.permission.RECORD_AUDIO)) {
permissionTitle = getResources().getString(R.string.sobot_no_record_audio_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getResources().getString(R.string.sobot_microphone) + " , " + getString(R.string.sobot_microphone_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(this, permissionTitle);
}
}
} else if (permissions[i] != null && permissions[i].equals(Manifest.permission.CAMERA)) {
permissionTitle = getResources().getString(R.string.sobot_no_camera_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getString(R.string.sobot_camera) + " , " + getString(R.string.sobot_camera_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(this, permissionTitle);
}
}
} else if (permissions[i] != null && permissions[i].equals(Manifest.permission.READ_MEDIA_IMAGES)) {
permissionTitle = getResources().getString(R.string.sobot_no_record_images_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_MEDIA_IMAGES) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getString(R.string.sobot_memory_card) + " , " + getString(R.string.sobot_memory_card_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(getSobotBaseActivity(), permissionTitle);
}
}
} else if (permissions[i] != null && permissions[i].equals(Manifest.permission.READ_MEDIA_VIDEO)) {
permissionTitle = getResources().getString(R.string.sobot_no_record_video_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_MEDIA_VIDEO) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getString(R.string.sobot_memory_card) + " , " + getString(R.string.sobot_memory_card_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(getSobotBaseActivity(), permissionTitle);
}
}
} else if (permissions[i] != null && permissions[i].equals(Manifest.permission.READ_MEDIA_AUDIO)) {
permissionTitle = getResources().getString(R.string.sobot_no_record_audio_permission);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_MEDIA_AUDIO) && !SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
SobotToastUtil.showCustomLongToast(this, SobotSystemUtils.getAppName(this) + getResources().getString(R.string.sobot_want_use_your) + getString(R.string.sobot_microphone) + " , " + getString(R.string.sobot_microphone_yongtu));
} else {
//调用权限失败
if (permissionListener != null) {
permissionListener.onPermissionErrorListener(getSobotBaseActivity(), permissionTitle);
}
}
}
return;
}
}
if (permissionListener != null) {
permissionListener.onPermissionSuccessListener();
}
} catch (Exception e) {
// e.printStackTrace();
}
break;
}
}
/**
* android 14 部分权限情况下,回显照片或者视频
*
* @param selectType 1:部分图片 2:部分视频 3:部分视频和图片
*/
private void openSelectPic(int selectType) {
Intent intent = new Intent(getSobotBaseActivity(), SobotSelectPicAndVideoActivity.class);
intent.putExtra("selectType", selectType);
startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_PICTURE);
}
/**
* 检查存储权限
*
* @param checkType 0:图片权限 1:视频权限,3,所有细分的权限, android 13 使用
* @return true, 已经获取权限;false,没有权限,尝试获取
*/
protected boolean checkStoragePermission(int checkType) {
//如果是升级Android13之前就已经具有读写SDK的权限,那么升级到13之后,自己具有上述三个权限。
//如果是升级Android13之后新装的应用,并且targetSDK小于33,则申请READ_EXTERNAL_STORAGE权限时,会自动转化为对上述三个权限的申请,权限申请框只一个
//如果是升级Android13之后新装的应用,并且targetSDK大于等于33,则申请READ_EXTERNAL_STORAGE权限时会自动拒绝(同理WRITE_EXTERNAL_STORAGE也是一样)。
//如果是android14 没有图片或者视频权限,还需要判断是否有部分权限,如果有部分权限,跳转允许图片视频界面,选择可以访问的上传,或者打开设置申请永久权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (checkType == 0) {
//检测是否有图片权限
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
!= PackageManager.PERMISSION_GRANTED) {
//有部分图片权限,直接打开允许访问图片视频列表界面
openSelectPic(1);//照片
return false;
} else {
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
} else {
//申请图片权限
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
} else if (checkType == 1) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
//有部分视频权限,直接打开允许访问图片视频列表界面
openSelectPic(2);//视频
return false;
} else {
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
} else {
//申请视频权限
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_VIDEO}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
return true;
} else {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
//有图片和视频但是 没有音频权限
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_AUDIO}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED) {
//有部分视频权限,直接打开允许访问图片视频列表界面
openSelectPic(3);//视频
return false;
} else {
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
} else {
//申请图片、视频、语音三个权限
this.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO,}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
}
} else if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请READ_EXTERNAL_STORAGE权限
this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
return true;
}
/**
* 判断是否有存储卡权限,android 14 部分权限有的话也返回true
*
* @param checkPermissionType 0:图片权限 1:视频权限,2:音频权限,3,所有细分的权限, android 13 使用
* @return true, 已经获取权限;false,没有权限
*/
protected boolean isHasStoragePermission(int checkPermissionType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (checkPermissionType == 0) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14 有部分权限就不弹权限提示框了
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}
} else if (checkPermissionType == 1) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14 有部分权限就不弹权限提示框了
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}
} else {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
//android 14 有部分权限就不弹权限提示框了
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}
}
} else if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 检查录音权限
*
* @return true, 已经获取权限;false,没有权限,尝试获取
*/
protected boolean checkAudioPermission() {
if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
return true;
}
/**
* 判断是否有录音权限
*
* @return true, 已经获取权限;false,没有权限
*/
protected boolean isHasAudioPermission() {
if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 检查相机权限
*
* @return true, 已经获取权限;false,没有权限,尝试获取
*/
protected boolean checkCameraPermission() {
if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.CAMERA}
, SobotBaseConstant.REQUEST_CODE_PICTURE);
return false;
}
}
return true;
}
/**
* 判断是否有相机权限
*
* @return true, 已经获取权限;false,没有权限
*/
protected boolean isHasCameraPermission() {
if (Build.VERSION.SDK_INT >= 23 && SobotSystemUtils.getTargetSdkVersion(getSobotBaseActivity().getApplicationContext()) >= 23) {
if (ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 从图库获取图片
*/
public void selectPicFromLocal() {
permissionListener = new SobotPermissionListenerImpl() {
@Override
public void onPermissionSuccessListener() {
SobotWidgetUtils.openSelectPic(getSobotBaseActivity());
}
};
if (checkIsShowPermissionPop(getString(R.string.sobot_memory_card), getString(R.string.sobot_memory_card_yongtu), 1, 0)) {
return;
}
if (!checkStoragePermission(0)) {
return;
}
SobotWidgetUtils.openSelectPic(getSobotBaseActivity());
}
/**
* 判断是否有存储卡权限
*
* @param type 1 存储卡;2 麦克风;3 相机;
* @param checkPermissionType 0:图片权限 1:视频权限,2:音频权限,3,所有细分的权限, android 13 使用
* @return true, 已经获取权限;false,没有权限
*/
protected boolean isHasPermission(int type, int checkPermissionType) {
if (type == 1) {
return isHasStoragePermission(checkPermissionType);
} else if (type == 2) {
return isHasAudioPermission();
} else if (type == 3) {
return isHasCameraPermission();
}
return true;
}
/**
* 检测是否需要弹出权限用途提示框pop,如果弹出,则拦截接下来的处理逻辑,自己处理
*
* @param title
* @param content
* @param type
* @param checkPermissionType 0:图片权限 1:视频权限,2:音频权限,3,所有细分的权限, android 13 使用
* @return
*/
public boolean checkIsShowPermissionPop(String title, String content, final int type, final int checkPermissionType) {
if (SobotWidgetApi.getSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP)) {
if (!isHasPermission(type, checkPermissionType)) {
SobotPermissionTipDialog dialog = new SobotPermissionTipDialog(getSobotBaseActivity(), title, content, new SobotPermissionTipDialog.ClickViewListener() {
@Override
public void clickRightView(Context context, SobotPermissionTipDialog dialog) {
dialog.dismiss();
if (type == 1) {
if (!checkStoragePermission(checkPermissionType)) {
return;
}
} else if (type == 2) {
if (!checkAudioPermission()) {
return;
}
} else if (type == 3) {
if (!checkCameraPermission()) {
return;
}
}
}
@Override
public void clickLeftView(Context context, SobotPermissionTipDialog dialog) {
dialog.dismiss();
}
});
dialog.show();
return true;
}
}
return false;
}
/**
* 从图库获取视频
*/
public void selectVedioFromLocal() {
permissionListener = new SobotPermissionListenerImpl() {
@Override
public void onPermissionSuccessListener() {
SobotWidgetUtils.openSelectVedio(getSobotBaseActivity());
}
};
if (checkIsShowPermissionPop(getString(R.string.sobot_memory_card), getString(R.string.sobot_memory_card_yongtu), 1, 1)) {
return;
}
if (!checkStoragePermission(1)) {
return;
}
SobotWidgetUtils.openSelectVedio(getSobotBaseActivity());
}
/**
* 打开相机
*/
public void openCamera() {
openCamera("", "");
}
/**
* 打开相机
*
* @param title 权限用途提示弹窗开启后,弹窗的的标题
* @param content 权限用途提示弹窗开启后,弹窗的内容
*/
public void openCamera(String title, String content) {
cameraFile = null;
permissionListener = null;
permissionListener = new SobotPermissionListenerImpl() {
@Override
public void onPermissionSuccessListener() {
if (isCameraCanUse()) {
cameraFile = SobotWidgetUtils.openCamera(getSobotBaseActivity());
}
}
};
if (checkIsShowPermissionPop(TextUtils.isEmpty(title) ? getResources().getString(R.string.sobot_camera) : title, TextUtils.isEmpty(content) ? getResources().getString(R.string.sobot_camera_yongtu) : content, 3, 4)) {
return;
}
if (!checkCameraPermission()) {
return;
}
if (isCameraCanUse()) {
cameraFile = SobotWidgetUtils.openCamera(getSobotBaseActivity());
}
}
} }
\ No newline at end of file
package com.sobot.widget.ui.base.picandroidvideo;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.sobot.utils.SobotDensityUtil;
import com.sobot.widget.R;
import com.sobot.widget.refresh.layout.callback.SobotRecyclerCallBack;
import com.sobot.widget.ui.SobotBaseConstant;
import com.sobot.widget.ui.base.SobotBaseActivity;
import java.util.ArrayList;
import java.util.List;
/**
* android 14 部分权限 允许后的回显界面
*/
public class SobotSelectPicAndVideoActivity extends SobotBaseActivity {
private TextView tv_go_to_settring;
private RecyclerView sobot_rcy;
private Button sobot_btn_submit;
private SobotSelectPicAndVideoAdapter picAdapter;
private List<SobotAlbumFile> albumFileList;
private int selectType = 1;
@Override
protected int getContentViewResId() {
return R.layout.sobot_activity_select_pic_and_video;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (albumFileList == null) {
albumFileList = new ArrayList<>();
}
albumFileList.clear();
albumFileList = SobotMediaReaderScanUtils.getAllMedia(getSobotBaseActivity(), selectType);
if (albumFileList == null) {
albumFileList = new ArrayList<>();
}
albumFileList.add(new SobotAlbumFile());
if (picAdapter != null) {
picAdapter.setmSelectedPos(-1);
picAdapter.updateList(albumFileList);
} else {
finish();
}
}
@Override
protected void onResume() {
super.onResume();
if(selectType == 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_IMAGES)
== PackageManager.PERMISSION_GRANTED) {
//如果android 14 手机有永久权限 直接关闭当前界面
finish();
}
}else if(selectType == 2){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && ContextCompat.checkSelfPermission(getSobotBaseActivity(), Manifest.permission.READ_MEDIA_VIDEO)
== PackageManager.PERMISSION_GRANTED) {
//如果android 14 手机有永久权限 直接关闭当前界面
finish();
}
}
}
@Override
protected void initView() {
tv_go_to_settring = findViewById(R.id.tv_go_to_settring);
sobot_rcy = findViewById(R.id.sobot_rcy);
sobot_btn_submit = findViewById(R.id.sobot_btn_submit);
sobot_btn_submit.setAlpha(0.5f);
sobot_btn_submit.setClickable(false);
setTitle(getString(R.string.sobot_str_select_pic_video));
displayInNotch(sobot_rcy);
tv_go_to_settring.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//去设置打开权限
Uri packageURI = Uri.parse("package:" + getPackageName());
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
startActivity(intent);
}
});
}
protected void initData() {
selectType = getIntent().getIntExtra("selectType", 1);
albumFileList = SobotMediaReaderScanUtils.getAllMedia(getSobotBaseActivity(), selectType);
if (albumFileList == null) {
albumFileList = new ArrayList<>();
}
albumFileList.add(new SobotAlbumFile());
picAdapter = new SobotSelectPicAndVideoAdapter(this, albumFileList, new SobotRecyclerCallBack() {
@Override
public void onItemClickListener(View view, int position) {
}
@Override
public void onItemLongClickListener(View view, int position) {
}
});
picAdapter.setClickListener(new SobotSelectPicAndVideoAdapter.myClickListener() {
@Override
public void onClickOtherListener() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (selectType == 3) {
requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
} else if (selectType == 2) {
requestPermissions(new String[]{Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
} else {
requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED}, SobotBaseConstant.REQUEST_CODE_PICTURE);
}
}
}
@Override
public void onCheckListener() {
if (picAdapter.getmSelectedPos() > -1) {
sobot_btn_submit.setAlpha(1f);
sobot_btn_submit.setClickable(true);
} else {
sobot_btn_submit.setAlpha(0.5f);
sobot_btn_submit.setClickable(false);
}
}
});
sobot_rcy.setAdapter(picAdapter);
GridLayoutManager gridlayoutmanager = new GridLayoutManager(SobotSelectPicAndVideoActivity.this, 4);
sobot_rcy.addItemDecoration(new SpaceItemDecoration(SobotDensityUtil.dp2px(SobotSelectPicAndVideoActivity.this, 3), SobotDensityUtil.dp2px(SobotSelectPicAndVideoActivity.this, 1.5f), 0, SpaceItemDecoration.GRIDLAYOUT));
sobot_rcy.setLayoutManager(gridlayoutmanager);
sobot_btn_submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (albumFileList != null && albumFileList.size() > 0 && picAdapter != null && picAdapter.getmSelectedPos() > -1) {
SobotAlbumFile albumFile = albumFileList.get(picAdapter.getmSelectedPos());
Intent intent = new Intent();
intent.setData(albumFile.getUri());
setResult(RESULT_OK, intent);
finish();
}
}
});
}
}
\ No newline at end of file
...@@ -405,7 +405,7 @@ public class SobotWebViewActivity extends SobotBaseActivity implements View.OnCl ...@@ -405,7 +405,7 @@ public class SobotWebViewActivity extends SobotBaseActivity implements View.OnCl
* 打开相机拍照 * 打开相机拍照
*/ */
private void openCapture() { private void openCapture() {
openCamera();
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment