version:1.0.0
update:更换包名 bugfixes:
This commit is contained in:
226
app/src/main/java/com/xxpatx/os/manager/AmapManager.java
Normal file
226
app/src/main/java/com/xxpatx/os/manager/AmapManager.java
Normal file
@@ -0,0 +1,226 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.amap.api.location.AMapLocation;
|
||||
import com.amap.api.location.AMapLocationClient;
|
||||
import com.amap.api.location.AMapLocationClientOption;
|
||||
import com.amap.api.location.AMapLocationListener;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.bean.BaseResponse;
|
||||
import com.xxpatx.os.bean.MapBean;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
import com.xxpatx.os.gson.GsonUtils;
|
||||
import com.xxpatx.os.network.NetInterfaceManager;
|
||||
import com.xxpatx.os.utils.ActivationUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
public class AmapManager {
|
||||
private static final String TAG = AmapManager.class.getSimpleName();
|
||||
|
||||
MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static AmapManager sInstance;
|
||||
private Context mContext;
|
||||
|
||||
private AMapLocationClient mAMapLocationClient;
|
||||
private AMapLocationClientOption mAMapLocationClientOption;
|
||||
private MapBean mMapBean;
|
||||
|
||||
private AmapManager(Context context) {
|
||||
this.mContext = context;
|
||||
initAmap();
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Context is NULL");
|
||||
}
|
||||
if (sInstance == null) {
|
||||
sInstance = new AmapManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static AmapManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException("You must be init AmapManager first");
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private AMapLocationClientOption getDefaultOption() {
|
||||
if (mAMapLocationClientOption == null) {
|
||||
mAMapLocationClientOption = new AMapLocationClientOption();
|
||||
}
|
||||
mAMapLocationClientOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn);
|
||||
//设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。
|
||||
mAMapLocationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
|
||||
mAMapLocationClientOption.setNeedAddress(true);
|
||||
//获取一次定位结果:
|
||||
//该方法默认为false。
|
||||
mAMapLocationClientOption.setOnceLocation(true);
|
||||
//获取最近3s内精度最高的一次定位结果:
|
||||
//设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。
|
||||
// 如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。
|
||||
mAMapLocationClientOption.setOnceLocationLatest(true);
|
||||
return mAMapLocationClientOption;
|
||||
}
|
||||
|
||||
public void initAmap() {
|
||||
if (mAMapLocationClient == null) {
|
||||
mAMapLocationClient = new AMapLocationClient(mContext);
|
||||
}
|
||||
mAMapLocationClient.setLocationOption(getDefaultOption());
|
||||
|
||||
//设置定位监听
|
||||
mAMapLocationClient.setLocationListener(mAMapLocationListener);
|
||||
//设置场景模式后最好调用一次stop,再调用start以保证场景模式生效
|
||||
|
||||
startLocation();
|
||||
|
||||
String jsonString = mMMKV.decodeString(CommonConfig.MAP_LOCATION_JSON_KEY, "");
|
||||
if (!TextUtils.isEmpty(jsonString)) {
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<MapBean>() {
|
||||
}.getType();
|
||||
mMapBean = gson.fromJson(jsonString, type);
|
||||
} else {
|
||||
Log.e(TAG, "initAmap: jsonString is empty");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void startLocation() {
|
||||
boolean activation = ActivationUtil.isActivation(mContext);
|
||||
if (!activation) {
|
||||
Log.e(TAG, "startLocation: 未激活");
|
||||
return;
|
||||
}
|
||||
mAMapLocationClient.stopLocation();
|
||||
mAMapLocationClient.startLocation();
|
||||
Log.e(TAG, "initAmap: " + "startLocation");
|
||||
}
|
||||
|
||||
private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(AMapLocation aMapLocation) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
//errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
|
||||
if (aMapLocation.getErrorCode() == 0) {
|
||||
Log.e(TAG, "onLocationChanged: " + "定位成功");
|
||||
mMMKV.encode(CommonConfig.MAP_LONGITUDE_KEY, String.valueOf(aMapLocation.getLongitude()));
|
||||
mMMKV.encode(CommonConfig.MAP_LATITUDE_KEY, String.valueOf(aMapLocation.getLatitude()));
|
||||
mMMKV.encode(CommonConfig.MAP_ADDRESS_KEY, aMapLocation.getAddress());
|
||||
updateAddress(aMapLocation);
|
||||
mMapBean = getMapBean(aMapLocation);
|
||||
saveMapResult(mMapBean);
|
||||
LiveEventBus
|
||||
.get(CommonConfig.AMAP_LOCATION_MAP_BEAN)
|
||||
.post(mMapBean);
|
||||
Log.e(TAG, "onLocationChanged: " + aMapLocation.getAddress());
|
||||
sb.append(aMapLocation.getAddress()).append("\n");
|
||||
|
||||
} else {
|
||||
//定位失败
|
||||
sb.append("定位失败" + "\n");
|
||||
sb.append(aMapLocation.getErrorInfo());
|
||||
Log.e(TAG, "onLocationChanged: " + "定位失败");
|
||||
}
|
||||
Log.e(TAG, "amap: " + sb.toString());
|
||||
}
|
||||
};
|
||||
|
||||
private void updateAddress(AMapLocation aMapLocation) {
|
||||
NetInterfaceManager.getInstance().getUpdateAddressObservable(aMapLocation.getAddress()
|
||||
, aMapLocation.getLongitude(), aMapLocation.getLatitude()
|
||||
)
|
||||
.subscribe(new Observer<BaseResponse>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("updateAddress", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse baseResponse) {
|
||||
Log.e("updateAddress", "onNext: " + baseResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Log.e("updateAddress", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.e("updateAddress", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getLocationTude() {
|
||||
if (mMapBean != null) {
|
||||
return mMapBean.getLongitude() + "," + mMapBean.getLatitude();
|
||||
} else {
|
||||
startLocation();
|
||||
return CommonConfig.DEFAULT_LOCATION_TUDE;
|
||||
}
|
||||
}
|
||||
|
||||
public String getDistrict() {
|
||||
if (mMapBean != null) {
|
||||
return mMapBean.getDistrict();
|
||||
} else {
|
||||
startLocation();
|
||||
return CommonConfig.DEFAULT_LOCATION_DISTRICT;
|
||||
}
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
if (mMapBean != null) {
|
||||
return mMapBean.getCity();
|
||||
} else {
|
||||
startLocation();
|
||||
return CommonConfig.DEFAULT_LOCATION_DISTRICT;
|
||||
}
|
||||
}
|
||||
|
||||
private MapBean getMapBean(AMapLocation location) {
|
||||
MapBean mapBean = new MapBean();
|
||||
mapBean.setLongitude(location.getLongitude());
|
||||
mapBean.setLatitude(location.getLatitude());
|
||||
mapBean.setAdcode(location.getAdCode());
|
||||
mapBean.setAddress(location.getAddress());
|
||||
mapBean.setCity(location.getCity());
|
||||
mapBean.setCityCode(location.getCityCode());
|
||||
mapBean.setCountry(location.getCountry());
|
||||
mapBean.setCountryCode(location.getAdCode());
|
||||
mapBean.setDistrict(location.getDistrict());
|
||||
mapBean.setProvince(location.getProvince());
|
||||
mapBean.setStreet(location.getStreet());
|
||||
mapBean.setStreetNumber(location.getStreetNum());
|
||||
mapBean.setTown(location.getStreet());
|
||||
mapBean.setLocationDescribe(location.getLocationDetail());
|
||||
Log.e(TAG, "getMapBean: " + GsonUtils.toJSONString(mapBean));
|
||||
return mapBean;
|
||||
|
||||
}
|
||||
|
||||
private void saveMapResult(MapBean mapBean) {
|
||||
Log.e(TAG, "saveMapResult: " + GsonUtils.toJSONString(mapBean));
|
||||
mMMKV.encode(CommonConfig.MAP_LOCATION_JSON_KEY, GsonUtils.toJSONString(mapBean));
|
||||
}
|
||||
|
||||
}
|
||||
317
app/src/main/java/com/xxpatx/os/manager/AppManager.java
Normal file
317
app/src/main/java/com/xxpatx/os/manager/AppManager.java
Normal file
@@ -0,0 +1,317 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.bean.DesktopIcon;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
import com.xxpatx.os.utils.ApkUtils;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AppManager {
|
||||
private static final String TAG = AppManager.class.getSimpleName();
|
||||
|
||||
public static final String ADD_NAME = "com.zyos.add";
|
||||
public static final String UPDATE_NAME = "com.zyos.update";
|
||||
private static final String SHOW_PACKAGE_KEY = "SHOW_PACKAGE_KEY";
|
||||
private static final String ADD_PACKAGE_KEY = "ADD_PACKAGE_KEY";
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static AppManager sInstance;
|
||||
private Context mContext;
|
||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
private Set<String> showPackages;
|
||||
private Set<String> addPackages;
|
||||
|
||||
public static void init(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("context is NULL");
|
||||
}
|
||||
if (sInstance == null) {
|
||||
Log.e(TAG, "init: ");
|
||||
sInstance = new AppManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public AppManager(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Context is NULL");
|
||||
}
|
||||
this.mContext = context;
|
||||
this.showPackages = mMMKV.decodeStringSet(SHOW_PACKAGE_KEY, new HashSet<>());
|
||||
this.addPackages = mMMKV.decodeStringSet(ADD_PACKAGE_KEY, new HashSet<>());
|
||||
this.showPackages.removeIf(TextUtils::isEmpty);
|
||||
}
|
||||
|
||||
public static AppManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException("You must be init AppManager first");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public Set<String> getShowPackages() {
|
||||
return showPackages;
|
||||
}
|
||||
|
||||
public void addPakcage(String packageName) {
|
||||
this.showPackages.add(packageName);
|
||||
mMMKV.encode(SHOW_PACKAGE_KEY, showPackages);
|
||||
}
|
||||
|
||||
public void removePakcage(String packageName) {
|
||||
this.showPackages.remove(packageName);
|
||||
mMMKV.encode(SHOW_PACKAGE_KEY, showPackages);
|
||||
}
|
||||
|
||||
public Set<String> getFilterAppset() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// 查询所有已经安装的应用程序
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
Set<String> allowPackages = resolveinfoList.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toSet());
|
||||
|
||||
// List<String> adminApp = RemoteManager.getInstance().getAdminApp();
|
||||
// Log.i(TAG, "getFilterAppset: adminapp = " + adminApp);
|
||||
for (ResolveInfo resolveInfo : resolveinfoList) {
|
||||
String pkg = resolveInfo.activityInfo.packageName;
|
||||
if (ApkUtils.appIsDisable(mContext, pkg)) {
|
||||
Log.e(TAG, "getFilterAppset: disable = " + pkg);
|
||||
continue;
|
||||
}
|
||||
if (showPackages.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
} else {
|
||||
//通过flag排除系统应用,会将电话、短信也排除掉
|
||||
if (ApkUtils.isSystemApp(mContext, pkg)) {
|
||||
if (ApkUtils.showPackageName.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
}
|
||||
} else {
|
||||
if (allowPackages.contains(pkg) && !ApkUtils.excludePackageName.contains(pkg)) {
|
||||
// if (adminApp.contains(pkg)) {
|
||||
// resolveInfos.add(resolveInfo);
|
||||
// } else if (ApkUtils.showPackageName.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(), "is_activity", 0) == 0) {
|
||||
resolveInfos.removeIf(resolveInfo -> "com.uiui.city".equals(resolveInfo.activityInfo.packageName));
|
||||
}
|
||||
Set<String> desktopIcons = resolveInfos.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toSet());
|
||||
return desktopIcons;
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<DesktopIcon> getFilterAppList() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// 查询所有已经安装的应用程序
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
Set<String> allowPackages = resolveinfoList.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toSet());
|
||||
|
||||
|
||||
// List<String> adminApp = RemoteManager.getInstance().getAdminApp();
|
||||
// Log.i(TAG, "getFilterAppset: adminapp = " + adminApp);
|
||||
for (ResolveInfo resolveInfo : resolveinfoList) {
|
||||
String pkg = resolveInfo.activityInfo.packageName;
|
||||
if (ApkUtils.appIsDisable(mContext, pkg)) {
|
||||
Log.e(TAG, "getFilterAppset: disable = " + pkg);
|
||||
continue;
|
||||
}
|
||||
if (showPackages.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
} else {
|
||||
//通过flag排除系统应用,会将电话、短信也排除掉
|
||||
if (ApkUtils.isSystemApp(mContext, pkg)) {
|
||||
if (ApkUtils.showPackageName.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
}
|
||||
} else {
|
||||
if (allowPackages.contains(pkg) && !ApkUtils.excludePackageName.contains(pkg)) {
|
||||
// if (adminApp.contains(pkg)) {
|
||||
// resolveInfos.add(resolveInfo);
|
||||
// } else if (ApkUtils.showPackageName.contains(pkg)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(), "is_activity", 0) == 0) {
|
||||
resolveInfos.removeIf(resolveInfo -> "com.uiui.city".equals(resolveInfo.activityInfo.packageName));
|
||||
}
|
||||
resolveInfos.sort(new Comparator<ResolveInfo>() {
|
||||
@Override
|
||||
public int compare(ResolveInfo o1, ResolveInfo o2) {
|
||||
return Collator.getInstance(Locale.CHINESE).compare(o1.loadLabel(pm).toString(), o2.loadLabel(pm).toString());
|
||||
}
|
||||
});
|
||||
resolveInfos.sort(new Comparator<ResolveInfo>() {
|
||||
@Override
|
||||
public int compare(ResolveInfo o1, ResolveInfo o2) {
|
||||
try {
|
||||
if ((pm.getApplicationInfo(o1.activityInfo.packageName, 0).flags & ApplicationInfo.FLAG_SYSTEM) <= (pm.getApplicationInfo(o2.activityInfo.packageName, 0).flags & ApplicationInfo.FLAG_SYSTEM)) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
ArrayList<DesktopIcon> desktopIcons = new ArrayList<>();
|
||||
for (ResolveInfo applicationInfo : resolveInfos) {
|
||||
if (!ApkUtils.excludeClassName.contains(applicationInfo.activityInfo.name)) {
|
||||
desktopIcons.add(DesktopIcon.creatDesktopIcon(mContext, applicationInfo));
|
||||
}
|
||||
}
|
||||
return desktopIcons;
|
||||
}
|
||||
|
||||
public ArrayList<DesktopIcon> getAllAppList() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// 查询所有已经安装的应用程序
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
Set<String> allowPackages = resolveinfoList.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toSet());
|
||||
|
||||
|
||||
// List<String> adminApp = RemoteManager.getInstance().getAdminApp();
|
||||
// Log.i(TAG, "getFilterAppset: adminapp = " + adminApp);
|
||||
for (ResolveInfo resolveInfo : resolveinfoList) {
|
||||
String pkg = resolveInfo.activityInfo.packageName;
|
||||
if (ApkUtils.appIsDisable(mContext, pkg)) {
|
||||
Log.e(TAG, "getFilterAppset: disable = " + pkg);
|
||||
continue;
|
||||
}
|
||||
if (ApkUtils.excludePackageName.contains(pkg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
resolveInfos.add(resolveInfo);
|
||||
}
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(), "is_activity", 0) == 0) {
|
||||
resolveInfos.removeIf(resolveInfo -> "com.uiui.city".equals(resolveInfo.activityInfo.packageName));
|
||||
}
|
||||
resolveInfos.sort(new Comparator<ResolveInfo>() {
|
||||
@Override
|
||||
public int compare(ResolveInfo o1, ResolveInfo o2) {
|
||||
return Collator.getInstance(Locale.CHINESE).compare(o1.loadLabel(pm).toString(), o2.loadLabel(pm).toString());
|
||||
}
|
||||
});
|
||||
// resolveInfos.sort(new Comparator<ResolveInfo>() {
|
||||
// @Override
|
||||
// public int compare(ResolveInfo o1, ResolveInfo o2) {
|
||||
// try {
|
||||
// if ((pm.getApplicationInfo(o1.activityInfo.packageName, 0).flags & ApplicationInfo.FLAG_SYSTEM) <= (pm.getApplicationInfo(o2.activityInfo.packageName, 0).flags & ApplicationInfo.FLAG_SYSTEM)) {
|
||||
// return 1;
|
||||
// } else {
|
||||
// return -1;
|
||||
// }
|
||||
// } catch (PackageManager.NameNotFoundException e) {
|
||||
// e.printStackTrace();
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
ArrayList<DesktopIcon> desktopIcons = new ArrayList<>();
|
||||
for (ResolveInfo applicationInfo : resolveInfos) {
|
||||
desktopIcons.add(DesktopIcon.creatDesktopIcon(mContext, applicationInfo));
|
||||
}
|
||||
return desktopIcons;
|
||||
}
|
||||
|
||||
public ArrayList<DesktopIcon> getAddDesktopIcon() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// 查询所有已经安装的应用程序
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
for (ResolveInfo resolveInfo : resolveinfoList) {
|
||||
if (addPackages.contains(resolveInfo.activityInfo.packageName)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
}
|
||||
}
|
||||
ArrayList<DesktopIcon> desktopIcons = new ArrayList<>();
|
||||
for (ResolveInfo applicationInfo : resolveInfos) {
|
||||
desktopIcons.add(DesktopIcon.creatDesktopIcon(mContext, applicationInfo));
|
||||
}
|
||||
return desktopIcons;
|
||||
}
|
||||
|
||||
public Set<String> getAddDesktopIconSet() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// 查询所有已经安装的应用程序
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
for (ResolveInfo resolveInfo : resolveinfoList) {
|
||||
if (addPackages.contains(resolveInfo.activityInfo.packageName)) {
|
||||
resolveInfos.add(resolveInfo);
|
||||
}
|
||||
}
|
||||
Set<String> pkgSet = resolveInfos.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toSet());
|
||||
return pkgSet;
|
||||
}
|
||||
|
||||
|
||||
public void addAddPakcage(String packageName) {
|
||||
this.addPackages.add(packageName);
|
||||
mMMKV.encode(ADD_PACKAGE_KEY, addPackages);
|
||||
}
|
||||
|
||||
public void removeAddPakcage(String packageName) {
|
||||
this.addPackages.remove(packageName);
|
||||
mMMKV.encode(ADD_PACKAGE_KEY, addPackages);
|
||||
}
|
||||
|
||||
public Set<String> getAddPackages() {
|
||||
Set<String> stringSet = mMMKV.decodeStringSet(ADD_PACKAGE_KEY, new HashSet<>());
|
||||
return stringSet;
|
||||
}
|
||||
|
||||
}
|
||||
121
app/src/main/java/com/xxpatx/os/manager/AppStatusManager.java
Normal file
121
app/src/main/java/com/xxpatx/os/manager/AppStatusManager.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.activity.main.deprecated.OldMainActivity;
|
||||
import com.xxpatx.os.bean.DailyAppBean;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AppStatusManager {
|
||||
private static final String TAG = AppStatusManager.class.getSimpleName();
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static AppStatusManager sInstance;
|
||||
|
||||
private Context mContext;
|
||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
private Set<String> hidedAppSet;
|
||||
|
||||
public static final String APP_STATUS_MANAGER_KEY = "AppStatusManagerSet";
|
||||
private static final Set<String> defaultHiedApp = new HashSet<String>() {{
|
||||
this.add("om.android.fmradio");//收音机
|
||||
this.add("com.android.mms");//信息
|
||||
this.add("com.android.gallery3d");
|
||||
this.add("com.android.documentsui");
|
||||
this.add("com.android.calculator2");
|
||||
this.add("com.android.calendar");
|
||||
this.add("com.mediatek.camera");
|
||||
this.add("com.android.dialer");
|
||||
this.add("com.android.settings");
|
||||
}};
|
||||
|
||||
private AppStatusManager(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Context is NULL");
|
||||
}
|
||||
this.mContext = context;
|
||||
Set<String> stringSet = mMMKV.decodeStringSet(APP_STATUS_MANAGER_KEY, defaultHiedApp);
|
||||
this.hidedAppSet = stringSet;
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (sInstance == null) {
|
||||
Log.e(TAG, "init: ");
|
||||
sInstance = new AppStatusManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static AppStatusManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException("You must be init AppStatusManager first");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public Set<String> getHidedAppSet() {
|
||||
return this.hidedAppSet;
|
||||
}
|
||||
|
||||
public void addHidedApp(String pkg) {
|
||||
this.hidedAppSet.add(pkg);
|
||||
mMMKV.encode(APP_STATUS_MANAGER_KEY, hidedAppSet);
|
||||
mContext.sendBroadcast(new Intent(OldMainActivity.ACTION_PACKAGE_HIDE));
|
||||
}
|
||||
|
||||
public void removeHidedApp(String pkg) {
|
||||
this.hidedAppSet.remove(pkg);
|
||||
mMMKV.encode(APP_STATUS_MANAGER_KEY, hidedAppSet);
|
||||
mContext.sendBroadcast(new Intent(OldMainActivity.ACTION_PACKAGE_HIDE));
|
||||
}
|
||||
|
||||
public List<DailyAppBean> getPackageList() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
List<DailyAppBean> dailyAppBeanList = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
for (ResolveInfo packageInfo : resolveinfoList) {
|
||||
String pkg = packageInfo.activityInfo.packageName;
|
||||
if (hidedAppSet.contains(pkg)) {
|
||||
Log.e(TAG, "getPackageList: " + pkg);
|
||||
DailyAppBean appSelectBean = new DailyAppBean(packageInfo.activityInfo.loadLabel(pm).toString(),
|
||||
packageInfo.activityInfo.packageName,
|
||||
packageInfo.activityInfo.name
|
||||
);
|
||||
|
||||
dailyAppBeanList.add(appSelectBean);
|
||||
}
|
||||
}
|
||||
return dailyAppBeanList;
|
||||
}
|
||||
|
||||
public long getPackageListSize() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
List<DailyAppBean> dailyAppBeanList = new ArrayList<>();
|
||||
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
|
||||
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
|
||||
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
|
||||
return resolveinfoList.stream().filter(new Predicate<ResolveInfo>() {
|
||||
@Override
|
||||
public boolean test(ResolveInfo resolveInfo) {
|
||||
return hidedAppSet.contains(resolveInfo.activityInfo.packageName);
|
||||
}
|
||||
}).count();
|
||||
}
|
||||
}
|
||||
140
app/src/main/java/com/xxpatx/os/manager/ConnectManager.java
Normal file
140
app/src/main/java/com/xxpatx/os/manager/ConnectManager.java
Normal file
@@ -0,0 +1,140 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
import com.xxpatx.os.utils.TimeUtils;
|
||||
|
||||
public class ConnectManager {
|
||||
private static final String TAG = ConnectManager.class.getSimpleName();
|
||||
|
||||
|
||||
public static final long ONE_MINUTES_TIME = 60 * 1000;
|
||||
public static final long FIFTEEN_MINUTES_TIME = ONE_MINUTES_TIME * 15;
|
||||
public static final long HALF_HOUR_TIME = FIFTEEN_MINUTES_TIME * 2;
|
||||
public static final long ONE_HOUR_TIME = HALF_HOUR_TIME * 2;
|
||||
public static final long SIX_HOUR_TIME = ONE_HOUR_TIME * 6;
|
||||
public static final long HALF_DAY_TIME = SIX_HOUR_TIME * 2;
|
||||
public static final long ONE_DAY_TIME = HALF_DAY_TIME * 2;
|
||||
|
||||
/*重启后连接成功的时间*/
|
||||
public static final String REBOOT_LAST_ONNECT_TIME = "reboot_last_connect_time";
|
||||
/*WiFi连接后连接成功的时间*/
|
||||
public static final String WIFI_LAST_CONNECT_TIME = "WiFi_last_connect_time";
|
||||
/*打开设备信息连接成功的时间*/
|
||||
public static final String OPENINFO_LAST_ONNECT_TIME = "opneinfo_last_connect_time";
|
||||
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static ConnectManager sInstance;
|
||||
private Context mContext;
|
||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
|
||||
private ConnectManager(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Context is NULL");
|
||||
}
|
||||
this.mContext = context;
|
||||
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (sInstance == null) {
|
||||
Log.e(TAG, "init: ");
|
||||
sInstance = new ConnectManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static ConnectManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException("You must be init ConnectManager first");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public long getConnectModeTime(ConnectMode connectMode) {
|
||||
long time = 0;
|
||||
switch (connectMode) {
|
||||
case DEFAULT:
|
||||
time = 0;
|
||||
break;
|
||||
case ONE_MINUTE:
|
||||
time = ONE_MINUTES_TIME;
|
||||
break;
|
||||
case FIFTEEN_MINUTES:
|
||||
time = FIFTEEN_MINUTES_TIME;
|
||||
break;
|
||||
case HALF_HOUR:
|
||||
time = HALF_HOUR_TIME;
|
||||
break;
|
||||
case ONE_HOUR:
|
||||
time = ONE_HOUR_TIME;
|
||||
break;
|
||||
case SIX_HOUR:
|
||||
time = SIX_HOUR_TIME;
|
||||
break;
|
||||
case HALF_DAY:
|
||||
time = HALF_DAY_TIME;
|
||||
break;
|
||||
case ONE_DAY:
|
||||
time = ONE_DAY_TIME;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
public boolean isNeedConnect(String key, ConnectMode connectMode) {
|
||||
long nowTime = System.currentTimeMillis();
|
||||
long lastTime = mMMKV.decodeLong(key, 0);
|
||||
long intervalTime = getConnectModeTime(connectMode);
|
||||
//防止修改了时间一直返回false
|
||||
if (lastTime > nowTime) {
|
||||
return true;
|
||||
}
|
||||
//防止一分钟内重复请求
|
||||
boolean refresh = nowTime - lastTime > intervalTime && nowTime - lastTime > ONE_MINUTES_TIME;
|
||||
return refresh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 重启后是否连接
|
||||
*/
|
||||
public boolean isRebootFistConnect() {
|
||||
long rebootTime = mMMKV.decodeLong(REBOOT_LAST_ONNECT_TIME, 0);
|
||||
//只在开机后15内连接,其他情况为service重启
|
||||
long time = System.currentTimeMillis() - rebootTime;
|
||||
return time < 15 * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 今天WiFi连接是否有连接
|
||||
*/
|
||||
public boolean isWiFiFistConnect() {
|
||||
long time = mMMKV.decodeLong(WIFI_LAST_CONNECT_TIME, 0);
|
||||
return !TimeUtils.isTodayTime(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 今天打开设备信息后是否连接
|
||||
*/
|
||||
public boolean isOpenInfoFistConnect() {
|
||||
long time = mMMKV.decodeLong(OPENINFO_LAST_ONNECT_TIME, 0);
|
||||
return !TimeUtils.isTodayTime(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WiFiAlias
|
||||
* @return 今天切换WiFi后是否连接
|
||||
*/
|
||||
public boolean isWiFiCutoverFistConnect(String WiFiAlias) {
|
||||
long time = mMMKV.decodeLong(WiFiAlias, 0);
|
||||
return !TimeUtils.isTodayTime(time);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
12
app/src/main/java/com/xxpatx/os/manager/ConnectMode.java
Normal file
12
app/src/main/java/com/xxpatx/os/manager/ConnectMode.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
public enum ConnectMode {
|
||||
DEFAULT,
|
||||
ONE_MINUTE,
|
||||
FIFTEEN_MINUTES,
|
||||
HALF_HOUR,
|
||||
ONE_HOUR,
|
||||
SIX_HOUR,
|
||||
HALF_DAY,
|
||||
ONE_DAY,
|
||||
}
|
||||
207
app/src/main/java/com/xxpatx/os/manager/RemoteManager.java
Normal file
207
app/src/main/java/com/xxpatx/os/manager/RemoteManager.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package com.xxpatx.os.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tencent.bugly.crashreport.CrashReport;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
import com.uiuios.sn.IGetInfoInterface;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class RemoteManager {
|
||||
private static final String TAG = RemoteManager.class.getSimpleName();
|
||||
private static final String SN_KEY = "sn_serial_key";
|
||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static RemoteManager sInstance;
|
||||
private Context mContext;
|
||||
private static boolean mServiceConnected = false;
|
||||
|
||||
private IGetInfoInterface mIGetInfoInterface;
|
||||
private ServiceConnection mIGetInfoConnection;
|
||||
|
||||
private RemoteManager(Context context) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Context is NULL");
|
||||
}
|
||||
this.mContext = context;
|
||||
mIGetInfoConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Log.e(TAG, "onServiceConnected: mIGetInfoConnection");
|
||||
mIGetInfoInterface = IGetInfoInterface.Stub.asInterface(service);
|
||||
mServiceConnected = true;
|
||||
for (ConnectedListener listener : mListeners) {
|
||||
if (listener != null) {
|
||||
listener.onRemoteConnected();
|
||||
}
|
||||
}
|
||||
try {
|
||||
String sn = mIGetInfoInterface.getSerial();
|
||||
CrashReport.setDeviceModel(mContext, sn);
|
||||
mMMKV.encode(SN_KEY, sn);
|
||||
Log.e(TAG, "onServiceConnected: sn = " + sn);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Log.e(TAG, "onServiceDisconnected: mIGetInfoConnection");
|
||||
mIGetInfoInterface = null;
|
||||
mServiceConnected = false;
|
||||
bindInfoService();
|
||||
}
|
||||
};
|
||||
bindInfoService();
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (sInstance == null) {
|
||||
Log.e(TAG, "init: ");
|
||||
sInstance = new RemoteManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static RemoteManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException("You must be init RemoteManager first");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public static boolean isServiceConnected() {
|
||||
return mServiceConnected;
|
||||
}
|
||||
|
||||
public interface ConnectedListener {
|
||||
void onRemoteConnected();
|
||||
}
|
||||
|
||||
private static Set<ConnectedListener> mListeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
public static void setListener(ConnectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
if (mServiceConnected) {
|
||||
listener.onRemoteConnected();
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeListener(ConnectedListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void bindInfoService() {
|
||||
if (mIGetInfoInterface == null) {
|
||||
//这是连接aidl服务的代码
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("com.uiuios.sn.IGetInfoInterface");
|
||||
intent.setPackage("com.uiuios.sn");
|
||||
intent.setComponent(new ComponentName("com.uiuios.sn", "com.uiuios.sn.service.RemoteService"));
|
||||
mContext.bindService(intent, mIGetInfoConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取sn
|
||||
*/
|
||||
public String getSerial() {
|
||||
// if (BuildConfig.DEBUG) return "MTK13220282310";
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
return mIGetInfoInterface.getSerial();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "getSerial: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
return mMMKV.decodeString(SN_KEY, "");
|
||||
}
|
||||
|
||||
public boolean putSystemInt(String name, int value) {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
return mIGetInfoInterface.SystemPutInt(name, value);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "putSystemInt: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void killBackgroundProcesses(String pkg) {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
mIGetInfoInterface.killBackgroundProcesses(pkg);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "killBackgroundProcesses: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
}
|
||||
|
||||
public String getConnectWifiSsid() {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
return mIGetInfoInterface.getWifiSsid();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "killBackgroundProcesses: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
return "获取失败";
|
||||
}
|
||||
|
||||
public String getBluetoothDeviceName() {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
return mIGetInfoInterface.getBluetoothSsid();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "killBackgroundProcesses: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
return "获取失败";
|
||||
}
|
||||
|
||||
public void openLauncher3() {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
mIGetInfoInterface.openLauncher3();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "openLauncher3: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultDesktop(String pkgName, String className) {
|
||||
if (mIGetInfoInterface != null) {
|
||||
try {
|
||||
mIGetInfoInterface.setDefaultDesktop(pkgName, className);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "setDefaultDesktop: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
bindInfoService();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user