第一次提交
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package com.fengliyan.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.caivideo.base.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
2
base/src/main/AndroidManifest.xml
Normal file
2
base/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.fengliyan.base" />
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.fengliyan.base.base;
|
||||
|
||||
public interface AnyCallback<T> {
|
||||
void callback(T t);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.fengliyan.base.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* MUNA框架的初始化类,所有初始化工作在此进行,应在使用其它组件前进行初始化
|
||||
* Created by siva on 16/1/14.
|
||||
*/
|
||||
public class BaseFramework {
|
||||
|
||||
private static boolean sInited = false;
|
||||
|
||||
public synchronized static void init(Context applicationContext) {
|
||||
|
||||
if (null == applicationContext) {
|
||||
throw new IllegalArgumentException("applicationContext cannot be null");
|
||||
}
|
||||
|
||||
if (sInited) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContextHolder.init(applicationContext.getApplicationContext()); //初始化上下文保持类
|
||||
sInited = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.fengliyan.base.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* 可以通过该类获取应用上下文,需要在使用其它组件之前对其进行初始化
|
||||
* Created by siva on 16/1/13.
|
||||
*/
|
||||
public final class ContextHolder {
|
||||
|
||||
private static boolean sInited = false;
|
||||
private static Context sApplicationContext;
|
||||
|
||||
/**
|
||||
* 使用其它组件之前对其进行初始化,由MunaFramework调用,无需直接使用
|
||||
*
|
||||
* @param applicationContext 指定ApplicationContext
|
||||
*/
|
||||
public synchronized static void init(Context applicationContext) {
|
||||
|
||||
if (null == applicationContext) {
|
||||
throw new IllegalArgumentException("applicationContext cannot be null");
|
||||
}
|
||||
|
||||
if (sInited) {
|
||||
return;
|
||||
}
|
||||
|
||||
sApplicationContext = applicationContext;
|
||||
sInited = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ApplicationContext对像
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Context getApplicationContext() {
|
||||
return sApplicationContext;
|
||||
}
|
||||
}
|
||||
112
base/src/main/java/com/fengliyan/base/base/bean/BaseBean.java
Normal file
112
base/src/main/java/com/fengliyan/base/base/bean/BaseBean.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.fengliyan.base.base.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by siva on 16/1/17.
|
||||
*/
|
||||
public abstract class BaseBean implements Serializable {
|
||||
|
||||
/**
|
||||
* 序列号
|
||||
*/
|
||||
private static final long serialVersionUID = 2249325746833199332L;
|
||||
|
||||
/**
|
||||
* 访问控制器,序列化的时候,不做处理
|
||||
*/
|
||||
private transient ThreadLocal<BaseBean> visitor = new ThreadLocal<BaseBean>() {
|
||||
|
||||
@Override
|
||||
protected BaseBean initialValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private String mSimpleName = getClass().getSimpleName();
|
||||
|
||||
/**
|
||||
* 避免子类中相互引用引起输出toString时栈溢出
|
||||
*
|
||||
* @return String 返回字符串
|
||||
*/
|
||||
private String toString0() {
|
||||
List<PropertyDescriptor> props = PropertyDescriptorHelper.getPropertyDescriptors(this);
|
||||
Object[] params = new Object[0];
|
||||
|
||||
Object result;
|
||||
boolean isFirst = true;
|
||||
Method m;
|
||||
boolean accessible;
|
||||
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
strBuilder.append(getClass().getName()).append('{');
|
||||
|
||||
for (PropertyDescriptor descriptor : props) {
|
||||
|
||||
if ("class".equals(descriptor.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m = descriptor.getReadMethod();
|
||||
if (m == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
accessible = m.isAccessible();
|
||||
if (!accessible) {
|
||||
m.setAccessible(true);
|
||||
}
|
||||
|
||||
try {
|
||||
result = m.invoke(this, params);
|
||||
|
||||
if (!isFirst) {
|
||||
strBuilder.append(", ");
|
||||
} else {
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
strBuilder.append(descriptor.getName()).append(": ");
|
||||
|
||||
// 对是否为String分别区分
|
||||
if (result instanceof String) {
|
||||
strBuilder.append('"');
|
||||
strBuilder.append(result);
|
||||
strBuilder.append('"');
|
||||
} else {
|
||||
strBuilder.append(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
if (!accessible) {
|
||||
m.setAccessible(false);
|
||||
}
|
||||
}
|
||||
|
||||
strBuilder.append('}');
|
||||
|
||||
return strBuilder.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (visitor.get() == null) {
|
||||
visitor.set(this);
|
||||
try {
|
||||
return toString0();
|
||||
} finally {
|
||||
visitor.set(null);
|
||||
}
|
||||
}
|
||||
return mSimpleName + "@" + Integer.toHexString(hashCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.fengliyan.base.base.bean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by siva on 16/1/17.
|
||||
*/
|
||||
public final class PropertyDescriptor {
|
||||
|
||||
/**
|
||||
* 属性名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 显示名称
|
||||
*/
|
||||
private String displayName;
|
||||
|
||||
/**
|
||||
* 读方法
|
||||
*/
|
||||
private Method readMethod;
|
||||
|
||||
/**
|
||||
* 写方法
|
||||
*/
|
||||
private Method writeMethod;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public Method getReadMethod() {
|
||||
return readMethod;
|
||||
}
|
||||
|
||||
public void setReadMethod(Method readMethod) {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
public Method getWriteMethod() {
|
||||
return writeMethod;
|
||||
}
|
||||
|
||||
public void setWriteMethod(Method writeMethod) {
|
||||
this.writeMethod = writeMethod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.fengliyan.base.base.bean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by siva on 16/1/17.
|
||||
*/
|
||||
public final class PropertyDescriptorHelper {
|
||||
|
||||
public static List<PropertyDescriptor> getPropertyDescriptors(Class<?> type) {
|
||||
|
||||
List<PropertyDescriptor> lsDescriptor = new ArrayList<PropertyDescriptor>();
|
||||
Method[] aryMethod = type.getMethods();
|
||||
Map<String, Method> dicMethod = new HashMap<String, Method>();
|
||||
|
||||
for (Method method : aryMethod) {
|
||||
if (method.getName().startsWith("set")
|
||||
&& method.getParameterTypes() != null
|
||||
&& method.getParameterTypes().length == 1) {
|
||||
dicMethod.put(method.getName(), method);
|
||||
}
|
||||
}
|
||||
|
||||
for (Method method : aryMethod) {
|
||||
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
|
||||
String name = Character.toLowerCase(method.getName().charAt(3))
|
||||
+ method.getName().substring(4, method.getName().length());
|
||||
PropertyDescriptor desc = new PropertyDescriptor();
|
||||
desc.setDisplayName(name);
|
||||
desc.setName(name);
|
||||
desc.setReadMethod(method);
|
||||
String setMethodName = "set" + name.substring(0, 1).toUpperCase()
|
||||
+ name.substring(1, name.length());
|
||||
|
||||
if (dicMethod.containsKey(setMethodName)) {
|
||||
desc.setWriteMethod(dicMethod.get(setMethodName));
|
||||
}
|
||||
|
||||
lsDescriptor.add(desc);
|
||||
} else if (method.getName().startsWith("is")
|
||||
&& method.getParameterTypes().length == 0) {
|
||||
String name = Character.toLowerCase(method.getName().charAt(2))
|
||||
+ method.getName().substring(3, method.getName().length());
|
||||
PropertyDescriptor desc = new PropertyDescriptor();
|
||||
desc.setDisplayName(name);
|
||||
desc.setName(name);
|
||||
desc.setReadMethod(method);
|
||||
String setMethodName = "set" + name.substring(0, 1).toUpperCase()
|
||||
+ name.substring(1, name.length());
|
||||
|
||||
if (dicMethod.containsKey(setMethodName)) {
|
||||
desc.setWriteMethod(dicMethod.get(setMethodName));
|
||||
}
|
||||
|
||||
lsDescriptor.add(desc);
|
||||
}
|
||||
}
|
||||
|
||||
return lsDescriptor;
|
||||
}
|
||||
|
||||
public static List<PropertyDescriptor> getPropertyDescriptors(Object bean) {
|
||||
return getPropertyDescriptors(bean.getClass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
|
||||
/**
|
||||
* 一个简化的权限回调,使用者只需要处理成功回调
|
||||
* Created by yangjinbo on 2016-5-3.
|
||||
*/
|
||||
public abstract class AbsPermissionResultCallBack extends BasePermissionResultCallBack {
|
||||
|
||||
private static Context mContext = PermissionHelper.getApplicationContext();
|
||||
|
||||
protected String message;
|
||||
|
||||
@Override
|
||||
public void onPermissionDenied(String... permissions) {
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(mContext, PermissionDeniedActivity.class);
|
||||
intent.putExtra("permissions", permissions);
|
||||
if (message != null) {
|
||||
intent.putExtra(PermissionDeniedActivity.DENIED_MESSAGE_EXTRA, message);
|
||||
}
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.fengliyan.base.base.ContextHolder;
|
||||
|
||||
/**
|
||||
* Created by zhanghuaijie on 16/9/2.
|
||||
*/
|
||||
public abstract class BasePermissionResultCallBack implements PermissionResultCallBack {
|
||||
|
||||
public static final String NEVER_ASK_PERMISSIONS = "never_ask_permissions";
|
||||
|
||||
@Override
|
||||
public void onRationalShow(PermissionRequest permissionRequest) {
|
||||
permissionRequest.proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeverAskAgain(String... strings) {
|
||||
SharedPreferences neverAskPermissions = ContextHolder.getApplicationContext().getSharedPreferences(NEVER_ASK_PERMISSIONS, Context.MODE_PRIVATE);
|
||||
if (neverAskPermissions != null) {
|
||||
SharedPreferences.Editor editor = neverAskPermissions.edit();
|
||||
for (String permission : strings) {
|
||||
editor.putBoolean(PermissionHelper.getPermissionExplain(permission), true);
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
import android.view.Window;
|
||||
|
||||
/**
|
||||
* Created by yangjinbo on 2016-6-14.
|
||||
*/
|
||||
public class PermissionDeniedActivity extends Activity {
|
||||
|
||||
private static final String TAG = "PermDeniedActivity";
|
||||
|
||||
public static final String DENIED_MESSAGE_EXTRA = "denied_message_extra";
|
||||
|
||||
public static final int REQUEST_CODE_START_APP_SETTING = 3;
|
||||
private PermissionDialog permissionDialog;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.i(TAG, TAG + "onCreate");
|
||||
if (savedInstanceState == null) {
|
||||
handleOnPermissionDeniedIntent(getIntent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
handleOnPermissionDeniedIntent(intent);
|
||||
}
|
||||
|
||||
private void handleOnPermissionDeniedIntent(Intent intent) {
|
||||
String[] permissions;
|
||||
permissions = intent.getStringArrayExtra("permissions");
|
||||
permissionDialog = new PermissionDialog(this, permissions);
|
||||
permissionDialog.show();
|
||||
String msg = intent.getStringExtra(DENIED_MESSAGE_EXTRA);
|
||||
if (msg == null) {
|
||||
msg = "由于一些必要的权限被拒绝了,相应的功能无法使用!";
|
||||
}
|
||||
|
||||
if (permissions == null || permissions.length < 1) {
|
||||
this.finish();
|
||||
return;
|
||||
}
|
||||
AlertDialog.Builder builder;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert);
|
||||
} else {
|
||||
builder = new AlertDialog.Builder(this);
|
||||
}
|
||||
|
||||
StringBuilder permissionNames = new StringBuilder();
|
||||
for (String permission : permissions) {
|
||||
permissionNames.append(PermissionHelper.getPermissionExplain(permission))
|
||||
.append("、");
|
||||
}
|
||||
permissionNames.deleteCharAt(permissionNames.length() - 1);
|
||||
|
||||
final SpannableStringBuilder message = new SpannableStringBuilder(msg + "请前往设置中打开");
|
||||
int start = message.length();
|
||||
message.append(permissionNames);
|
||||
|
||||
message.setSpan(new ForegroundColorSpan(Color.RED), start, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
message.append("权限后使用。");
|
||||
|
||||
builder.setMessage(message);
|
||||
builder.setPositiveButton("立即设置", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent();
|
||||
try {
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.fromParts("package", getPackageName(), null));
|
||||
startActivityForResult(intent, REQUEST_CODE_START_APP_SETTING);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
intent.setAction(Settings.ACTION_APPLICATION_SETTINGS);
|
||||
startActivityForResult(intent, REQUEST_CODE_START_APP_SETTING);
|
||||
} catch (Exception e1) {
|
||||
try {
|
||||
intent.setAction(Settings.ACTION_SETTINGS);
|
||||
startActivityForResult(intent, REQUEST_CODE_START_APP_SETTING);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.setCancelable(false);
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (permissionDialog != null && permissionDialog.isShowing()) {
|
||||
permissionDialog.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.fengliyan.base.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class PermissionDialog extends Dialog {
|
||||
private static final String TAG = "PermissionDialog";
|
||||
private Context mContext;
|
||||
private String[] permissions;
|
||||
|
||||
private TextView tv_permission;
|
||||
|
||||
public PermissionDialog(@NonNull Context context, String[] permission) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
this.permissions = permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.dialog_permission);
|
||||
Window window = this.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
window.setGravity(Gravity.TOP);
|
||||
}
|
||||
// setCanceledOnTouchOutside(false);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
tv_permission = findViewById(R.id.tv_permission);
|
||||
HashMap<Integer, String> map = new HashMap<>();
|
||||
for (String s : permissions) {
|
||||
switch (s) {
|
||||
case Manifest.permission.ACCESS_COARSE_LOCATION:
|
||||
case Manifest.permission.ACCESS_FINE_LOCATION:
|
||||
map.put(1, "定位权限用于完善资料、编辑资料、推荐同城等场景;");
|
||||
break;
|
||||
case Manifest.permission.CAMERA:
|
||||
map.put(2, "相机权限用于拍照、录制、视频通话、认证等场景;");
|
||||
break;
|
||||
case Manifest.permission.WRITE_EXTERNAL_STORAGE:
|
||||
case Manifest.permission.READ_EXTERNAL_STORAGE:
|
||||
map.put(3, "读写手机存储权限用于访问相册及储存图片、文件等场景;");
|
||||
break;
|
||||
case Manifest.permission.RECORD_AUDIO:
|
||||
map.put(4, "访问麦克风用于发送语音、语音通话等场景;");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int key : map.keySet()) {
|
||||
String value = map.get(key);
|
||||
System.out.println("key=" + key + ", vlaue=" + value);
|
||||
str.append(value);
|
||||
}
|
||||
tv_permission.setText(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
boolean isCheck = true;
|
||||
for (String permission : permissions) {
|
||||
if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
isCheck = false;
|
||||
}
|
||||
}
|
||||
if (!isCheck) {
|
||||
super.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.fengliyan.base.base.ContextHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PermissionHelper {
|
||||
|
||||
private static Context sApplicationContext = ContextHolder.getApplicationContext();
|
||||
|
||||
private static SparseArray<PermissionRequestImpl> sRequests = new SparseArray<>();
|
||||
|
||||
private static AtomicInteger sRequestCodeGen = new AtomicInteger(1);
|
||||
|
||||
private static int getRequestCode() {
|
||||
return sRequestCodeGen.getAndIncrement();
|
||||
}
|
||||
|
||||
public static Context getApplicationContext() {
|
||||
return sApplicationContext;
|
||||
}
|
||||
|
||||
private static class PermissionRequestImpl implements PermissionRequest {
|
||||
private String[] mPermissions = null;
|
||||
private String[] mNeedReqPermissions = null;
|
||||
private PermissionResultCallBack mResultCallBack = null;
|
||||
|
||||
public PermissionRequestImpl(String[] permissions, String[] needReqPermissions,
|
||||
PermissionResultCallBack resultCallBack) {
|
||||
this.mPermissions = permissions;
|
||||
this.mResultCallBack = resultCallBack;
|
||||
this.mNeedReqPermissions = needReqPermissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void proceed() {
|
||||
int requestCode = getRequestCode() & 0x7fff;
|
||||
sRequests.put(requestCode, this);
|
||||
requestPermissions(mNeedReqPermissions, requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
mResultCallBack.onPermissionDenied(mNeedReqPermissions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于请求权限
|
||||
*
|
||||
* @param permissions 请求的权限列表
|
||||
* @param callBack 结果回调
|
||||
*/
|
||||
public static void request(@NonNull String[] permissions, @NonNull PermissionResultCallBack callBack) {
|
||||
|
||||
if (sApplicationContext == null) {
|
||||
throw new RuntimeException("Before call PermissionHelper.request(), you must call PermissionHelper.init() once to set a context!");
|
||||
}
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
throw new RuntimeException("request permission only can run in MainThread!");
|
||||
}
|
||||
|
||||
if (permissions.length == 0) {
|
||||
callBack.onPermissionGranted();
|
||||
return;
|
||||
}
|
||||
|
||||
if (VERSION.SDK_INT < VERSION_CODES.M) {
|
||||
callBack.onPermissionGranted();
|
||||
return;
|
||||
}
|
||||
|
||||
String[] needReqPermissions = getPermissionListNeedReq(permissions);
|
||||
|
||||
if (needReqPermissions == null || needReqPermissions.length == 0) {
|
||||
callBack.onPermissionGranted();
|
||||
} else {
|
||||
PermissionRequestImpl request = new PermissionRequestImpl(permissions, needReqPermissions, callBack);
|
||||
callBack.onRationalShow(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过开启一个新的activity作为申请权限的媒介
|
||||
*/
|
||||
private static void requestPermissions(String[] permissions, int requestCode) {
|
||||
Intent intent = new Intent(sApplicationContext, PermissionHelperActivity.class);
|
||||
intent.putExtra("permissions", permissions);
|
||||
intent.putExtra("requestCode", requestCode);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
sApplicationContext.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要请求的权限
|
||||
*
|
||||
* @return 需要请求的权限数组
|
||||
*/
|
||||
private static String[] getPermissionListNeedReq(String permissions[]) {
|
||||
ArrayList<String> needReqPermissions = new ArrayList<>();
|
||||
for (String permissionName : permissions) {
|
||||
// android.permission.WRITE_SETTINGS, android.permission.SYSTEM_ALERT_WINDOW 两个权限需要特殊处理
|
||||
if (permission.WRITE_SETTINGS.equals(permissionName)) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
if (!Settings.System.canWrite(sApplicationContext)) {
|
||||
needReqPermissions.add(permissionName);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (permission.SYSTEM_ALERT_WINDOW.equals(permissionName)) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
if (!Settings.canDrawOverlays(sApplicationContext)) {
|
||||
needReqPermissions.add(permissionName);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int checkRes = ContextCompat.checkSelfPermission(sApplicationContext, permissionName);
|
||||
if (checkRes != PackageManager.PERMISSION_GRANTED) {
|
||||
needReqPermissions.add(permissionName);
|
||||
}
|
||||
// if (!Utility.checkPermission(sApplicationContext, permissionName)) {
|
||||
// needReqPermissions.add(permissionName);
|
||||
// }
|
||||
}
|
||||
if (needReqPermissions.size() == 0) {
|
||||
return null;
|
||||
} else {
|
||||
String[] ret = new String[needReqPermissions.size()];
|
||||
return needReqPermissions.toArray(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请权限结果返回
|
||||
*/
|
||||
static void onRequestPermissionResult(int requestCode, ArrayList<String> deniedPermissions, ArrayList<String> neverAskPermissions) {
|
||||
PermissionRequestImpl request = sRequests.get(requestCode);
|
||||
sRequests.remove(requestCode);
|
||||
|
||||
String[] stillNeedReqPermissions = getPermissionListNeedReq(request.mPermissions);
|
||||
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
if (neverAskPermissions.size() > 0) {
|
||||
request.mResultCallBack.onNeverAskAgain(neverAskPermissions.toArray(new String[neverAskPermissions.size()]));
|
||||
}
|
||||
|
||||
if (deniedPermissions.size() > 0) {
|
||||
request.mResultCallBack.onPermissionDenied(deniedPermissions.toArray(new String[deniedPermissions.size()]));
|
||||
} else if (stillNeedReqPermissions != null && stillNeedReqPermissions.length > 0) {
|
||||
request.mResultCallBack.onPermissionDenied(stillNeedReqPermissions);
|
||||
} else {
|
||||
request.mResultCallBack.onPermissionGranted();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据权限获取相应的中文名称
|
||||
*
|
||||
* @param permissionName 权限
|
||||
* @return 中文名称
|
||||
*/
|
||||
public static String getPermissionExplain(String permissionName) {
|
||||
if (permissionName == null) {
|
||||
return null;
|
||||
} else if (permissionName.equals(permission.READ_CALENDAR)
|
||||
|| permissionName.equals(permission.WRITE_CALENDAR)) {
|
||||
return "日历";
|
||||
} else if (permissionName.equals(permission.CAMERA)) {
|
||||
return "相机";
|
||||
} else if (permissionName.equals(permission.READ_CONTACTS)
|
||||
|| permissionName.equals(permission.WRITE_CONTACTS)
|
||||
|| permissionName.equals(permission.GET_ACCOUNTS)) {
|
||||
return "通讯录";
|
||||
} else if (permissionName.equals(permission.ACCESS_FINE_LOCATION)
|
||||
|| permissionName.equals(permission.ACCESS_COARSE_LOCATION)) {
|
||||
return "位置信息";
|
||||
} else if (permissionName.equals(permission.RECORD_AUDIO)) {
|
||||
return "麦克风";
|
||||
} else if (permissionName.equals(permission.READ_PHONE_STATE)
|
||||
|| permissionName.equals(permission.CALL_PHONE)
|
||||
|| permissionName.equals(permission.READ_CALL_LOG)
|
||||
|| permissionName.equals(permission.WRITE_CALL_LOG)
|
||||
|| permissionName.equals(permission.ADD_VOICEMAIL)
|
||||
|| permissionName.equals(permission.USE_SIP)
|
||||
|| permissionName.equals(permission.PROCESS_OUTGOING_CALLS)) {
|
||||
return "电话";
|
||||
} else if (permissionName.equals(permission.BODY_SENSORS)) {
|
||||
return "身体传感器";
|
||||
} else if (permissionName.equals(permission.SEND_SMS)
|
||||
|| permissionName.equals(permission.RECEIVE_SMS)
|
||||
|| permissionName.equals(permission.READ_SMS)
|
||||
|| permissionName.equals(permission.RECEIVE_WAP_PUSH)
|
||||
|| permissionName.equals(permission.RECEIVE_MMS)) {
|
||||
return "短信";
|
||||
} else if (permissionName.equals(permission.READ_EXTERNAL_STORAGE)
|
||||
|| permissionName.equals(permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
return "存储空间";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class PermissionHelperActivity extends Activity {
|
||||
|
||||
private static final String TAG = "PermissionHelpActivity";
|
||||
|
||||
private ArrayList<String> mShouldRequestList = null;
|
||||
|
||||
private ArrayList<String> mSpecialPermissionList = null;
|
||||
|
||||
// 拒绝的权限
|
||||
private ArrayList<String> mDeniedPermissions = new ArrayList<>();
|
||||
|
||||
// 拒绝的权限
|
||||
private ArrayList<String> mNeverAskPermissions = new ArrayList<>();
|
||||
|
||||
public static final int REQUEST_CODE_WRITE_SETTING = 1;
|
||||
public static final int REQUEST_CODE_ALERT_WINDOW = 2;
|
||||
private PermissionDialog permissionDialog;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.i(TAG, TAG + "onCreate");
|
||||
if (savedInstanceState == null) {
|
||||
handleRequestPermissionsIntent(getIntent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
handleRequestPermissionsIntent(intent);
|
||||
}
|
||||
|
||||
|
||||
// 权限申请
|
||||
private void handleRequestPermissionsIntent(Intent intent) {
|
||||
String[] permissions = intent.getStringArrayExtra("permissions");
|
||||
mShouldRequestList = new ArrayList<>();
|
||||
permissionDialog = new PermissionDialog(this, permissions);
|
||||
permissionDialog.show();
|
||||
for (String permissionName : permissions) {
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissionName)) {
|
||||
mShouldRequestList.add(permissionName);
|
||||
}
|
||||
|
||||
if (permission.WRITE_SETTINGS.equals(permissionName)
|
||||
|| permission.SYSTEM_ALERT_WINDOW.equals(permissionName)) {
|
||||
if (mSpecialPermissionList == null) {
|
||||
mSpecialPermissionList = new ArrayList<>();
|
||||
}
|
||||
mSpecialPermissionList.add(permissionName);
|
||||
}
|
||||
}
|
||||
|
||||
int requestCode = intent.getIntExtra("requestCode", 0);
|
||||
ActivityCompat.requestPermissions(this, permissions, requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (permissionDialog != null && permissionDialog.isShowing()) {
|
||||
permissionDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
|
||||
for (int i = 0; i < permissions.length; i++) {
|
||||
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
|
||||
mDeniedPermissions.add(permissions[i]);
|
||||
if (mShouldRequestList.contains(permissions[i])
|
||||
&& !ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
|
||||
mNeverAskPermissions.add(permissions[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleResult();
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.M)
|
||||
private void handleResult() {
|
||||
if (mSpecialPermissionList == null || mSpecialPermissionList.size() == 0) {
|
||||
int requestCode = getIntent().getIntExtra("requestCode", 0);
|
||||
PermissionHelper.onRequestPermissionResult(requestCode, mDeniedPermissions, mNeverAskPermissions);
|
||||
finish();
|
||||
} else {
|
||||
String permissionName = mSpecialPermissionList.remove(mSpecialPermissionList.size() - 1);
|
||||
if (permission.SYSTEM_ALERT_WINDOW.equals(permissionName)) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + getPackageName()));
|
||||
startActivityForResult(intent, REQUEST_CODE_ALERT_WINDOW);
|
||||
|
||||
} else if (permission.WRITE_SETTINGS.equals(permissionName)) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
|
||||
Uri.parse("package:" + getPackageName()));
|
||||
startActivityForResult(intent, REQUEST_CODE_WRITE_SETTING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_WRITE_SETTING:
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
if (Settings.System.canWrite(this)) {
|
||||
mDeniedPermissions.remove(permission.WRITE_SETTINGS);
|
||||
mNeverAskPermissions.remove(permission.WRITE_SETTINGS);
|
||||
} else if (!mDeniedPermissions.contains(permission.WRITE_SETTINGS)) {
|
||||
mDeniedPermissions.add(permission.WRITE_SETTINGS);
|
||||
}
|
||||
handleResult();
|
||||
}
|
||||
break;
|
||||
case REQUEST_CODE_ALERT_WINDOW:
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
if (Settings.canDrawOverlays(this)) {
|
||||
mDeniedPermissions.remove(permission.SYSTEM_ALERT_WINDOW);
|
||||
mNeverAskPermissions.remove(permission.SYSTEM_ALERT_WINDOW);
|
||||
} else if (!mDeniedPermissions.contains(permission.SYSTEM_ALERT_WINDOW)) {
|
||||
mDeniedPermissions.add(permission.SYSTEM_ALERT_WINDOW);
|
||||
}
|
||||
handleResult();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
/**
|
||||
* 权限请求
|
||||
* Created by yangjinbo on 2016-4-29.
|
||||
*/
|
||||
public interface PermissionRequest {
|
||||
/**
|
||||
* 继续请求
|
||||
*/
|
||||
void proceed();
|
||||
|
||||
/**
|
||||
* 取消请求
|
||||
*/
|
||||
void cancel() ;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.fengliyan.base.base.permission;
|
||||
|
||||
/**
|
||||
* 权限请求的回调
|
||||
* Created by yangjinbo on 2016-4-28.
|
||||
*/
|
||||
public interface PermissionResultCallBack {
|
||||
|
||||
/**
|
||||
* 当所有权限的申请被用户同意之后,该方法会被调用
|
||||
*/
|
||||
void onPermissionGranted();
|
||||
|
||||
/**
|
||||
* 当权限申请中的某一个或多个权限,被用户曾经否定了
|
||||
* 该方法将会被调用
|
||||
*
|
||||
* @param permissions 拒绝的权限
|
||||
*/
|
||||
void onPermissionDenied(String... permissions);
|
||||
|
||||
/**
|
||||
* 当权限申请需要弹出让用户选择时,选择前弹出的解释说明时,该方法将会被调用.
|
||||
* 如果需要停止请求,可以通过调用{@link PermissionRequest#cancel()}取消请求。
|
||||
* 如果要继续请求,需要调用{@link PermissionRequest#proceed()}继续请求。
|
||||
*
|
||||
* @param request 权限请求
|
||||
*/
|
||||
void onRationalShow(PermissionRequest request);
|
||||
|
||||
/**
|
||||
* 当用户拒绝时,并且选择了不再询问时回调
|
||||
*
|
||||
* @param permissions 不在询问的权限
|
||||
*/
|
||||
void onNeverAskAgain(String... permissions);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* AES 加密工具类,目前只支持128bit加密
|
||||
*
|
||||
* @author yangjinbo
|
||||
*/
|
||||
public class AesUtil {
|
||||
|
||||
/**
|
||||
* 加密数据方法
|
||||
*
|
||||
* @param seed 密钥
|
||||
* @param cleartext 待加密内容
|
||||
* @return 返回加密结果
|
||||
*/
|
||||
public static String encrypt(String seed, String cleartext) {
|
||||
try {
|
||||
byte[] rawKey = getRawKey(seed.getBytes());
|
||||
byte[] result = encrypt(rawKey, cleartext.getBytes());
|
||||
return Utility.toHex(result);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to encrypt", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密数据
|
||||
*
|
||||
* @param seed 密钥
|
||||
* @param encrypted 待解密内容
|
||||
* @return 解密结果
|
||||
*/
|
||||
public static String decrypt(String seed, String encrypted) {
|
||||
try {
|
||||
byte[] rawKey = getRawKey(seed.getBytes());
|
||||
byte[] enc = Utility.toByte(encrypted);
|
||||
byte[] result = decrypt(rawKey, enc);
|
||||
return new String(result);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to decrypt", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getRawKey(byte[] seed) throws Exception {
|
||||
KeyGenerator kgen = KeyGenerator.getInstance("AES");
|
||||
SecureRandom sr; // SecureRandom.getInstance("SHA1PRNG");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
|
||||
} else {
|
||||
sr = SecureRandom.getInstance("SHA1PRNG");
|
||||
}
|
||||
sr.setSeed(seed);
|
||||
kgen.init(128, sr); // 192 and 256 bits may not be available
|
||||
SecretKey skey = kgen.generateKey();
|
||||
return skey.getEncoded();
|
||||
}
|
||||
|
||||
public static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||
return cipher.doFinal(clear);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
|
||||
return cipher.doFinal(encrypted);
|
||||
}
|
||||
|
||||
public static String toHex(String txt) {
|
||||
return Utility.toHex(txt.getBytes());
|
||||
}
|
||||
|
||||
public static String fromHex(String hex) {
|
||||
return new String(Utility.toByte(hex));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
182
base/src/main/java/com/fengliyan/base/base/utils/FileUtil.java
Normal file
182
base/src/main/java/com/fengliyan/base/base/utils/FileUtil.java
Normal file
@@ -0,0 +1,182 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.fengliyan.base.base.ContextHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 文件相关操作
|
||||
* Created by yangjinbo on 2015/12/23.
|
||||
*/
|
||||
public class FileUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 获取app的data内部存储的根目录
|
||||
*
|
||||
* @return 存储路径
|
||||
*/
|
||||
public static String getInternalRootDir() {
|
||||
return ContextHolder.getApplicationContext().getFilesDir().getAbsolutePath()
|
||||
+ File.separator + "mucfc" + File.separator;
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasExtentsion(String filename) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot > -1) && (dot < (filename.length() - 1))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app的data内部存储的稳定存储目录,存储在文件夹内的数据默认不删除。
|
||||
*
|
||||
* @return 存储路径
|
||||
*/
|
||||
public static String getInternalStableDir() {
|
||||
return ContextHolder.getApplicationContext().getFilesDir().getAbsolutePath()
|
||||
+ File.separator + "mucfc" + File.separator + "stable" + File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app的SD存储的稳定存储目录,存储在文件夹内的数据默认不删除。
|
||||
*
|
||||
* @return 存储路径
|
||||
*/
|
||||
public static String getExternStableDir() {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return null;
|
||||
}
|
||||
return Environment.getExternalStorageDirectory().getAbsoluteFile() + File.separator
|
||||
+ "mucfc" + File.separator + "stable" + File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取招联金融所有应用在sdcard 目录下存储根目录,后续所有招联应用都使用此目录存储。
|
||||
*
|
||||
* @return sdcard的存储路径,当sdcard不可用时,返回null
|
||||
*/
|
||||
public static String getExternalRootDir() {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return null;
|
||||
}
|
||||
return Environment.getExternalStorageDirectory().getAbsoluteFile() + File.separator
|
||||
+ "mucfc" + File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app在sdcard 目录下存储根目录。
|
||||
*
|
||||
* @return sdcard的存储路径,当sdcard不可用时,返回null
|
||||
*/
|
||||
public static String getExternalAppRootDir() {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return null;
|
||||
}
|
||||
return Environment.getExternalStorageDirectory().getAbsoluteFile() + File.separator
|
||||
+ "mucfc" + File.separator + ContextHolder.getApplicationContext().getPackageName()
|
||||
+ File.separator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除文件夹及其文件夹里面的文件
|
||||
*
|
||||
* @param path 文件夹
|
||||
* @return true 删成功了, false未删除成功,但是文件夹里面的部分内容可能已经删除。
|
||||
*/
|
||||
public static boolean deleteFolder(String path) {
|
||||
File dir = new File(path);
|
||||
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 递归删除目录中的子目录下
|
||||
String[] children = dir.list();
|
||||
if (children != null) {
|
||||
for (String child : children) {
|
||||
File file = new File(dir, child);
|
||||
if (file.isFile() && !file.delete()) {
|
||||
return false;
|
||||
}
|
||||
if (file.isDirectory() && !deleteFolder(file.getPath())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 目录此时为空,可以删除
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件中的内容读入到byte数组中
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件的byte数组,当文件不存在或为目录时,返回的{@code null}。
|
||||
* @throws IllegalArgumentException if {@code fileName} is {@code null}。
|
||||
*/
|
||||
public static byte[] readToByteArray(String fileName) {
|
||||
if (fileName == null) {
|
||||
throw new IllegalArgumentException("fileName cannot be null!");
|
||||
}
|
||||
File file = new File(fileName);
|
||||
if (!file.exists() || file.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = new FileInputStream(fileName);
|
||||
byte[] buffer = new byte[(int) file.length()];
|
||||
if (input.read(buffer) == -1) {
|
||||
return null;
|
||||
} else {
|
||||
return buffer;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
} finally {
|
||||
Utility.closeSilently(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容,并以字符串的形式返回
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 当文件不存在或为目录时,返回的{@code null}。
|
||||
* @throws IllegalArgumentException if {@code fileName} is {@code null}。
|
||||
*/
|
||||
public static String readFileToString(String fileName) {
|
||||
if (fileName == null) {
|
||||
throw new IllegalArgumentException("fileName cannot be null!");
|
||||
}
|
||||
|
||||
File file = new File(fileName);
|
||||
if (!file.exists() || file.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
FileReader fileReader = null;
|
||||
try {
|
||||
fileReader = new FileReader(file);
|
||||
char[] buffer = new char[(int) file.length()];
|
||||
fileReader.read(buffer);
|
||||
return new String(buffer);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
} finally {
|
||||
Utility.closeSilently(fileReader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 压缩图片
|
||||
* Created by yangjinbo on 2016/2/19.
|
||||
*/
|
||||
public class ImageCompressUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 压缩图片
|
||||
*
|
||||
* @param maxSize 需要压缩的大小
|
||||
* @param imageFile 图片路径
|
||||
* @param deleteOriginal 是否删除原始图片,true删除,false不删除
|
||||
* @return 压缩后的图片路径
|
||||
*/
|
||||
public static String compress(int maxSize, String imageFile, boolean deleteOriginal) {
|
||||
File file = new File(imageFile);
|
||||
long size = file.length();
|
||||
if (size < maxSize) {
|
||||
return imageFile;
|
||||
}
|
||||
|
||||
String newImageName = null;
|
||||
FileOutputStream out = null;
|
||||
Bitmap bmp = null;
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = (int) (Math.sqrt(size / maxSize) + 0.8f);
|
||||
bmp = BitmapFactory.decodeFile(imageFile, options);
|
||||
File newFile = File.createTempFile("tmp-", ".dat", file.getParentFile());
|
||||
out = new FileOutputStream(newFile);
|
||||
bmp.compress(Bitmap.CompressFormat.JPEG, 80, out);
|
||||
newImageName = newFile.getAbsolutePath();
|
||||
if (deleteOriginal) {
|
||||
new File(imageFile).delete();
|
||||
}
|
||||
return newImageName;
|
||||
} catch (OutOfMemoryError e) {
|
||||
return imageFile;
|
||||
} catch (IOException e) {
|
||||
return imageFile;
|
||||
} finally {
|
||||
Utility.closeSilently(out);
|
||||
if (bmp != null) {
|
||||
bmp.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩图片,会删除原始图片
|
||||
*
|
||||
* @param maxSize 需要压缩的大小
|
||||
* @param imageFile 图片路径
|
||||
* @return 压缩后的图片路径
|
||||
*/
|
||||
public static String compress(int maxSize, String imageFile) {
|
||||
return compress(maxSize, imageFile, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* MD5的相关操作
|
||||
* Created by yangjinbo on 2015/12/23.
|
||||
*/
|
||||
public class Md5Util {
|
||||
|
||||
private static final String HASH_ALGORITHM = "MD5";
|
||||
|
||||
/**
|
||||
* 获取文件MD5
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 当文件不存在或者是目录时以及文件读取和MD5算法不存在时,返回null;其他返回文件MD5值
|
||||
*/
|
||||
public static String getFileMd5(String fileName) {
|
||||
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(fileName);
|
||||
if (!file.exists() || file.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
byte[] md5 = getMD5(file);
|
||||
if (md5 == null) {
|
||||
return null;
|
||||
}
|
||||
return Utility.toHex(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串MD5
|
||||
*
|
||||
* @param text 字符串
|
||||
* @return 字符串转换为16进制的Md5值。当字符串为空时或发生错误时,返回null
|
||||
*/
|
||||
public static String getStringMd5(String text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] md5 = getMD5(text.getBytes());
|
||||
if (md5 == null) {
|
||||
return null;
|
||||
}
|
||||
return Utility.toHex(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的MD5
|
||||
*
|
||||
* @param file 文件
|
||||
*/
|
||||
private static byte[] getMD5(File file) {
|
||||
InputStream fis = null;
|
||||
byte[] md5 = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
|
||||
int numRead;
|
||||
while ((numRead = fis.read(buffer)) != -1) {
|
||||
digest.update(buffer, 0, numRead);
|
||||
}
|
||||
md5 = digest.digest();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
Utility.closeSilently(fis);
|
||||
}
|
||||
return md5;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取byte数组的md5
|
||||
*
|
||||
* @param data 数据
|
||||
*/
|
||||
private static byte[] getMD5(byte[] data) {
|
||||
byte[] hash;
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
|
||||
digest.update(data);
|
||||
hash = digest.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
/**
|
||||
* Created by zhangbin on 2019/2/21.
|
||||
*/
|
||||
|
||||
public class NoClearSPUtils {
|
||||
|
||||
private final static String name = "no_clear_sp";
|
||||
private final static int mode = Context.MODE_PRIVATE;
|
||||
|
||||
/**
|
||||
* 保存首选项
|
||||
*
|
||||
* @param context
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public static void saveBoolean(Context context, String key, boolean value) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
SharedPreferences.Editor edit = sp.edit();
|
||||
edit.putBoolean(key, value);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
public static void saveInt(Context context, String key, int value) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
SharedPreferences.Editor edit = sp.edit();
|
||||
edit.putInt(key, value);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
public static void saveString(Context context, String key, String value) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
SharedPreferences.Editor edit = sp.edit();
|
||||
edit.putString(key, value);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取首选项
|
||||
*
|
||||
* @param context
|
||||
* @param key
|
||||
* @param defValue
|
||||
* @return
|
||||
*/
|
||||
public static boolean getBoolean(Context context, String key, boolean defValue) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getBoolean(key, defValue);
|
||||
}
|
||||
|
||||
public static boolean getBoolean(Context context, String key) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getBoolean(key, false);
|
||||
}
|
||||
|
||||
public static int getInt(Context context, String key, int defValue) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getInt(key, defValue);
|
||||
}
|
||||
|
||||
public static int getInt(Context context, String key) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getInt(key, 0);
|
||||
}
|
||||
|
||||
public static String getString(Context context, String key, String defValue) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getString(key, defValue);
|
||||
}
|
||||
|
||||
public static String getString(Context context, String key) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
return sp.getString(key, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除保存
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static void clear(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(name, mode);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.clear();
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NotificationBadgesUtils {
|
||||
|
||||
/**
|
||||
* 应用角标工具类
|
||||
*/
|
||||
private static int notificationId = 0;
|
||||
|
||||
public static boolean setCount(final int count, final Context context) {
|
||||
if (count >= 0 && context != null) {
|
||||
Log.d("BRAND", Build.BRAND);
|
||||
Log.v("-=-", "角标数量" + count);
|
||||
Log.v("-=-", "Build.BRAND.toLowerCase()" + Build.BRAND.toLowerCase());
|
||||
switch (Build.BRAND.toLowerCase()) {
|
||||
case "xiaomi":
|
||||
case "redmi":
|
||||
// new Handler().postDelayed(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// setNotificationBadge(count, context);
|
||||
// }
|
||||
// }, 3000);
|
||||
setXiaomiBadge(count);
|
||||
return true;
|
||||
case "huawei":
|
||||
return setHuaweiBadge(count, context);
|
||||
case "honor":
|
||||
return setHonorBadge(count, context);
|
||||
case "samsung":
|
||||
return setSamsungBadge(count, context);
|
||||
case "oppo":
|
||||
return setOPPOBadge(count, context) || setOPPOBadge2(count, context);
|
||||
case "vivo":
|
||||
return setVivoBadge(count, context);
|
||||
case "lenovo":
|
||||
return setZukBadge(count, context);
|
||||
case "htc":
|
||||
return setHTCBadge(count, context);
|
||||
case "sony":
|
||||
return setSonyBadge(count, context);
|
||||
// default:
|
||||
// return setNotificationBadge(count, context);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// public static boolean setNotificationBadge(int count, Context context) {
|
||||
// NotificationManager notificationManager = (NotificationManager) context.getSystemService
|
||||
// (Context.NOTIFICATION_SERVICE);
|
||||
// if (notificationManager == null) {
|
||||
// return false;
|
||||
// }
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// // 8.0之后添加角标需要NotificationChannel
|
||||
// NotificationChannel channel = new NotificationChannel("badge", "badge",
|
||||
// NotificationManager.IMPORTANCE_DEFAULT);
|
||||
// channel.setShowBadge(true);
|
||||
// notificationManager.createNotificationChannel(channel);
|
||||
// }
|
||||
// Intent intent = new Intent(context, MainActivity.class);
|
||||
// PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
|
||||
// Notification notification = new NotificationCompat.Builder(context, "badge")
|
||||
// .setContentTitle(context.getResources().getString(R.string.application_angle))
|
||||
// .setContentText(context.getResources().getString(R.string.you_have) + count + context.getResources().getString(R.string.unread_message))
|
||||
// .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap
|
||||
// .ic_launcher))
|
||||
// .setSmallIcon(R.mipmap.ic_launcher)
|
||||
// .setAutoCancel(true)
|
||||
// .setContentIntent(pendingIntent)
|
||||
// .setChannelId("badge")
|
||||
// .setNumber(count)
|
||||
// .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL).build();
|
||||
// // 小米
|
||||
// if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
|
||||
// setXiaomiBadge(count);
|
||||
// }
|
||||
// notificationManager.notify(notificationId++, notification);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
private static void setXiaomiBadge(int count) {
|
||||
try {
|
||||
Notification notification = new Notification();
|
||||
Field field = notification.getClass().getDeclaredField("extraNotification");
|
||||
Object extraNotification = field.get(notification);
|
||||
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int
|
||||
.class);
|
||||
method.invoke(extraNotification, count);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setHonorBadge(int count, Context context) {
|
||||
try {
|
||||
String launchClassName = getLauncherClassName(context);
|
||||
if (TextUtils.isEmpty(launchClassName)) {
|
||||
return false;
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("package", context.getPackageName());
|
||||
bundle.putString("class", launchClassName);
|
||||
bundle.putInt("badgenumber", count);
|
||||
context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher" +
|
||||
".settings/badge/"), "change_badge", null, bundle);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setHuaweiBadge(int count, Context context) {
|
||||
try {
|
||||
String launchClassName = getLauncherClassName(context);
|
||||
if (TextUtils.isEmpty(launchClassName)) {
|
||||
return false;
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("package", context.getPackageName());
|
||||
bundle.putString("class", launchClassName);
|
||||
bundle.putInt("badgenumber", count);
|
||||
context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher" + ".settings/badge/"), "change_badge", null, bundle);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setSamsungBadge(int count, Context context) {
|
||||
try {
|
||||
String launcherClassName = getLauncherClassName(context);
|
||||
if (TextUtils.isEmpty(launcherClassName)) {
|
||||
return false;
|
||||
}
|
||||
Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
|
||||
intent.putExtra("badge_count", count);
|
||||
intent.putExtra("badge_count_package_name", context.getPackageName());
|
||||
intent.putExtra("badge_count_class_name", launcherClassName);
|
||||
context.sendBroadcast(intent);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static boolean setOPPOBadge(int count, Context context) {
|
||||
try {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putInt("app_badge_count", count);
|
||||
context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"),
|
||||
"setAppBadgeCount", String.valueOf(count), extras);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static boolean setOPPOBadge2(int count, Context context) {
|
||||
try {
|
||||
Intent intent = new Intent("com.oppo.unsettledevent");
|
||||
intent.putExtra("packageName", context.getPackageName());
|
||||
intent.putExtra("number", count);
|
||||
intent.putExtra("upgradeNumber", count);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
|
||||
if (receivers != null && receivers.size() > 0) {
|
||||
context.sendBroadcast(intent);
|
||||
} else {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putInt("app_badge_count", count);
|
||||
context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"),
|
||||
"setAppBadgeCount", null, extras);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setVivoBadge(int count, Context context) {
|
||||
try {
|
||||
String launcherClassName = getLauncherClassName(context);
|
||||
if (TextUtils.isEmpty(launcherClassName)) {
|
||||
return false;
|
||||
}
|
||||
Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
|
||||
intent.putExtra("packageName", context.getPackageName());
|
||||
intent.putExtra("className", launcherClassName);
|
||||
intent.putExtra("notificationNum", count);
|
||||
context.sendBroadcast(intent);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setZukBadge(int count, Context context) {
|
||||
try {
|
||||
Bundle extra = new Bundle();
|
||||
ArrayList<String> ids = new ArrayList<>();
|
||||
// 以列表形式传递快捷方式id,可以添加多个快捷方式id
|
||||
// ids.add("custom_id_1");
|
||||
// ids.add("custom_id_2");
|
||||
extra.putStringArrayList("app_shortcut_custom_id", ids);
|
||||
extra.putInt("app_badge_count", count);
|
||||
Uri contentUri = Uri.parse("content://com.android.badge/badge");
|
||||
Bundle bundle = context.getContentResolver().call(contentUri, "setAppBadgeCount", null,
|
||||
extra);
|
||||
return bundle != null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setHTCBadge(int count, Context context) {
|
||||
try {
|
||||
ComponentName launcherComponentName = getLauncherComponentName(context);
|
||||
if (launcherComponentName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Intent intent1 = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
|
||||
intent1.putExtra("com.htc.launcher.extra.COMPONENT", launcherComponentName
|
||||
.flattenToShortString());
|
||||
intent1.putExtra("com.htc.launcher.extra.COUNT", count);
|
||||
context.sendBroadcast(intent1);
|
||||
|
||||
Intent intent2 = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
|
||||
intent2.putExtra("packagename", launcherComponentName.getPackageName());
|
||||
intent2.putExtra("count", count);
|
||||
context.sendBroadcast(intent2);
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setSonyBadge(int count, Context context) {
|
||||
String launcherClassName = getLauncherClassName(context);
|
||||
if (TextUtils.isEmpty(launcherClassName)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
//官方给出方法
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put("badge_count", count);
|
||||
contentValues.put("package_name", context.getPackageName());
|
||||
contentValues.put("activity_name", launcherClassName);
|
||||
SonyAsyncQueryHandler asyncQueryHandler = new SonyAsyncQueryHandler(context
|
||||
.getContentResolver());
|
||||
asyncQueryHandler.startInsert(0, null, Uri.parse("content://com.sonymobile.home" +
|
||||
".resourceprovider/badge"), contentValues);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
//网上大部分使用方法
|
||||
Intent intent = new Intent("com.sonyericsson.home.action.UPDATE_BADGE");
|
||||
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", count > 0);
|
||||
intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME",
|
||||
launcherClassName);
|
||||
intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String
|
||||
.valueOf(count));
|
||||
intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context
|
||||
.getPackageName());
|
||||
context.sendBroadcast(intent);
|
||||
return true;
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getLauncherClassName(Context context) {
|
||||
ComponentName launchComponent = getLauncherComponentName(context);
|
||||
if (launchComponent == null) {
|
||||
return "";
|
||||
} else {
|
||||
return launchComponent.getClassName();
|
||||
}
|
||||
}
|
||||
|
||||
private static ComponentName getLauncherComponentName(Context context) {
|
||||
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context
|
||||
.getPackageName());
|
||||
if (launchIntent != null) {
|
||||
return launchIntent.getComponent();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class SonyAsyncQueryHandler extends AsyncQueryHandler {
|
||||
|
||||
SonyAsyncQueryHandler(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
209
base/src/main/java/com/fengliyan/base/base/utils/RsaUtil.java
Normal file
209
base/src/main/java/com/fengliyan/base/base/utils/RsaUtil.java
Normal file
@@ -0,0 +1,209 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
/**
|
||||
* RSA加密方式
|
||||
*/
|
||||
public class RsaUtil {
|
||||
|
||||
// 公钥
|
||||
public static final String PUBLIC_KEY = "PublicKey";
|
||||
// 私钥
|
||||
public static final String PRIVATE_KEY = "PrivateKey";
|
||||
/**
|
||||
* RSA最大加密明文大小
|
||||
*/
|
||||
private static final int MAX_ENCRYPT_BLOCK = 117;
|
||||
/**
|
||||
* RSA最大解密密文大小
|
||||
*/
|
||||
private static final int MAX_DECRYPT_BLOCK = 128;
|
||||
private static final int KEY_LENGTH = 256;
|
||||
|
||||
/**
|
||||
* 字符串加密
|
||||
*
|
||||
* @param clearText
|
||||
* @param publicKey
|
||||
* @return 返回密文的BASE64字符串
|
||||
*/
|
||||
public static String encryptByPublicKey(String clearText, String publicKey) {
|
||||
|
||||
if (null == clearText) {
|
||||
throw new IllegalArgumentException("clearText cannot be null");
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] clearBytes = clearText.getBytes("UTF-8");
|
||||
byte[] encryptBytes = encryptByPublicKey(clearBytes, publicKey);
|
||||
return new String(Base64.encode(encryptBytes, Base64.DEFAULT), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Failed to encrypt with public key", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密数据
|
||||
*
|
||||
* @param data 加密内容
|
||||
* @param publicKey 加密公钥
|
||||
* @return 加密后的结果
|
||||
*/
|
||||
public static byte[] encryptByPublicKey(byte[] data, String publicKey) {
|
||||
|
||||
if (null == data) {
|
||||
throw new IllegalArgumentException("data cannot be null");
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(publicKey)) {
|
||||
throw new IllegalArgumentException("publicKey cannot be null or empty");
|
||||
}
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
byte[] bytePublicKey = Base64.decode(publicKey, Base64.DEFAULT);
|
||||
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(bytePublicKey);
|
||||
Key publicK = keyFactory.generatePublic(x509EncodedKeySpec);
|
||||
|
||||
// 对数据加密
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); //Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicK);
|
||||
int inputLen = data.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段加密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_ENCRYPT_BLOCK;
|
||||
}
|
||||
byte[] encryptedData = out.toByteArray();
|
||||
return encryptedData;
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to encrypt with public key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BASE64密文解密
|
||||
*
|
||||
* @param encryptedBase64Text BASE64编码的密文
|
||||
* @param privateKey
|
||||
* @return
|
||||
*/
|
||||
public static String decryptByPrivateKey(String encryptedBase64Text, String privateKey) {
|
||||
|
||||
if (null == encryptedBase64Text) {
|
||||
throw new IllegalArgumentException("encryptedBase64Text cannot be null");
|
||||
}
|
||||
try {
|
||||
byte[] encryptedBytes = Base64.decode(encryptedBase64Text.getBytes("UTF-8"), Base64.DEFAULT);
|
||||
byte[] clearBytes = decryptByPrivateKey(encryptedBytes, privateKey);
|
||||
return new String(clearBytes, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Failed to decrypt with private key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密内容
|
||||
*
|
||||
* @param encryptedData 待解密数据
|
||||
* @param privateKey 私钥
|
||||
* @return 解密后的结果
|
||||
*/
|
||||
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) {
|
||||
|
||||
if (null == encryptedData) {
|
||||
throw new IllegalArgumentException("encryptedData cannot be null");
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(privateKey)) {
|
||||
throw new IllegalArgumentException("privateKey cannot be null or empty");
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] keyBytes = Base64.decode(privateKey, Base64.DEFAULT);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");//Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateK);
|
||||
int inputLen = encryptedData.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段解密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
|
||||
cache = cipher
|
||||
.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher
|
||||
.doFinal(encryptedData, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_DECRYPT_BLOCK;
|
||||
}
|
||||
byte[] decryptedData = out.toByteArray();
|
||||
return decryptedData;
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to decrypt with private key", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> getGenKeyPair() {
|
||||
try {
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
|
||||
kpg.initialize(1024);
|
||||
KeyPair keyPair = kpg.generateKeyPair();
|
||||
|
||||
byte[] pubKeyBytes = Base64.encode(keyPair.getPublic().getEncoded(), Base64.DEFAULT);
|
||||
byte[] priKeyBytes = Base64.encode(keyPair.getPrivate().getEncoded(), Base64.DEFAULT);
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put(PUBLIC_KEY, new String(pubKeyBytes));
|
||||
map.put(PRIVATE_KEY, new String(priKeyBytes));
|
||||
return map;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
base/src/main/java/com/fengliyan/base/base/utils/Utility.java
Normal file
118
base/src/main/java/com/fengliyan/base/base/utils/Utility.java
Normal file
@@ -0,0 +1,118 @@
|
||||
package com.fengliyan.base.base.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 存放一些小的较独立的方法
|
||||
* Created by yangjinbo on 2015/12/25.
|
||||
*/
|
||||
public class Utility {
|
||||
|
||||
|
||||
/**
|
||||
* 关闭资源,不抛出异常
|
||||
*
|
||||
* @param closeable 待关闭资源
|
||||
*/
|
||||
public static void closeSilently(Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查权限是否同意
|
||||
* @param permission 权限名称
|
||||
* @return true 具有该权限
|
||||
*/
|
||||
public static boolean checkPermission(Context context, String permission) {
|
||||
return context.getPackageManager().checkPermission(permission, context.getPackageName()) == PackageManager
|
||||
.PERMISSION_GRANTED;
|
||||
}
|
||||
/**
|
||||
* 获取随机字符串
|
||||
* @param length 字符串长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String getRandomString(int length) {
|
||||
if(length < 0) {
|
||||
throw new IllegalArgumentException("The length cannot be a negative!");
|
||||
}
|
||||
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = random.nextInt(base.length());
|
||||
sb.append(base.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将16进制字符串转为byte数组
|
||||
*
|
||||
* @param hexString 待转数组
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] toByte(String hexString) {
|
||||
if (hexString == null) {
|
||||
return null;
|
||||
}
|
||||
int len = hexString.length() / 2;
|
||||
byte[] result = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将byte数组转为16进制字符串
|
||||
*
|
||||
* @param buf 待转数组
|
||||
*/
|
||||
public static String toHex(byte[] buf) {
|
||||
if (buf == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer result = new StringBuffer(2 * buf.length);
|
||||
for (byte b : buf) {
|
||||
appendHex(result, b);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private final static String HEX = "0123456789abcdef";
|
||||
|
||||
private static void appendHex(StringBuffer sb, byte b) {
|
||||
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统的prop属性
|
||||
* @param key 属性的key
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getSystemProperties(Context context, String key) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Class SystemProperties = context.getClassLoader().loadClass("android.os.SystemProperties");
|
||||
Method get = SystemProperties.getMethod("get", String.class);
|
||||
return (String) get.invoke(null, key);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
base/src/main/res/layout/dialog_permission.xml
Normal file
40
base/src/main/res/layout/dialog_permission.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:orientation="vertical"
|
||||
tools:viewBindingIgnore="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="25dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:background="#cdcdcd"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="70dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="设备权限使用说明"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_permission"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="用于识别设备,进行信息推送和安全保障等功能"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
3
base/src/main/res/values/strings.xml
Normal file
3
base/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Base</string>
|
||||
</resources>
|
||||
17
base/src/test/java/com/fengliyan/base/ExampleUnitTest.java
Normal file
17
base/src/test/java/com/fengliyan/base/ExampleUnitTest.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.fengliyan.base;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user