tasks = am.getRunningTasks(1);
- if (!tasks.isEmpty()) {
- ComponentName topActivity = tasks.get(0).topActivity;
- if (!topActivity.getPackageName().equals(context.getPackageName())) {
- return true;
- }
- }
- return false;
-}
-```
diff --git a/about_device.md b/about_device.md
deleted file mode 100644
index bfdccbbeb5..0000000000
--- a/about_device.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# 设备相关
-### 获取设备MAC地址
-``` java
-/**
- * 获取设备MAC地址
- * 需添加权限
- */
-public static String getMacAddress(Context context) {
- String macAddress;
- WifiManager wifi = (WifiManager) context
- .getSystemService(Context.WIFI_SERVICE);
- WifiInfo info = wifi.getConnectionInfo();
- macAddress = info.getMacAddress();
- if (null == macAddress) {
- return "";
- }
- macAddress = macAddress.replace(":", "");
- return macAddress;
-}
-```
-
-### 获取设备厂商,如Xiaomi
-``` java
-/**
-* 获取设备厂商,如Xiaomi
-*/
-public static String getManufacturer() {
- String MANUFACTURER = Build.MANUFACTURER;
- return MANUFACTURER;
-}
-```
-
-### 获取设备型号,如MI2SC
-``` java
-/**
- * 获取设备型号,如MI2SC
- */
-public static String getModel() {
- String model = Build.MODEL;
- if (model != null) {
- model = model.trim().replaceAll("\\s*", "");
- } else {
- model = "";
- }
- return model;
-}
-```
-
-### 获取设备SD卡是否可用
-``` java
-/**
- * 获取设备SD卡是否可用
- */
-public static boolean isSDCardEnable() {
- return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
-}
-```
-
-### 获取设备SD卡路径
-```
-/**
- * 获取设备SD卡路径
- *
一般是/storage/emulated/0/
- */
-public static String getSDCardPath() {
- return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
-}
-```
diff --git a/about_encrypt.md b/about_encrypt.md
deleted file mode 100644
index ab1d1cb37a..0000000000
--- a/about_encrypt.md
+++ /dev/null
@@ -1,148 +0,0 @@
-# 加解密相关
-### MD5加密
-``` java
-/**
- * MD5加密
- *
- * @param data 明文字符串
- * @return 密文
- */
-public static String getMD5(String data) {
- return getMD5(data.getBytes());
-}
-
-/**
- * MD5加密
- *
- * @param data 明文字符串
- * @param salt 盐
- * @return 密文
- */
-public static String getMD5(String data, String salt) {
- return bytes2Hex(encryptMD5((data + salt).getBytes()));
-}
-
-/**
- * MD5加密
- *
- * @param data 明文字节数组
- * @return 密文
- */
-public static String getMD5(byte[] data) {
- return bytes2Hex(encryptMD5(data));
-}
-
-/**
- * MD5加密
- *
- * @param data 明文字节数组
- * @param salt 盐字节数组
- * @return 密文
- */
-public static String getMD5(byte[] data, byte[] salt) {
- byte[] dataSalt = new byte[data.length + salt.length];
- System.arraycopy(data, 0, dataSalt, 0, data.length);
- System.arraycopy(salt, 0, dataSalt, data.length, salt.length);
- return bytes2Hex(encryptMD5(dataSalt));
-}
-
-/**
- * MD5加密
- *
- * @param data 明文字节数组
- * @return 密文字节数组
- */
-public static byte[] encryptMD5(byte[] data) {
- try {
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(data);
- return md.digest();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return new byte[0];
-}
-
-/**
- * 获取文件的MD5校验码
- *
- * @param filePath 文件路径
- * @return 文件的MD5校验码
- */
-public static String getMD5File(String filePath) {
- FileInputStream in = null;
- try {
- MessageDigest md = MessageDigest.getInstance("MD5");
- in = new FileInputStream(filePath);
- int len;
- byte[] buffer = new byte[1024];
- while ((len = in.read(buffer)) != -1) {
- md.update(buffer, 0, len);
- }
- return bytes2Hex(md.digest());
- } catch (NoSuchAlgorithmException | IOException e) {
- e.printStackTrace();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException ignored) {
- }
- }
- }
- return "";
-}
-```
-
-### SHA加密
-```
-/**
- * SHA加密
- *
- * @param data 明文字符串
- * @return 密文
- */
-public static String getSHA(String data) {
- return getSHA(data.getBytes());
-}
-
-/**
- * SHA加密
- *
- * @param data 明文字节数组
- * @return 密文
- */
-public static String getSHA(byte[] data) {
- return bytes2Hex(encryptSHA(data));
-}
-
-/**
- * SHA加密
- *
- * @param data 明文字节数组
- * @return 密文字节数组
- */
-public static byte[] encryptSHA(byte[] data) {
- try {
- MessageDigest md = MessageDigest.getInstance("SHA");
- md.update(data);
- return md.digest();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return new byte[0];
-}
-
-/**
- * 一个byte转为2个hex字符
- */
-public static String bytes2Hex(byte[] src) {
- char[] res = new char[src.length * 2];
- final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- for (int i = 0, j = 0; i < src.length; i++) {
- res[j++] = hexDigits[src[i] >>> 4 & 0x0f];
- res[j++] = hexDigits[src[i] & 0x0f];
- }
- return new String(res);
-}
-```
diff --git a/about_keyboard.md b/about_keyboard.md
deleted file mode 100644
index 5cadb8fdd5..0000000000
--- a/about_keyboard.md
+++ /dev/null
@@ -1,126 +0,0 @@
-# 键盘相关
-### 避免输入法面板遮挡
-``` java
-// 在manifest.xml中activity中设置
-android:windowSoftInputMode="stateVisible|adjustResize"
-```
-
-### 动态隐藏软键盘
-``` java
-/**
-* 动态隐藏软键盘
-*/
-public static void hideSoftInput(Activity activity) {
- View view = activity.getWindow().peekDecorView();
- if (view != null) {
- InputMethodManager inputmanger = (InputMethodManager) activity
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0);
- }
-}
-
-/**
-* 动态隐藏软键盘
-*/
-public static void hideSoftInput(Context context, EditText edit) {
- edit.clearFocus();
- InputMethodManager inputmanger = (InputMethodManager) context
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- inputmanger.hideSoftInputFromWindow(edit.getWindowToken(), 0);
-}
-```
-
-### 点击屏幕空白区域隐藏软键盘
-``` java
-/**
- * 点击屏幕空白区域隐藏软键盘(方法0)
- *
在onTouch中处理,未获焦点则隐藏
- *
参照以下注释代码
- */
-public static void clickBlankArea2HideSoftInput0() {
- Log.i("tips", "U should copy the following code.");
- /*
- @Override
- public boolean onTouchEvent (MotionEvent event){
- if (null != this.getCurrentFocus()) {
- InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
- return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
- }
- return super.onTouchEvent(event);
- }
- */
-}
-
-/**
- * 点击屏幕空白区域隐藏软键盘(方法1)
- *
根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
- *
需重写dispatchTouchEvent
- *
参照以下注释代码
- */
-public static void clickBlankArea2HideSoftInput1() {
- Log.i("tips", "U should copy the following code.");
- /*
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- View v = getCurrentFocus();
- if (isShouldHideKeyboard(v, ev)) {
- hideKeyboard(v.getWindowToken());
- }
- }
- return super.dispatchTouchEvent(ev);
- }
- // 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
- private boolean isShouldHideKeyboard(View v, MotionEvent event) {
- if (v != null && (v instanceof EditText)) {
- int[] l = {0, 0};
- v.getLocationInWindow(l);
- int left = l[0],
- top = l[1],
- bottom = top + v.getHeight(),
- right = left + v.getWidth();
- return !(event.getX() > left && event.getX() < right
- && event.getY() > top && event.getY() < bottom);
- }
- return false;
- }
- // 获取InputMethodManager,隐藏软键盘
- private void hideKeyboard(IBinder token) {
- if (token != null) {
- InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
- }
- }
- */
-}
-```
-
-### 动态显示软键盘
-``` java
-/**
-* 动态显示软键盘
-*/
-public static void showSoftInput(Context context, EditText edit) {
- edit.setFocusable(true);
- edit.setFocusableInTouchMode(true);
- edit.requestFocus();
- InputMethodManager inputManager = (InputMethodManager) context
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.showSoftInput(edit, 0);
-}
-```
-
-### 切换键盘显示与否状态
-``` java
-/**
-* 切换键盘显示与否状态
-*/
-public static void toggleSoftInput(Context context, EditText edit) {
- edit.setFocusable(true);
- edit.setFocusableInTouchMode(true);
- edit.requestFocus();
- InputMethodManager inputManager = (InputMethodManager) context
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
-}
-```
diff --git a/about_network.md b/about_network.md
deleted file mode 100644
index 547ac05b20..0000000000
--- a/about_network.md
+++ /dev/null
@@ -1,210 +0,0 @@
-# 网络相关
-### 打开网络设置界面
-``` java
-/**
- * 打开网络设置界面
- *
3.0以下打开设置界面
- */
-public static void openWirelessSettings(Context context) {
- if (android.os.Build.VERSION.SDK_INT > 10) {
- context.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
- } else {
- context.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS));
- }
-}
-```
-
-### 判断网络是否可用
-``` java
-/**
- * 获取活动网路信息
- */
-private static NetworkInfo getActiveNetworkInfo(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- return cm.getActiveNetworkInfo();
-}
-
-/**
- * 判断网络是否可用
- *
需添加权限
- */
-public static boolean isAvailable(Context context) {
- NetworkInfo info = getActiveNetworkInfo(context);
- return info != null && info.isAvailable();
-}
-```
-
-### 判断网络是否连接
-``` java
-/**
- * 判断网络是否连接
- *
需添加权限
- */
-public static boolean isConnected(Context context) {
- NetworkInfo info = getActiveNetworkInfo(context);
- return info != null && info.isConnected();
-}
-```
-
-### 判断网络是否是4G
-``` java
-/**
- * 判断网络是否是4G
- *
需添加权限
- */
-public static boolean is4G(Context context) {
- NetworkInfo info = getActiveNetworkInfo(context);
- return info != null && info.isAvailable() && info.getSubtype() == TelephonyManager.NETWORK_TYPE_LTE;
-}
-```
-
-### 判断wifi是否连接状态
-``` java
-/**
- * 判断wifi是否连接状态
- *
需添加权限
- */
-public static boolean isWifiConnected(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- return cm != null && cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;
-}
-```
-
-### 获取移动网络运营商名称
-``` java
-/**
- * 获取移动网络运营商名称
- *
如中国联通、中国移动、中国电信
- */
-public static String getNetworkOperatorName(Context context) {
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- return tm != null ? tm.getNetworkOperatorName() : null;
-}
-```
-
-### 获取移动终端类型
-``` java
-/**
- * 获取移动终端类型
- *
- * @return 手机制式
- *
- * PHONE_TYPE_NONE : 0 手机制式未知
- * PHONE_TYPE_GSM : 1 手机制式为GSM,移动和联通
- * PHONE_TYPE_CDMA : 2 手机制式为CDMA,电信
- * PHONE_TYPE_SIP : 3
- *
- */
-public static int getPhoneType(Context context) {
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- return tm != null ? tm.getPhoneType() : -1;
-}
-```
-
-### 获取当前的网络类型(WIFI,2G,3G,4G)
-``` java
-/**
- * 获取当前的网络类型(WIFI,2G,3G,4G)
- * 需添加权限
- *
- * @return 网络类型
- *
- * NETWORK_WIFI = 1;
- * NETWORK_4G = 4;
- * NETWORK_3G = 3;
- * NETWORK_2G = 2;
- * NETWORK_UNKNOWN = 5;
- * NETWORK_NO = -1;
- *
- */
-public static int getNetWorkType(Context context) {
- int netType = NETWORK_NO;
- NetworkInfo info = getActiveNetworkInfo(context);
- if (info != null && info.isAvailable()) {
-
- if (info.getType() == ConnectivityManager.TYPE_WIFI) {
- netType = NETWORK_WIFI;
- } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- switch (info.getSubtype()) {
-
- case NETWORK_TYPE_GSM:
- case TelephonyManager.NETWORK_TYPE_GPRS:
- case TelephonyManager.NETWORK_TYPE_CDMA:
- case TelephonyManager.NETWORK_TYPE_EDGE:
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- case TelephonyManager.NETWORK_TYPE_IDEN:
- netType = NETWORK_2G;
- break;
-
- case NETWORK_TYPE_TD_SCDMA:
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_UMTS:
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- netType = NETWORK_3G;
- break;
-
- case NETWORK_TYPE_IWLAN:
- case TelephonyManager.NETWORK_TYPE_LTE:
- netType = NETWORK_4G;
- break;
- default:
-
- String subtypeName = info.getSubtypeName();
- if (subtypeName.equalsIgnoreCase("TD-SCDMA")
- || subtypeName.equalsIgnoreCase("WCDMA")
- || subtypeName.equalsIgnoreCase("CDMA2000")) {
- netType = NETWORK_3G;
- } else {
- netType = NETWORK_UNKNOWN;
- }
- break;
- }
- } else {
- netType = NETWORK_UNKNOWN;
- }
- }
- return netType;
-}
-
-/**
- * 获取当前的网络类型(WIFI,2G,3G,4G)
- * 依赖上面的方法
- *
- * @param context
- * @return 网络类型名称
- *
- * NETWORK_WIFI
- * NETWORK_4G
- * NETWORK_3G
- * NETWORK_2G
- * NETWORK_UNKNOWN
- * NETWORK_NO
- *
- */
-public static String getNetWorkTypeName(Context context) {
- switch (getNetWorkType(context)) {
- case NETWORK_WIFI:
- return "NETWORK_WIFI";
- case NETWORK_4G:
- return "NETWORK_4G";
- case NETWORK_3G:
- return "NETWORK_3G";
- case NETWORK_2G:
- return "NETWORK_2G";
- case NETWORK_NO:
- return "NETWORK_NO";
- default:
- return "NETWORK_UNKNOWN";
- }
-}
-```
diff --git a/about_phone.md b/about_phone.md
deleted file mode 100644
index ef36f14c25..0000000000
--- a/about_phone.md
+++ /dev/null
@@ -1,282 +0,0 @@
-# 手机相关
-### 判断设备是否是手机
-``` java
-/**
- * 判断设备是否是手机
- */
-public static boolean isPhone(Context context) {
- TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- return tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
-}
-```
-
-### 获取手机的IMIE
-``` java
-/**
- * 获取当前设备的IMIE
- * 需与上面的isPhone一起使用
- *
需添加权限
- */
-public static String getPhoneIMEI(Context context) {
- String deviceId;
- if (isPhone(context)) {
- TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- deviceId = tm.getDeviceId();
- } else {
- deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
- }
- return deviceId;
-}
-```
-
-### 获取手机状态信息
-``` java
-/**
- * 获取手机状态信息
- *
需添加权限
- *
返回如下
- *
- * DeviceId(IMEI) = 99000311726612
- * DeviceSoftwareVersion = 00
- * Line1Number =
- * NetworkCountryIso = cn
- * NetworkOperator = 46003
- * NetworkOperatorName = 中国电信
- * NetworkType = 6
- * honeType = 2
- * SimCountryIso = cn
- * SimOperator = 46003
- * SimOperatorName = 中国电信
- * SimSerialNumber = 89860315045710604022
- * SimState = 5
- * SubscriberId(IMSI) = 460030419724900
- * VoiceMailNumber = *86
- *
- */
-public static String getPhoneStatus(Context context) {
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- String str = "";
- str += "DeviceId(IMEI) = " + tm.getDeviceId() + "\n";
- str += "DeviceSoftwareVersion = " + tm.getDeviceSoftwareVersion() + "\n";
- str += "Line1Number = " + tm.getLine1Number() + "\n";
- str += "NetworkCountryIso = " + tm.getNetworkCountryIso() + "\n";
- str += "NetworkOperator = " + tm.getNetworkOperator() + "\n";
- str += "NetworkOperatorName = " + tm.getNetworkOperatorName() + "\n";
- str += "NetworkType = " + tm.getNetworkType() + "\n";
- str += "honeType = " + tm.getPhoneType() + "\n";
- str += "SimCountryIso = " + tm.getSimCountryIso() + "\n";
- str += "SimOperator = " + tm.getSimOperator() + "\n";
- str += "SimOperatorName = " + tm.getSimOperatorName() + "\n";
- str += "SimSerialNumber = " + tm.getSimSerialNumber() + "\n";
- str += "SimState = " + tm.getSimState() + "\n";
- str += "SubscriberId(IMSI) = " + tm.getSubscriberId() + "\n";
- str += "VoiceMailNumber = " + tm.getVoiceMailNumber() + "\n";
- return str;
-}
-```
-
-### 跳至填充好phoneNumber的拨号界面
-``` java
-/**
- * 跳至填充好phoneNumber的拨号界面
- */
-public static void dial(Context context, String phoneNumber) {
- context.startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)));
-}
-```
-
-### 拨打phoneNumber
-``` java
-/**
- * 拨打phoneNumber
- * 需添加权限
- */
-public static void call(Context context, String phoneNumber) {
- context.startActivity(new Intent("android.intent.action.CALL", Uri.parse("tel:" + phoneNumber)));
-}
-```
-
-### 发送短信
-``` java
-/**
-* 发送短信
-*/
-public static void sendSms(Context context, String phoneNumber, String content) {
- Uri uri = Uri.parse("smsto:" + (TextUtils.isEmpty(phoneNumber) ? "" : phoneNumber));
- Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
- intent.putExtra("sms_body", TextUtils.isEmpty(content) ? "" : content);
- context.startActivity(intent);
-}
-```
-
-### 获取手机联系人
-``` java
-/**
- * 获取手机联系人
- *
需添加权限
- *
需添加权限
- */
-public static List> getAllContactInfo(Context context) {
- SystemClock.sleep(3000);
- ArrayList> list = new ArrayList>();
- // 1.获取内容解析者
- ContentResolver resolver = context.getContentResolver();
- // 2.获取内容提供者的地址:com.android.contacts
- // raw_contacts表的地址 :raw_contacts
- // view_data表的地址 : data
- // 3.生成查询地址
- Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");
- Uri date_uri = Uri.parse("content://com.android.contacts/data");
- // 4.查询操作,先查询raw_contacts,查询contact_id
- // projection : 查询的字段
- Cursor cursor = resolver.query(raw_uri, new String[] { "contact_id" },
- null, null, null);
- // 5.解析cursor
- while (cursor.moveToNext()) {
- // 6.获取查询的数据
- String contact_id = cursor.getString(0);
- // cursor.getString(cursor.getColumnIndex("contact_id"));//getColumnIndex
- // : 查询字段在cursor中索引值,一般都是用在查询字段比较多的时候
- // 判断contact_id是否为空
- if (!TextUtils.isEmpty(contact_id)) {//null ""
- // 7.根据contact_id查询view_data表中的数据
- // selection : 查询条件
- // selectionArgs :查询条件的参数
- // sortOrder : 排序
- // 空指针: 1.null.方法 2.参数为null
- Cursor c = resolver.query(date_uri, new String[] { "data1",
- "mimetype" }, "raw_contact_id=?",
- new String[] { contact_id }, null);
- HashMap map = new HashMap();
- // 8.解析c
- while (c.moveToNext()) {
- // 9.获取数据
- String data1 = c.getString(0);
- String mimetype = c.getString(1);
- // 10.根据类型去判断获取的data1数据并保存
- if (mimetype.equals("vnd.android.cursor.item/phone_v2")) {
- // 电话
- map.put("phone", data1);
- } else if (mimetype.equals("vnd.android.cursor.item/name")) {
- // 姓名
- map.put("name", data1);
- }
- }
- // 11.添加到集合中数据
- list.add(map);
- // 12.关闭cursor
- c.close();
- }
- }
- // 12.关闭cursor
- cursor.close();
- return list;
-}
-```
-
-### 打开手机联系人界面点击联系人后便获取该号码
-``` java
-/**
- * 打开手机联系人界面点击联系人后便获取该号码
- * 参照以下注释代码
- */
-public static void getContantNum() {
- Log.i("tips", "U should copy the follow code.");
- /*
- Intent intent = new Intent();
- intent.setAction("android.intent.action.PICK");
- intent.setType("vnd.android.cursor.dir/phone_v2");
- startActivityForResult(intent, 0);
- @Override
- protected void onActivityResult ( int requestCode, int resultCode, Intent data){
- super.onActivityResult(requestCode, resultCode, data);
- if (data != null) {
- Uri uri = data.getData();
- String num = null;
- // 创建内容解析者
- ContentResolver contentResolver = getContentResolver();
- Cursor cursor = contentResolver.query(uri,
- null, null, null, null);
- while (cursor.moveToNext()) {
- num = cursor.getString(cursor.getColumnIndex("data1"));
- }
- cursor.close();
- num = num.replaceAll("-", "");//替换的操作,555-6 -> 5556
- }
- }
- */
-}
-```
-
-### 获取手机短信并保存到xml中
-``` java
-/**
- * 获取手机短信并保存到xml中
- *
需添加权限
- *
需添加权限
- */
-public static void getAllSMS(Context context) {
- //1.获取短信
- //1.1获取内容解析者
- ContentResolver resolver = context.getContentResolver();
- //1.2获取内容提供者地址 sms,sms表的地址:null 不写
- //1.3获取查询路径
- Uri uri = Uri.parse("content://sms");
- //1.4.查询操作
- //projection : 查询的字段
- //selection : 查询的条件
- //selectionArgs : 查询条件的参数
- //sortOrder : 排序
- Cursor cursor = resolver.query(uri, new String[]{"address", "date", "type", "body"}, null, null, null);
- //设置最大进度
- int count = cursor.getCount();//获取短信的个数
- //2.备份短信
- //2.1获取xml序列器
- XmlSerializer xmlSerializer = Xml.newSerializer();
- try {
- //2.2设置xml文件保存的路径
- //os : 保存的位置
- //encoding : 编码格式
- xmlSerializer.setOutput(new FileOutputStream(new File("/mnt/sdcard/backupsms.xml")), "utf-8");
- //2.3设置头信息
- //standalone : 是否独立保存
- xmlSerializer.startDocument("utf-8", true);
- //2.4设置根标签
- xmlSerializer.startTag(null, "smss");
- //1.5.解析cursor
- while (cursor.moveToNext()) {
- SystemClock.sleep(1000);
- //2.5设置短信的标签
- xmlSerializer.startTag(null, "sms");
- //2.6设置文本内容的标签
- xmlSerializer.startTag(null, "address");
- String address = cursor.getString(0);
- //2.7设置文本内容
- xmlSerializer.text(address);
- xmlSerializer.endTag(null, "address");
- xmlSerializer.startTag(null, "date");
- String date = cursor.getString(1);
- xmlSerializer.text(date);
- xmlSerializer.endTag(null, "date");
- xmlSerializer.startTag(null, "type");
- String type = cursor.getString(2);
- xmlSerializer.text(type);
- xmlSerializer.endTag(null, "type");
- xmlSerializer.startTag(null, "body");
- String body = cursor.getString(3);
- xmlSerializer.text(body);
- xmlSerializer.endTag(null, "body");
- xmlSerializer.endTag(null, "sms");
- System.out.println("address:" + address + " date:" + date + " type:" + type + " body:" + body);
- }
- xmlSerializer.endTag(null, "smss");
- xmlSerializer.endDocument();
- //2.8将数据刷新到文件中
- xmlSerializer.flush();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-}
-```
diff --git a/about_regular.md b/about_regular.md
deleted file mode 100644
index 9a5d0dbe3e..0000000000
--- a/about_regular.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# 正则相关
-### 正则工具类
-``` java
-import android.text.TextUtils;
-
-import java.util.regex.Pattern;
-
-/*********************************************
- * author: Blankj on 2016/8/2 21:19
- * blog: http://blankj.com
- * e-mail: blankj@qq.com
- *********************************************/
-public class RegularUtils {
-
- private RegularUtils() {
- throw new UnsupportedOperationException("u can't fuck me...");
- }
-
- /**
- * 验证手机号(简单)
- */
- private static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$";
- /**
- * 验证手机号(精确)
- *
- *
移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188
- *
联通:130、131、132、145、155、156、175、176、185、186
- *
电信:133、153、173、177、180、181、189
- *
全球星:1349
- *
虚拟运营商:170
- */
- private static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-8])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$";
- /**
- * 验证座机号,正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx/
- */
- private static final String REGEX_TEL = "^0\\d{2,3}[- ]?\\d{7,8}";
- /**
- * 验证邮箱
- */
- private static final String REGEX_EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
- /**
- * 验证url
- */
- private static final String REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?";
- /**
- * 验证汉字
- */
- private static final String REGEX_CHZ = "^[\\u4e00-\\u9fa5]+$";
- /**
- * 验证用户名,取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位
- */
- private static final String REGEX_USERNAME = "^[\\w\\u4e00-\\u9fa5]{6,20}(?= 19方可使用)
-``` java
-/**
- * 设置透明状态栏(api >= 19方可使用)
- *
可在Activity的onCreat()中调用
- *
需在顶部控件布局中加入以下属性让内容出现在状态栏之下
- *
android:clipToPadding="true"
- *
android:fitsSystemWindows="true"
- */
-public static void setTransparentStatusBar(Activity activity) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- //透明状态栏
- activity.getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
- //透明导航栏
- activity.getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
- }
-}
-```
-
-### 隐藏状态栏
-``` java
-/**
- * 隐藏状态栏
- *
也就是设置全屏,一定要在setContentView之前调用,否则报错
- *
此方法Activity可以继承AppCompatActivity
- *
启动的时候状态栏会显示一下再隐藏,比如QQ的欢迎界面
- *
在配置文件中Activity加属性android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- *
如加了以上配置Activity不能继承AppCompatActivity,会报错
- */
-public static void hideStatusBar(Activity activity) {
- activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
- activity.getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN,
- LayoutParams.FLAG_FULLSCREEN);
-}
-```
-
-### 获取状态栏高度
-``` java
-/**
- * 获取状态栏高度
- */
-public static int getStatusBarHeight(Context context) {
- int result = 0;
- int resourceId = context.getResources()
- .getIdentifier("status_bar_height", "dimen", "android");
- if (resourceId > 0) {
- result = context.getResources().getDimensionPixelSize(resourceId);
- }
- return result;
-}
-```
-
-### 判断状态栏是否存在
-``` java
-/**
-* 判断状态栏是否存在
-*
-* @param activity
-* @return
-* true: 存在
-* false: 不存在
-*
-*/
-public static boolean isStatusBarExists(Activity activity) {
- WindowManager.LayoutParams params = activity.getWindow().getAttributes();
- return (params.flags & LayoutParams.FLAG_FULLSCREEN) != LayoutParams.FLAG_FULLSCREEN;
-}
-```
-
-### 获取ActionBar高度
-``` java
-/**
- * 获取ActionBar高度
- */
-public static int getActionBarHeight(Activity activity) {
- TypedValue tv = new TypedValue();
- if (activity.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
- return TypedValue.complexToDimensionPixelSize(tv.data, activity.getResources().getDisplayMetrics());
- }
- return 0;
-}
-```
-
-### 设置屏幕为横屏
-```
-/**
- * 设置屏幕为横屏
- * 还有一种就是在Activity中加属性android:screenOrientation="landscape"
- *
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
- *
设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
- *
设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"(4.0以上必须带最后一个参数)时
- * 切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
- */
-public static void setLandscape(Activity activity) {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
-}
-```
-
-### 获取当前屏幕截图
-``` java
-/**
- * 获取当前屏幕截图,包含状态栏
- */
-public static Bitmap captureWithStatusBar(Activity activity) {
- View view = activity.getWindow().getDecorView();
- view.setDrawingCacheEnabled(true);
- view.buildDrawingCache();
- Bitmap bmp = view.getDrawingCache();
- int width = getScreenWidth(activity);
- int height = getScreenHeight(activity);
- Bitmap bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
- view.destroyDrawingCache();
- return bp;
-}
-
-/**
- * 获取当前屏幕截图,不包含状态栏
- *
需要用到上面获取状态栏高度的方法
- */
-public static Bitmap captureWithoutStatusBar(Activity activity) {
- View view = activity.getWindow().getDecorView();
- view.setDrawingCacheEnabled(true);
- view.buildDrawingCache();
- Bitmap bmp = view.getDrawingCache();
- int statusBarHeight = getStatusBarHeight(activity);
- int width = getScreenWidth(activity);
- int height = getScreenHeight(activity);
- Bitmap bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
- view.destroyDrawingCache();
- return bp;
-}
-```
-
-### 判断是否锁屏
-``` java
-/**
- * 判断是否锁屏
- */
-public static boolean isScreenLock(Context context) {
- KeyguardManager km = (KeyguardManager) context
- .getSystemService(Context.KEYGUARD_SERVICE);
- return km.inKeyguardRestrictedInputMode();
-}
-```
-
-***
-# 尺寸相关
-### dp与px转换
-``` java
-/**
-* dp转px
-*/
-public static int dp2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
-}
-
-/**
-* px转dp
-*/
-public static int px2dp(Context context, float pxValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (pxValue / scale + 0.5f);
-}
-```
-
\ No newline at end of file
diff --git a/about_size.md b/about_size.md
deleted file mode 100644
index 17d3fc0400..0000000000
--- a/about_size.md
+++ /dev/null
@@ -1,131 +0,0 @@
-# 尺寸相关
-### dp与px转换
-``` java
-/**
-* dp转px
-*/
-public static int dp2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
-}
-
-/**
-* px转dp
-*/
-public static int px2dp(Context context, float pxValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (pxValue / scale + 0.5f);
-}
-```
-
-### sp与px转换
-``` java
-/**
-* sp转px
-*/
-public static int sp2px(Context context, float spValue) {
- final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
- return (int) (spValue * fontScale + 0.5f);
-}
-
-/**
-* px转sp
-*/
-public static int px2sp(Context context, float pxValue) {
- final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
- return (int) (pxValue / fontScale + 0.5f);
-}
-```
-
-### 各种单位转换
-``` java
-/**
- * 各种单位转换
- *
该方法存在于TypedValue
- */
-public static float applyDimension(int unit, float value, DisplayMetrics metrics) {
- switch (unit) {
- case TypedValue.COMPLEX_UNIT_PX:
- return value;
- case TypedValue.COMPLEX_UNIT_DIP:
- return value * metrics.density;
- case TypedValue.COMPLEX_UNIT_SP:
- return value * metrics.scaledDensity;
- case TypedValue.COMPLEX_UNIT_PT:
- return value * metrics.xdpi * (1.0f / 72);
- case TypedValue.COMPLEX_UNIT_IN:
- return value * metrics.xdpi;
- case TypedValue.COMPLEX_UNIT_MM:
- return value * metrics.xdpi * (1.0f / 25.4f);
- }
- return 0;
-}
-```
-
-### 在onCreate()即可强行获取View的尺寸
-``` java
-/**
-* 在onCreate()即可强行获取View的尺寸
-*
需回调onGetSizeListener接口,在onGetSize中获取view宽高
-* 用法示例如下所示
-* SizeUtils.forceGetViewSize(view);
-* SizeUtils.setListener(new SizeUtils.onGetSizeListener() {
- * @Override
- * public void onGetSize(View view) {
- * Log.d("tag", view.getWidth() + " " + view.getHeight());
- * }
-* });
-*/
-public static void forceGetViewSize(final View view) {
- view.post(new Runnable() {
- @Override
- public void run() {
- if (mListener != null) {
- mListener.onGetSize(view);
- }
- }
- });
-}
-
-/**
-* 获取到View尺寸的监听
-*/
-public interface onGetSizeListener {
- void onGetSize(View view);
-}
-
-public static void setListener(onGetSizeListener listener) {
- mListener = listener;
-}
-
-private static onGetSizeListener mListener;
-```
-
-### ListView中提前测量View尺寸
-``` java
-/**
- * ListView中提前测量View尺寸,如headerView
- *
用的时候去掉注释拷贝到ListView中即可
- *
参照以下注释代码
- */
-public static void measureViewInLV(View view) {
- Log.i("tips", "U should copy the follow code.");
- /*
- ViewGroup.LayoutParams p = view.getLayoutParams();
- if (p == null) {
- p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- }
- int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
- int height;
- int tempHeight = p.height;
- if (tempHeight > 0) {
- height = MeasureSpec.makeMeasureSpec(tempHeight,
- MeasureSpec.EXACTLY);
- } else {
- height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- }
- view.measure(width, height);
- */
-}
-```
diff --git a/about_time.md b/about_time.md
deleted file mode 100644
index e1d7c95253..0000000000
--- a/about_time.md
+++ /dev/null
@@ -1,265 +0,0 @@
-# 时间相关
-### 将时间戳转为时间字符串
-``` java
-/**
- * 将时间戳转为时间字符串
- *
格式为yyyy-MM-dd HH:mm:ss
- */
-public static String milliseconds2String(long milliseconds) {
- return milliseconds2String(milliseconds, DEFAULT_SDF);
-}
-
-/**
- * 将时间戳转为时间字符串
- *
格式为用户自定义
- */
-public static String milliseconds2String(long milliseconds, SimpleDateFormat format) {
- return format.format(new Date(milliseconds));
-}
-```
-
-### 将时间字符串转为时间戳
-``` java
-/**
- * 将时间字符串转为时间戳
- *
格式为yyyy-MM-dd HH:mm:ss
- */
-public static long string2Milliseconds(String time) {
- return string2Milliseconds(time, DEFAULT_SDF);
-}
-
-/**
- * 将时间字符串转为时间戳
- *
格式为用户自定义
- */
-public static long string2Milliseconds(String time, SimpleDateFormat format) {
- try {
- return format.parse(time).getTime();
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return -1;
-}
-```
-
-### 将时间字符串转为Date类型
-``` java
-/**
- * 将时间字符串转为Date类型
- *
格式为yyyy-MM-dd HH:mm:ss
- */
-public static Date string2Date(String formatDate) {
- return string2Date(formatDate, DEFAULT_SDF);
-}
-
-/**
- * 将时间字符串转为Date类型
- *
格式为用户自定义
- */
-public static Date string2Date(String formatDate, SimpleDateFormat format) {
- return new Date(string2Milliseconds(formatDate, format));
-}
-```
-
-### 将Date类型转为时间字符串
-``` java
-/**
- * 将Date类型转为时间字符串
- *
格式为yyyy-MM-dd HH:mm:ss
- */
-public static String date2String(Date date) {
- return date2String(date, DEFAULT_SDF);
-}
-
-/**
- * 将Date类型转为时间字符串
- *
格式为用户自定义
- */
-public static String date2String(Date date, SimpleDateFormat format) {
- return format.format(date);
-}
-```
-
-### 将Date类型转为时间戳
-``` java
-/**
- * 将Date类型转为时间戳
- */
-public static long date2Milliseconds(Date date) {
- return date.getTime();
-}
-```
-
-### 将时间戳转为Date类型
-``` java
-/**
- * 将时间戳转为Date类型
- */
-public static Date milliseconds2Date(long milliseconds) {
- return new Date(milliseconds);
-}
-```
-
-### 毫秒时间戳单位转换(单位:unit)
-``` java
-/**
- * 毫秒时间戳单位转换(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- *
- */
-private static long milliseconds2Unit(long milliseconds, int unit) {
- switch (unit) {
- case UNIT_MSEC:
- case UNIT_SEC:
- case UNIT_MIN:
- case UNIT_HOUR:
- case UNIT_DAY:
- return Math.abs(milliseconds) / unit;
- }
- return -1;
-}
-```
-
-### 获取两个时间差(单位:unit)
-``` java
-/**
- * 获取两个时间差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- *
- * time1和time2格式都为yyyy-MM-dd HH:mm:ss
- */
-public static long getIntervalTime(String time1, String time2, int unit) {
- return getIntervalTime(time1, time2, unit, DEFAULT_SDF);
-}
-
-/**
- * 获取两个时间差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- *
- * time1和time2格式都为format
- */
-public static long getIntervalTime(String time1, String time2, int unit, SimpleDateFormat for
- return milliseconds2Unit(string2Milliseconds(time1, format)
- - string2Milliseconds(time2, format), unit);
-}
-
-/**
- * 获取两个时间差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- *
- * time1和time2都为Date
- */
-public static long getIntervalTime(Date time1, Date time2, int unit) {
- return milliseconds2Unit(date2Milliseconds(time2) - date2Milliseconds(time1), unit);
-}
-```
-
-### 获取当前时间
-``` java
-/**
- * 获取当前时间
- *
单位(毫秒)
- */
-public static long getCurTimeMills() {
- return System.currentTimeMillis();
-}
-
-/**
- * 获取当前时间
- *
格式为yyyy-MM-dd HH:mm:ss
- */
-public static String getCurTimeString() {
- return milliseconds2String(getCurTimeMills());
-}
-
-/**
- * 获取当前时间
- *
格式为用户自定义
- */
-public static String getCurTimeString(SimpleDateFormat format) {
- return milliseconds2String(getCurTimeMills(), format);
-}
-
-/**
- * 获取当前时间
- *
Date类型
- */
-public static Date getCurTimeDate() {
- return new Date();
-}
-```
-
-### 获取与当前时间的差(单位:unit)
-``` java
-/**
- * 获取与当前时间的差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- * time1和time2格式都为yyyy-MM-dd HH:mm:ss
- */
-public static long getIntervalByNow(String time, int unit) {
- return getIntervalByNow(time, unit, DEFAULT_SDF);
-}
-
-/**
- * 获取与当前时间的差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- * time1和time2格式都为format
- */
-public static long getIntervalByNow(String time, int unit, SimpleDateFormat format) {
- return getIntervalTime(getCurTimeString(), time, unit, format);
-}
-
-/**
- * 获取与当前时间的差(单位:unit)
- *
- * UNIT_MSEC:毫秒
- * UNIT_SEC :秒
- * UNIT_MIN :分
- * UNIT_HOUR:小时
- * UNIT_DAY :天
- * time1和time2格式都为format
- */
-public static long getIntervalByNow(Date time, int unit) {
- return getIntervalTime(getCurTimeDate(), time, unit);
-}
-```
-
-### 判断闰年
-``` java
-/**
- * 判断闰年
- */
-public static boolean isLeapYear(int year) {
- return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
-}
-```
diff --git a/about_unclassified.md b/about_unclassified.md
deleted file mode 100644
index 7aeb237703..0000000000
--- a/about_unclassified.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# 未归类
-### 获取服务是否开启
-```
-/**
- * 获取服务是否开启
- * @param className 完整包名的服务类名
- */
-public static boolean isRunningService(String className, Context context) {
- // 进程的管理者,活动的管理者
- ActivityManager activityManager = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- // 获取正在运行的服务,最多获取1000个
- List runningServices = activityManager.getRunningServices(1000);
- // 遍历集合
- for (RunningServiceInfo runningServiceInfo : runningServices) {
- ComponentName service = runningServiceInfo.service;
- if (className.equals(service.getClassName())) {
- return true;
- }
- }
- return false;
-}
-```
diff --git a/art/auc_frame.png b/art/auc_frame.png
new file mode 100644
index 0000000000..68c92d37b1
Binary files /dev/null and b/art/auc_frame.png differ
diff --git a/art/auc_frame_cn.png b/art/auc_frame_cn.png
new file mode 100644
index 0000000000..2382c03197
Binary files /dev/null and b/art/auc_frame_cn.png differ
diff --git a/art/busutil_vs_eventbus.png b/art/busutil_vs_eventbus.png
new file mode 100644
index 0000000000..1a2272b808
Binary files /dev/null and b/art/busutil_vs_eventbus.png differ
diff --git a/art/communication.png b/art/communication.png
new file mode 100644
index 0000000000..f3d68d0b10
Binary files /dev/null and b/art/communication.png differ
diff --git a/art/donate.png b/art/donate.png
new file mode 100644
index 0000000000..0ba2a4cca6
Binary files /dev/null and b/art/donate.png differ
diff --git a/art/logo.png b/art/logo.png
new file mode 100644
index 0000000000..bf4208c15b
Binary files /dev/null and b/art/logo.png differ
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..e0f0f36c87
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,41 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ConfigUtils.init(gradle)
+ repositories {
+ mavenLocal()
+ google()
+ mavenCentral()
+ jcenter()
+ }
+
+ dependencies {
+ for (def entrySet : ConfigUtils.getApplyPlugins().entrySet()) {
+ classpath entrySet.value.path
+ }
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ maven { url "https://jitpack.io/" }
+ google()
+ mavenCentral()
+ jcenter()
+ }
+
+ configurations.all {
+ resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
+
+ resolutionStrategy.eachDependency {
+ if (it.requested.group == 'com.android.support' && !it.requested.name.contains(
+ 'multidex')) {
+ it.useVersion Config.supportVersion
+ }
+ }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/buildApp.gradle b/buildApp.gradle
new file mode 100644
index 0000000000..93f0b9b1d4
--- /dev/null
+++ b/buildApp.gradle
@@ -0,0 +1,131 @@
+apply plugin: "com.android.application"
+
+apply {
+ from "${rootDir.path}/buildCommon.gradle"
+ from "${rootDir.path}/config/flavor.gradle"
+ if (Config.plugins.plugin_api.isApply) {
+ plugin Config.plugins.plugin_api.id
+ }
+ if (Config.plugins.plugin_bus.isApply) {
+ plugin Config.plugins.plugin_bus.id
+ }
+}
+
+configSigning()
+configApkName()
+
+//if (PluginConfig.plugin_bus.isApply) {
+// bus {
+// onlyScanLibRegex = '^([:]|(com\\.blankj)).+$'
+// }
+//}
+//
+//if (PluginConfig.plugin_api.isApply) {
+// api {
+// onlyScanLibRegex = '^([:]|(com\\.blankj)).+$'
+// }
+//}
+
+android {
+ defaultConfig {
+ applicationId Config.applicationId + suffix
+ targetSdkVersion Config.targetSdkVersion
+ multiDexEnabled true
+ }
+
+ buildTypes {
+ debug {}
+
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ packagingOptions {
+ exclude 'META-INF/*'
+ }
+
+ dexOptions {
+ preDexLibraries true
+ javaMaxHeapSize "8g"
+ maxProcessCount 8
+ dexInProcess = true
+ }
+
+ productFlavors {
+ dev {
+ applicationIdSuffix ".dev"
+ versionNameSuffix "-dev"
+ resValue "string", "app_name", Config.appName + suffix + "-dev"
+ }
+
+ production {
+ resValue "string", "app_name", Config.appName + suffix
+ }
+ }
+}
+
+dependencies {
+ // LeakCanary
+ debugImplementation Config.libs.leakcanary.path
+
+ debugImplementation Config.modules.lib_utildebug.dep
+ releaseImplementation Config.modules.lib_utildebug_no_op.dep
+
+ // 根据 Config.pkgConfig 来依赖所有 pkg
+ for (def entrySet : ConfigUtils.getApplyPkgs().entrySet()) {
+ api entrySet.value.dep
+ }
+
+ if (Config.modules.feature_mock.isApply) {
+ api ModuleConfig.modules.feature_mock.dep
+ }
+}
+
+def getSuffix() {
+ if (project.name == "feature_launcher_app") return ""
+ return "." + project.
+ name.
+ substring("feature_".length(), project.name.length() - "_app".length())
+}
+
+def configSigning() {
+
+ File signPropertiesFile = file("${rootDir.path}/sign/keystore.properties")
+ if (!signPropertiesFile.exists()) return
+
+ GLog.d("${project.toString()} sign start...")
+ project.android {
+ Properties properties = new Properties()
+ properties.load(new FileInputStream(signPropertiesFile))
+ signingConfigs {
+ release {
+ storeFile new File(signPropertiesFile.getParent(), properties['keystore'])
+ storePassword properties['storePassword']
+ keyAlias properties['keyAlias']
+ keyPassword properties['keyPassword']
+ }
+ }
+ buildTypes.release.signingConfig signingConfigs.release
+ }
+ GLog.d("${project.toString()} sign end...")
+}
+
+def configApkName() {
+ project.android.applicationVariants.all { variant ->
+ if (variant.buildType.name != "debug") {
+ def artifact = variant.getPackageApplicationProvider().get()
+ artifact.outputDirectory = new File("${rootDir.path}/apk")
+ variant.outputs.each {
+ it.outputFileName = "util" + suffix +
+ (variant.flavorName == "" ? "" : ("_" + variant.flavorName)) +
+ "_" +
+ variant.versionName.replace(".", "_") +
+ "_" +
+ variant.buildType.name +
+ ".apk"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/buildCommon.gradle b/buildCommon.gradle
new file mode 100644
index 0000000000..2cba3ffea2
--- /dev/null
+++ b/buildCommon.gradle
@@ -0,0 +1,30 @@
+apply {
+ plugin "kotlin-android"
+ plugin "kotlin-android-extensions"
+}
+
+android {
+ compileSdkVersion Config.compileSdkVersion
+ defaultConfig {
+ minSdkVersion Config.minSdkVersion
+ versionCode Config.versionCode
+ versionName Config.versionName
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+}
\ No newline at end of file
diff --git a/buildLib.gradle b/buildLib.gradle
new file mode 100644
index 0000000000..aed207cbee
--- /dev/null
+++ b/buildLib.gradle
@@ -0,0 +1,13 @@
+apply plugin: "com.android.library"
+apply from: "${rootDir.path}/buildCommon.gradle"
+
+dependencies {
+ if (project.name.endsWith("_pkg") || project.name.endsWith("_mock")) {
+ // if module's name equals 'pkg', api all of export
+ for (def entrySet : ConfigUtils.getApplyExports().entrySet()) {
+ api entrySet.value.dep
+ }
+ } else if (project.name.endsWith("_export")) {
+ api Config.modules.lib_common.dep
+ }
+}
\ No newline at end of file
diff --git a/utilcode/.gitignore b/buildSrc/.gitignore
similarity index 100%
rename from utilcode/.gitignore
rename to buildSrc/.gitignore
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 0000000000..349aed4fec
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,37 @@
+repositories {
+ google()
+ jcenter()
+}
+
+apply {
+ plugin 'groovy'
+ plugin 'java-gradle-plugin'
+}
+
+gradlePlugin {
+ plugins {
+ readmeCore {
+ id = 'readme-core'
+ implementationClass = 'com.blankj.plugin.readme.ReadmeCorePlugin'
+ }
+
+ readmeSub {
+ id = 'readme-sub'
+ implementationClass = 'com.blankj.plugin.readme.ReadmeSubPlugin'
+ }
+ }
+}
+
+dependencies {
+ implementation gradleApi()
+ implementation localGroovy()
+ implementation "commons-io:commons-io:2.6"
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDirs += 'src/main/java'
+ }
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle
new file mode 100644
index 0000000000..8a313c3b99
--- /dev/null
+++ b/buildSrc/settings.gradle
@@ -0,0 +1,8 @@
+//dependencyResolutionManagement {
+// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+// repositories {
+// google()
+// mavenCentral()
+// jcenter() // Warning: this repository is going to shut down soon
+// }
+//}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
new file mode 100644
index 0000000000..9a8d69d659
--- /dev/null
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -0,0 +1,89 @@
+class Config {
+
+ static applicationId = 'com.blankj.androidutilcode'
+ static appName = 'Util'
+
+ static compileSdkVersion = 29
+ static minSdkVersion = 14
+ static targetSdkVersion = 29
+ static versionCode = 1_031_001
+ static versionName = '1.31.1'// E.g. 1.9.72 => 1,009,072
+
+ // lib version
+ static gradlePluginVersion = '4.1.0'
+ static kotlinVersion = '1.3.72'
+ static androidxVersion = '1.0.0'
+
+ static modules = [
+ /*Don't delete this line*/
+ /*Generated by "module_config.json"*/
+ plugin_api_gradle_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/api-gradle-plugin"),
+ plugin_bus_gradle_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/bus-gradle-plugin"),
+ plugin_lib_base_transform : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/lib/base-transform", remotePath: "com.blankj:base-transform:1.0"),
+ plugin_buildSrc_plugin : new ModuleConfig(isApply: true , useLocal: true , localPath: "./plugin/buildSrc-plugin"),
+ feature_mock : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/mock"),
+ feature_launcher_app : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/launcher/app"),
+ feature_main_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/main/app"),
+ feature_main_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/main/pkg"),
+ feature_subutil_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/subutil/app"),
+ feature_subutil_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/subutil/pkg"),
+ feature_subutil_export : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/subutil/export"),
+ feature_utilcode_app : new ModuleConfig(isApply: false, useLocal: true , localPath: "./feature/utilcode/app"),
+ feature_utilcode_pkg : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/utilcode/pkg"),
+ feature_utilcode_export : new ModuleConfig(isApply: true , useLocal: true , localPath: "./feature/utilcode/export", remotePath: "com.blankj:utilcode-export:1.1"),
+ lib_base : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/base"),
+ lib_common : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/common"),
+ lib_subutil : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/subutil"),
+ lib_utilcode : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"),
+ lib_utildebug : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug"),
+ lib_utildebug_no_op : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug-no-op"),
+ /*Don't delete this line*/
+ ]
+
+ static plugins = [
+ plugin_gradle : new PluginConfig(path: "com.android.tools.build:gradle:$gradlePluginVersion"),
+ plugin_kotlin : new PluginConfig(path: "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"),
+ // 上传到 maven
+ plugin_maven : new PluginConfig(path: "com.github.dcendents:android-maven-gradle-plugin:2.1", id: "com.github.dcendents.android-maven"),
+
+ // 上传新版本插件更新 path 中的版本号,并设置 isApply = false
+ // 通过 mavenLocal 上传本地版本,设置 isApply = true 即可应用插件来调试,最后通过 bintrayUpload 来发布插件
+ plugin_api : new PluginConfig(isApply: true, useLocal: false, path: "com.blankj:api-gradle-plugin:1.5", id: "com.blankj.api"),
+ //./gradlew clean :plugin_api-gradle-plugin:mavenLocal // 上传到本地 mavenLocal
+ //./gradlew clean :plugin_api-gradle-plugin:bintrayUpload // 上传到 jcenter
+ plugin_bus : new PluginConfig(isApply: true, useLocal: false, path: "com.blankj:bus-gradle-plugin:2.6", id: "com.blankj.bus"),
+ //./gradlew clean :plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal
+ //./gradlew clean :plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter
+ plugin_buildSrc: new PluginConfig(isApply: false, useLocal: false, path: "com.blankj:buildSrc-plugin:1.0", id: "com.blankj.buildSrc"),
+ //./gradlew clean :plugin_bus-gradle-plugin:mavenLocal // 上传到本地 mavenLocal
+ //./gradlew clean :plugin_bus-gradle-plugin:bintrayUpload // 上传到 jcenter
+ ]
+
+ static libs = [
+ androidx_appcompat : new LibConfig(path: "androidx.appcompat:appcompat:$androidxVersion"),
+ androidx_material : new LibConfig(path: "com.google.android.material:material:$androidxVersion"),
+ androidx_multidex : new LibConfig(path: "androidx.multidex:multidex:2.0.0"),
+ androidx_constraint: new LibConfig(path: "androidx.constraintlayout:constraintlayout:1.1.3"),
+
+ kotlin : new LibConfig(path: "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"),
+
+ leakcanary : new LibConfig(path: "com.squareup.leakcanary:leakcanary-android:2.1"),
+
+ free_proguard : new LibConfig(path: "com.blankj:free-proguard:1.0.2"),
+ swipe_panel : new LibConfig(path: "com.blankj:swipe-panel:1.2"),
+
+ gson : new LibConfig(path: "com.google.code.gson:gson:2.8.5"),
+ glide : new LibConfig(path: "com.github.bumptech.glide:glide:4.7.1"),
+ retrofit : new LibConfig(path: "com.squareup.retrofit2:retrofit:2.4.0"),
+ commons_io : new LibConfig(path: "commons-io:commons-io:2.6"),
+
+ eventbus_lib : new LibConfig(path: "org.greenrobot:eventbus:3.1.1"),
+ eventbus_processor : new LibConfig(path: "org.greenrobot:eventbus-annotation-processor:3.0.1"),
+
+ photo_view : new LibConfig(path: "com.github.chrisbanes:PhotoView:2.0.0"),
+
+ test_junit : new LibConfig(path: "junit:junit:4.12"),
+ test_robolectric : new LibConfig(path: "org.robolectric:robolectric:4.3.1"),
+ ]
+}
+//./gradlew clean :lib_utilcode:bintrayUpload
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/ConfigUtils.groovy b/buildSrc/src/main/groovy/ConfigUtils.groovy
new file mode 100644
index 0000000000..6a09d2f2d9
--- /dev/null
+++ b/buildSrc/src/main/groovy/ConfigUtils.groovy
@@ -0,0 +1,99 @@
+import org.gradle.api.Project
+import org.gradle.api.ProjectEvaluationListener
+import org.gradle.api.ProjectState
+import org.gradle.api.invocation.Gradle
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/07/13
+ * desc :
+ *
+ */
+class ConfigUtils {
+
+ static init(Gradle gradle) {
+ generateDep(gradle)
+ addCommonGradle(gradle)
+ TaskDurationUtils.init(gradle)
+ }
+
+ /**
+ * 根据 depConfig 生成 dep
+ */
+ private static void generateDep(Gradle gradle) {
+ def configs = [:]
+ for (Map.Entry entry : Config.modules.entrySet()) {
+ def (name, config) = [entry.key, entry.value]
+ if (config.useLocal) {
+ config.dep = gradle.rootProject.findProject(name)
+ } else {
+ config.dep = config.remotePath
+ }
+ configs.put(name, config)
+ }
+ GLog.l("generateDep = ${GLog.object2String(configs)}")
+ }
+
+ private static addCommonGradle(Gradle gradle) {
+ gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
+ @Override
+ void beforeEvaluate(Project project) {
+ // 在 project 的 build.gradle 前 do sth.
+ if (project.name.contains("plugin")) {
+ return
+ }
+ if (project.name.endsWith("_app")) {
+ GLog.l(project.toString() + " applies buildApp.gradle")
+ project.apply {
+ from "${project.rootDir.path}/buildApp.gradle"
+ }
+ } else {
+ GLog.l(project.toString() + " applies buildLib.gradle")
+ project.apply {
+ from "${project.rootDir.path}/buildLib.gradle"
+ }
+ }
+ }
+
+ @Override
+ void afterEvaluate(Project project, ProjectState state) {
+ // 在 project 的 build.gradle 末 do sth.
+ }
+ })
+ }
+
+ static getApplyPlugins() {
+ def plugins = [:]
+ for (Map.Entry entry : Config.plugins.entrySet()) {
+ if (entry.value.isApply) {
+ plugins.put(entry.key, entry.value)
+ }
+ }
+ GLog.d("getApplyPlugins = ${GLog.object2String(plugins)}")
+ return plugins
+ }
+
+ static getApplyPkgs() {
+ def pkgs = [:]
+ for (Map.Entry entry : Config.modules.entrySet()) {
+ if (entry.value.isApply && entry.key.endsWith("_pkg")) {
+ pkgs.put(entry.key, entry.value)
+ }
+ }
+ GLog.d("getApplyPkgs = ${GLog.object2String(pkgs)}")
+ return pkgs
+ }
+
+ static getApplyExports() {
+ def exports = [:]
+ for (Map.Entry entry : Config.modules.entrySet()) {
+ if (entry.value.isApply && entry.key.endsWith("_export")) {
+ exports.put(entry.key, entry.value)
+ }
+ }
+ GLog.d("getApplyExports = ${GLog.object2String(exports)}")
+ return exports
+ }
+}
diff --git a/buildSrc/src/main/groovy/GLog.groovy b/buildSrc/src/main/groovy/GLog.groovy
new file mode 100644
index 0000000000..6a5554fc46
--- /dev/null
+++ b/buildSrc/src/main/groovy/GLog.groovy
@@ -0,0 +1,208 @@
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/07/13
+ * desc :
+ *
+ */
+class GLog {
+
+ def static debugSwitch = true
+
+ static d(Object... contents) {
+ if (!debugSwitch) return contents
+ return l(contents)
+ }
+
+ static l(Object... contents) {
+ StringBuilder sb = new StringBuilder()
+ sb.append(LogConst.BORDER_TOP)
+ sb.append(borderMsg(processContents(contents)))
+ sb.append(LogConst.BORDER_BTM)
+ print sb.toString()
+ return contents
+ }
+
+ private static borderMsg(String msg) {
+ StringBuilder sb = new StringBuilder()
+ object2String(msg).split(LogConst.LINE_SEP).each { line ->
+ sb.append(LogConst.BORDER_LFT).append(line).append(LogConst.LINE_SEP)
+ }
+ return sb
+ }
+
+ private static processContents(final Object... contents) {
+ String body = LogConst.NULL
+ if (contents != null) {
+ if (contents.length == 1) {
+ body = object2String(contents[0])
+ } else {
+ StringBuilder sb = new StringBuilder()
+ int i = 0
+ for (int len = contents.length; i < len; ++i) {
+ Object content = contents[i]
+ sb.append("args[$i] = ")
+ .append(object2String(content))
+ .append(LogConst.LINE_SEP)
+ }
+ body = sb.toString()
+ }
+ }
+ return body.length() == 0 ? LogConst.NOTHING : body
+ }
+
+ static String object2String(Object object) {
+ if (object == null) return "null";
+ if (object.getClass().isArray()) return LogFormatter.array2String(object);
+ if (object instanceof List) return LogFormatter.list2String(object);
+ if (object instanceof Map) return LogFormatter.map2String(object);
+ if (object instanceof Throwable) return LogFormatter.throwable2String(object);
+ return object.toString();
+ }
+
+ static class LogFormatter {
+
+ private static array2String(Object object) {
+ if (object instanceof Object[]) {
+ return Arrays.deepToString((Object[]) object);
+ } else if (object instanceof boolean[]) {
+ return Arrays.toString((boolean[]) object);
+ } else if (object instanceof byte[]) {
+ return Arrays.toString((byte[]) object);
+ } else if (object instanceof char[]) {
+ return Arrays.toString((char[]) object);
+ } else if (object instanceof double[]) {
+ return Arrays.toString((double[]) object);
+ } else if (object instanceof float[]) {
+ return Arrays.toString((float[]) object);
+ } else if (object instanceof int[]) {
+ return Arrays.toString((int[]) object);
+ } else if (object instanceof long[]) {
+ return Arrays.toString((long[]) object);
+ } else if (object instanceof short[]) {
+ return Arrays.toString((short[]) object);
+ }
+ throw new IllegalArgumentException("Array has incompatible type: " + object.getClass());
+ }
+
+ private static list2String(List list) {
+ StringBuilder sb = new StringBuilder()
+ sb.append("[")
+ list.each { v ->
+ if (v instanceof Map || v instanceof List) {
+ sb.append(String.format("$LogConst.LINE_SEP%${deep++ * 8}s${object2String(v)},", ""))
+ deep--
+ } else {
+ sb.append(String.format("$LogConst.LINE_SEP%${deep * 8}s$v,", ""))
+ }
+ }
+ sb.deleteCharAt(sb.length() - 1)
+ if (deep - 1 == 0) {
+ sb.append("$LogConst.LINE_SEP]")
+ } else {
+ sb.append(String.format("$LogConst.LINE_SEP%${(deep - 1) * 8}s]", ""))
+ }
+ return sb.toString()
+ }
+
+ private static deep = 1;
+
+ private static map2String(Map map) {
+ StringBuilder sb = new StringBuilder()
+ sb.append("[")
+ map.each { k, v ->
+ if (v instanceof Map || v instanceof List) {
+ sb.append(String.format("$LogConst.LINE_SEP%${deep++ * 8}s%-26s: ${object2String(v)},", "", k))
+ deep--
+ } else {
+ sb.append(String.format("$LogConst.LINE_SEP%${deep * 8}s%-26s: $v,", "", k))
+ }
+ }
+ sb.deleteCharAt(sb.length() - 1)
+ if (deep - 1 == 0) {
+ sb.append("$LogConst.LINE_SEP]")
+ } else {
+ sb.append(String.format("$LogConst.LINE_SEP%${(deep - 1) * 8}s]", ""))
+ }
+ return sb.toString()
+ }
+
+ private static throwable2String(Throwable throwable) {
+ final List throwableList = new ArrayList<>();
+ while (throwable != null && !throwableList.contains(throwable)) {
+ throwableList.add(throwable);
+ throwable = throwable.getCause();
+ }
+ final int size = throwableList.size();
+ final List frames = new ArrayList<>();
+ List nextTrace = getStackFrameList(throwableList.get(size - 1));
+ for (int i = size; --i >= 0;) {
+ final List trace = nextTrace;
+ if (i != 0) {
+ nextTrace = getStackFrameList(throwableList.get(i - 1));
+ removeCommonFrames(trace, nextTrace);
+ }
+ if (i == size - 1) {
+ frames.add(throwableList.get(i).toString());
+ } else {
+ frames.add(" Caused by: " + throwableList.get(i).toString());
+ }
+ frames.addAll(trace);
+ }
+ StringBuilder sb = new StringBuilder();
+ for (final String element : frames) {
+ sb.append(element).append(LogConst.LINE_SEP);
+ }
+ return sb.toString();
+ }
+
+ private static List getStackFrameList(final Throwable throwable) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw, true);
+ throwable.printStackTrace(pw);
+ final String stackTrace = sw.toString();
+ final StringTokenizer frames = new StringTokenizer(stackTrace, LogConst.LINE_SEP);
+ final List list = new ArrayList<>();
+ boolean traceStarted = false;
+ while (frames.hasMoreTokens()) {
+ final String token = frames.nextToken();
+ // Determine if the line starts with at
+ final int at = token.indexOf("at");
+ if (at != -1 && token.substring(0, at).trim().isEmpty()) {
+ traceStarted = true;
+ list.add(token);
+ } else if (traceStarted) {
+ break;
+ }
+ }
+ return list;
+ }
+
+ private static void removeCommonFrames(final List causeFrames, final List wrapperFrames) {
+ int causeFrameIndex = causeFrames.size() - 1;
+ int wrapperFrameIndex = wrapperFrames.size() - 1;
+ while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
+ // Remove the frame from the cause trace if it is the same
+ // as in the wrapper trace
+ final String causeFrame = causeFrames.get(causeFrameIndex);
+ final String wrapperFrame = wrapperFrames.get(wrapperFrameIndex);
+ if (causeFrame.equals(wrapperFrame)) {
+ causeFrames.remove(causeFrameIndex);
+ }
+ causeFrameIndex--;
+ wrapperFrameIndex--;
+ }
+ }
+ }
+
+ static class LogConst {
+ static LINE_SEP = System.getProperty("line.separator");
+ static BORDER_TOP = "┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────" + LINE_SEP
+ static BORDER_LFT = "│ ";
+ static BORDER_BTM = "└────────────────────────────────────────────────────────────────────────────────────────────────────────────────" + LINE_SEP
+
+ static final NOTHING = "log nothing";
+ static final NULL = "null";
+ }
+}
diff --git a/buildSrc/src/main/groovy/LibConfig.groovy b/buildSrc/src/main/groovy/LibConfig.groovy
new file mode 100644
index 0000000000..6369553ba0
--- /dev/null
+++ b/buildSrc/src/main/groovy/LibConfig.groovy
@@ -0,0 +1,29 @@
+class LibConfig {
+
+ String path
+
+ String getGroupId() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[0] : null
+ }
+
+ String getArtifactId() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[1] : null
+ }
+
+ String getVersion() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[2] : null
+ }
+
+ @Override
+ String toString() {
+ return "LibConfig { path = $path }"
+ }
+
+ static String getFlag(boolean b) {
+ return b ? "✅" : "❌"
+ }
+}
+
diff --git a/buildSrc/src/main/groovy/ModuleConfig.groovy b/buildSrc/src/main/groovy/ModuleConfig.groovy
new file mode 100644
index 0000000000..291abd8ffe
--- /dev/null
+++ b/buildSrc/src/main/groovy/ModuleConfig.groovy
@@ -0,0 +1,35 @@
+class ModuleConfig {
+
+ boolean isApply // 是否应用
+ boolean useLocal // 是否使用本地的
+ String localPath // 本地路径
+ String remotePath // 远程路径
+ def dep // 根据条件生成项目最终的依赖项
+
+ String getGroupId() {
+ String[] splits = remotePath.split(":")
+ return splits.length == 3 ? splits[0] : null
+ }
+
+ String getArtifactId() {
+ String[] splits = remotePath.split(":")
+ return splits.length == 3 ? splits[1] : null
+ }
+
+ String getVersion() {
+ String[] splits = remotePath.split(":")
+ return splits.length == 3 ? splits[2] : null
+ }
+
+ @Override
+ String toString() {
+ return "ModuleConfig { isApply = ${getFlag(isApply)}" +
+ ", dep = " + dep +
+ " }"
+ }
+
+ static String getFlag(boolean b) {
+ return b ? "✅" : "❌"
+ }
+}
+
diff --git a/buildSrc/src/main/groovy/PluginConfig.groovy b/buildSrc/src/main/groovy/PluginConfig.groovy
new file mode 100644
index 0000000000..3811c6a0ca
--- /dev/null
+++ b/buildSrc/src/main/groovy/PluginConfig.groovy
@@ -0,0 +1,35 @@
+final class PluginConfig {
+
+ boolean isApply = true // 是否应用
+ boolean useLocal // 是否使用本地的
+ String path // 插件路径
+ String id // 插件 ID
+
+ String getGroupId() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[0] : null
+ }
+
+ String getArtifactId() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[1] : null
+ }
+
+ String getVersion() {
+ String[] splits = path.split(":")
+ return splits.length == 3 ? splits[2] : null
+ }
+
+ @Override
+ String toString() {
+ return "PluginConfig { isApply = ${getFlag(isApply)}" +
+ ", useLocal = ${getFlag(useLocal)}" +
+ ", path = " + path +
+ ", id = " + id +
+ " }"
+ }
+
+ static String getFlag(boolean b) {
+ return b ? "✅" : "❌"
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/TaskDurationUtils.groovy b/buildSrc/src/main/groovy/TaskDurationUtils.groovy
new file mode 100644
index 0000000000..6aacfcf30f
--- /dev/null
+++ b/buildSrc/src/main/groovy/TaskDurationUtils.groovy
@@ -0,0 +1,91 @@
+import org.gradle.BuildListener
+import org.gradle.BuildResult
+import org.gradle.api.Task
+import org.gradle.api.execution.TaskExecutionListener
+import org.gradle.api.initialization.Settings
+import org.gradle.api.invocation.Gradle
+import org.gradle.api.tasks.TaskState
+
+import java.text.SimpleDateFormat
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/22
+ * desc :
+ *
+ */
+class TaskDurationUtils {
+
+ static List taskInfoList = []
+ static long startMillis
+
+ static init(Gradle grd) {
+ startMillis = System.currentTimeMillis()
+ grd.addListener(new TaskExecutionListener() {
+ @Override
+ void beforeExecute(Task task) {
+ task.ext.startTime = System.currentTimeMillis()
+ }
+
+ @Override
+ void afterExecute(Task task, TaskState state) {
+ def exeDuration = System.currentTimeMillis() - task.ext.startTime
+ if (exeDuration >= 500) {
+ taskInfoList.add(new TaskInfo(task: task, exeDuration: exeDuration))
+ }
+ }
+ })
+ grd.addBuildListener(new BuildListener() {
+ @Override
+ void beforeSettings(Settings settings) {
+ super.beforeSettings(settings)
+ }
+
+ @Override
+ void buildStarted(Gradle gradle) {}
+
+ @Override
+ void settingsEvaluated(Settings settings) {}
+
+ @Override
+ void projectsLoaded(Gradle gradle) {}
+
+ @Override
+ void projectsEvaluated(Gradle gradle) {}
+
+ @Override
+ void buildFinished(BuildResult buildResult) {
+ if (!taskInfoList.isEmpty()) {
+ Collections.sort(taskInfoList, new Comparator() {
+ @Override
+ int compare(TaskInfo t, TaskInfo t1) {
+ return t1.exeDuration - t.exeDuration
+ }
+ })
+ StringBuilder sb = new StringBuilder()
+ int buildSec = (System.currentTimeMillis() - startMillis) / 1000;
+ int m = buildSec / 60;
+ int s = buildSec % 60;
+ def timeInfo = (m == 0 ? "${s}s" : "${m}m ${s}s (${buildSec}s)")
+ sb.append("BUILD FINISHED in $timeInfo\n")
+ taskInfoList.each {
+ sb.append(String.format("%7sms %s\n", it.exeDuration, it.task.path))
+ }
+ def content = sb.toString()
+ GLog.d(content)
+ File file = new File(grd.rootProject.buildDir.getAbsolutePath(),
+ "build_time_records_" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".txt")
+ file.getParentFile().mkdirs()
+ file.write(content)
+ }
+ }
+ })
+ }
+
+ private static class TaskInfo {
+ Task task
+ long exeDuration
+ }
+}
diff --git a/buildSrc/src/main/java/com/blankj/plugin/readme/FormatUtils.groovy b/buildSrc/src/main/java/com/blankj/plugin/readme/FormatUtils.groovy
new file mode 100644
index 0000000000..f617ff2eae
--- /dev/null
+++ b/buildSrc/src/main/java/com/blankj/plugin/readme/FormatUtils.groovy
@@ -0,0 +1,42 @@
+package com.blankj.plugin.readme
+
+class FormatUtils {
+
+ static def LINE_SEP = System.getProperty("line.separator")
+ static def LONG_SPACE = " "
+
+ static def format(File readmeCN) {
+ def sb = new StringBuilder(),
+ lines = readmeCN.readLines("UTF-8"),
+ i = 0,
+ size = lines.size()
+ for (; i < size; ++i) {
+ String line = lines.get(i)
+ if (line.contains("* ###")) {
+ sb.append(line).append(LINE_SEP)
+ .append("```").append(LINE_SEP)
+ def maxLen = 0
+ line = lines.get(i += 2)
+ // get the max length of space
+ for (def j = i; !line.equals("```"); line = lines.get(++j)) {
+ maxLen = Math.max(maxLen, line.replace(" ", "").replace(",", ", ").indexOf(':'))
+ }
+ line = lines.get(i)
+ for (; !line.equals("```"); line = lines.get(++i)) {
+ def noSpaceLine = line.replace(" ", "")
+ def spaceLen = maxLen - line.replace(" ", "").replace(",", ", ").indexOf(':')
+ sb.append(noSpaceLine.substring(0, noSpaceLine.indexOf(':')).replace(",", ", "))
+ .append(LONG_SPACE.substring(0, spaceLen))// add the space
+ .append(': ')
+ .append(line.substring(line.indexOf(':') + 1).trim())
+ .append(LINE_SEP)
+ }
+ sb.append("```")
+ } else {
+ sb.append(line)
+ }
+ sb.append(LINE_SEP)
+ }
+ readmeCN.write(sb.toString(), "UTF-8")
+ }
+}
diff --git a/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeCorePlugin.groovy b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeCorePlugin.groovy
new file mode 100644
index 0000000000..8f3cf47780
--- /dev/null
+++ b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeCorePlugin.groovy
@@ -0,0 +1,52 @@
+package com.blankj.plugin.readme
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class ReadmeCorePlugin implements Plugin {
+
+ @Override
+ void apply(Project project) {
+ project.extensions.create('readme', ReadmeExtension)
+
+ project.task('readmeTask') {
+ doLast {
+ println "readmeTask start..."
+
+ def ext = project['readme'] as ReadmeExtension
+ def readmeCN = ext.readmeCnFile
+ def readmeEng = ext.readmeFile
+
+ readmeOfUtilCode2Eng(readmeCN, readmeEng)
+
+ println "readmeTask finished."
+ }
+ }
+ }
+
+ static def readmeOfUtilCode2Eng(File readmeCN, File readmeEng) {
+ FormatUtils.format(readmeCN)
+ def lines = readmeCN.readLines("UTF-8")
+ def sb = new StringBuilder()
+ readmeCN.eachLine { line ->
+ if (line.contains("* ###")) {
+ if (line.contains("UtilsTransActivity")) {
+ sb.append(line)
+ } else {
+ String utilsName = line.substring(line.indexOf("[") + 1, line.indexOf("Utils"))
+ sb.append("* ### About ").append(utilsName).append(line.substring(line.indexOf(" -> ")))
+ }
+ } else if (line.contains(": ") && !line.contains("[")) {
+ sb.append(line.substring(0, line.indexOf(':')).trim())
+ } else if (line.contains("打个小广告") || line.contains("基你太美")) {
+ return
+ } else {
+ sb.append(line)
+ }
+ sb.append(FormatUtils.LINE_SEP)
+ }
+ readmeEng.write(sb.toString(), "UTF-8")
+ }
+}
+
+
diff --git a/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeExtension.groovy b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeExtension.groovy
new file mode 100644
index 0000000000..789e683c80
--- /dev/null
+++ b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeExtension.groovy
@@ -0,0 +1,8 @@
+package com.blankj.plugin.readme
+
+class ReadmeExtension {
+
+ File readmeFile
+ File readmeCnFile
+
+}
diff --git a/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeSubPlugin.groovy b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeSubPlugin.groovy
new file mode 100644
index 0000000000..bade51bbf4
--- /dev/null
+++ b/buildSrc/src/main/java/com/blankj/plugin/readme/ReadmeSubPlugin.groovy
@@ -0,0 +1,49 @@
+package com.blankj.plugin.readme
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class ReadmeSubPlugin implements Plugin {
+
+ @Override
+ void apply(Project project) {
+ project.extensions.create('readme', ReadmeExtension)
+
+ project.task('readmeTask') {
+ doLast {
+ println "readmeTask start..."
+
+ def ext = project['readme'] as ReadmeExtension
+ def readmeCN = ext.readmeCnFile
+ def readmeEng = ext.readmeFile
+
+ readmeOfSubUtil2Eng(readmeCN, readmeEng)
+
+ println "readmeTask finished."
+ }
+ }
+ }
+
+ static def readmeOfSubUtil2Eng(File readmeCN, File readmeEng) {
+ FormatUtils.format(readmeCN)
+ def lines = readmeCN.readLines("UTF-8"),
+ sb = new StringBuilder("## How to use" + FormatUtils.LINE_SEP
+ + FormatUtils.LINE_SEP +
+ "You should copy the following classes which you want to use in your project." + FormatUtils.LINE_SEP),
+ i = 3,
+ size = lines.size()
+ for (; i < size; ++i) {
+ String line = lines.get(i)
+ if (line.contains("* ###")) {
+ String utilsName = line.substring(line.indexOf("[") + 1, line.indexOf("Utils"))
+ sb.append("* ### About ").append(utilsName).append(line.substring(line.indexOf(" -> ")))
+ } else if (line.contains(": ") && !line.contains("[")) {
+ sb.append(line.substring(0, line.indexOf(':')).trim())
+ } else {
+ sb.append(line)
+ }
+ sb.append(FormatUtils.LINE_SEP)
+ }
+ readmeEng.write(sb.toString(), "UTF-8")
+ }
+}
diff --git a/config/flavor.gradle b/config/flavor.gradle
new file mode 100644
index 0000000000..25c1801983
--- /dev/null
+++ b/config/flavor.gradle
@@ -0,0 +1,22 @@
+android {
+ flavorDimensions "env"
+ productFlavors {
+ dev {
+ dimension "env"
+ }
+
+ production {
+ dimension "env"
+ }
+ }
+
+ variantFilter { variant ->
+ def flavorNames = variant.flavors*.name
+ def buildTypeName = variant.buildType.name
+
+ // production 包不允许 debug 构建
+ if (flavorNames.contains("production") && buildTypeName.contains("debug")) {
+ variant.setIgnore(true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/publish.gradle b/config/publish.gradle
new file mode 100644
index 0000000000..7608215123
--- /dev/null
+++ b/config/publish.gradle
@@ -0,0 +1,226 @@
+/*
+ 1. add
+ signing.keyId=xx
+ signing.password=xx
+ signing.secretKeyRingFile=/Users/xx/secring.gpg
+ ossrhUsername=xx
+ ossrhPassword=xx
+ in root local.properties
+
+ 2. copy the file to the directory of gradle, and apply the file in the module
+ ext {
+ groupId = Config.modules.lib_utilcode.groupId
+ artifactId = Config.modules.lib_utilcode.artifactId
+ version = Config.modules.lib_utilcode.version
+ website = "https://github.com/Blankj/AndroidUtilCode"
+}
+ apply from: "${rootDir.path}/config/publish.gradle"
+
+ 3. execute following command to publish
+ ./gradlew :xxmodule:publish2Local -> upload to mavenLocal
+ ./gradlew :xxmodule:publish2Remote -> upload to mavenCentral
+*/
+
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+ext.multiPublishMode = true
+
+File localPropertiesFile = project.rootProject.file("local.properties");
+if (!localPropertiesFile.exists()) {
+ return
+}
+
+Properties properties = new Properties()
+properties.load(new FileInputStream(localPropertiesFile))
+properties.each { name, value -> ext[name] = value }
+
+afterEvaluate {
+ def ext = project.ext
+ publishing {
+ publications {
+ release(MavenPublication) {
+ groupId ext.groupId
+ artifactId ext.artifactId
+ version ext.version
+
+ if (isAndroidEnv(project)) {
+ if (project.ext.multiPublishMode) {
+ artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
+ artifact sourcesJar
+ } else {
+ from project.components.release
+ }
+ } else {
+ from project.components.java
+ }
+
+ pom {
+ name = ext.artifactId
+ description = ext.artifactId
+ url = ext.website
+
+ licenses {
+ license {
+ name = 'The Apache Software License, Version 2.0'
+ url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ }
+ }
+ developers {
+ developer {
+ id = ext.ossrhUsername
+ name = ext.ossrhUsername
+ }
+ }
+ scm {
+ url = ext.website
+ connection = ext.website
+ developerConnection = ext.website + ".git"
+ }
+
+ if (project.ext.multiPublishMode) {
+ withXml {
+ def dependenciesNode = asNode().getAt('dependencies')[0] ?:
+ asNode().appendNode('dependencies')
+
+ configurations.api.getDependencies().each {
+ dep -> addDependency(project, dependenciesNode, dep, "compile")
+ }
+ configurations.implementation.getDependencies().each {
+ dep -> addDependency(project, dependenciesNode, dep, "runtime")
+ }
+ }
+ }
+ }
+ }
+ }
+
+ repositories {
+ maven {
+ // s01 is newest
+ def releasesUrl = "https://s01.oss.sonatype.org/content/repositories/releases/"
+ def snapshotUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
+ url = version.toUpperCase().endsWith('SNAPSHOT') ? snapshotUrl : releasesUrl
+
+ credentials {
+ username ossrhUsername
+ password ossrhPassword
+ }
+ }
+ }
+ }
+
+ signing {
+ sign publishing.publications
+ }
+}
+
+private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) {
+ if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
+ return
+ }
+
+ final dependencyNode = dependenciesNode.appendNode('dependency')
+ dependencyNode.appendNode('scope', scope)
+
+ if (dep.version == 'unspecified') {
+ // 检测 module 中的 dependencies 是否有源码依赖
+ // 如果是源码依赖,而且没有在 config 中配置 remotePath,
+ // 那么发布到仓库,其他地方依赖该库时会找不到源码的那个库
+ println "publish -> module(unspecified) <${dep.group}:${dep.name}:${dep.version}>"
+ if (project.ext.groupId || project.ext.version) {
+ throw new GradleException("The module of <" + dep.name + "> should set groupId & version.")
+ }
+ // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath
+ println("publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>")
+
+ dependencyNode.appendNode('groupId', project.ext.pomGroupID)
+ dependencyNode.appendNode('artifactId', dep.name)
+ dependencyNode.appendNode('version', project.ext.pomVersion)
+ } else {
+ dependencyNode.appendNode('groupId', dep.group)
+ dependencyNode.appendNode('artifactId', dep.name)
+ dependencyNode.appendNode('version', dep.version)
+ println("publish -> library <${dep.group}:${dep.name}:${dep.version}>")
+ }
+
+ if (!dep.transitive) {
+ // In case of non transitive dependency,
+ // all its dependencies should be force excluded from them POM file
+ final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
+ exclusionNode.appendNode('groupId', '*')
+ exclusionNode.appendNode('artifactId', '*')
+ } else if (!dep.properties.excludeRules.empty) {
+ // For transitive with exclusions, all exclude rules should be added to the POM file
+ final exclusions = dependencyNode.appendNode('exclusions')
+ dep.properties.excludeRules.each { ExcludeRule rule ->
+ final exclusionNode = exclusions.appendNode('exclusion')
+ exclusionNode.appendNode('groupId', rule.group ?: '*')
+ exclusionNode.appendNode('artifactId', rule.module ?: '*')
+ }
+ }
+}
+
+if (isAndroidEnv(project)) {
+ // This generates sources.jar
+ task sourcesJar(type: Jar) {
+ classifier = 'sources'
+ from android.sourceSets.main.java.source
+ }
+
+ task javadoc(type: Javadoc) {
+ source = android.sourceSets.main.java.source
+ classpath += configurations.compile
+ classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+ }
+
+ task javadocJar(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+ }
+} else {
+ task sourcesJar(type: Jar, dependsOn: classes) {
+ classifier = 'sources'
+ from sourceSets.main.allSource
+ }
+
+ task javadocJar(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+ }
+}
+
+if (project.hasProperty("kotlin")) {
+ // Disable creating javadocs
+ project.tasks.withType(Javadoc) {
+ enabled = false
+ }
+}
+
+javadoc {
+ options {
+ encoding "UTF-8"
+ charSet 'UTF-8'
+ author true
+ version project.ext.version
+ links "http://docs.oracle.com/javase/7/docs/api"
+ title "${project.ext.artifactId} ${project.ext.version}"
+ }
+}
+
+artifacts {
+ archives javadocJar
+ archives sourcesJar
+}
+
+static def isAndroidEnv(Project project) {
+ return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
+}
+
+task publish2Local(type: GradleBuild) {
+ tasks = ['assemble', 'publishReleasePublicationToMavenLocal']
+}
+
+task publish2Remote(type: GradleBuild) {
+ tasks = ['assemble', 'publishReleasePublicationToMavenRepository']
+}
\ No newline at end of file
diff --git a/feature/launcher/app/.gitignore b/feature/launcher/app/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/launcher/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/launcher/app/build.gradle b/feature/launcher/app/build.gradle
new file mode 100644
index 0000000000..8f2b6d205d
--- /dev/null
+++ b/feature/launcher/app/build.gradle
@@ -0,0 +1,5 @@
+apply plugin: 'kotlin-kapt'
+
+dependencies {
+ kapt Config.libs.eventbus_processor.path
+}
\ No newline at end of file
diff --git a/feature/launcher/app/proguard-rules.pro b/feature/launcher/app/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/launcher/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/launcher/app/src/main/AndroidManifest.xml b/feature/launcher/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..4f033c06a6
--- /dev/null
+++ b/feature/launcher/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java b/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java
new file mode 100644
index 0000000000..7dc22cee69
--- /dev/null
+++ b/feature/launcher/app/src/main/java/com/blankj/launcher/app/LauncherApp.java
@@ -0,0 +1,28 @@
+package com.blankj.launcher.app;
+
+import com.blankj.common.CommonApplication;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/12
+ * desc :
+ *
+ */
+public class LauncherApp extends CommonApplication {
+
+ private static LauncherApp sInstance;
+
+ public static LauncherApp getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ sInstance = this;
+ }
+}
+
+
diff --git a/feature/main/app/.gitignore b/feature/main/app/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/main/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/main/app/build.gradle b/feature/main/app/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/main/app/proguard-rules.pro b/feature/main/app/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/main/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/main/app/src/main/AndroidManifest.xml b/feature/main/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..bb8c3398d4
--- /dev/null
+++ b/feature/main/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/main/app/src/main/java/com/blankj/main/app/MainApp.java b/feature/main/app/src/main/java/com/blankj/main/app/MainApp.java
new file mode 100644
index 0000000000..7b083b92ba
--- /dev/null
+++ b/feature/main/app/src/main/java/com/blankj/main/app/MainApp.java
@@ -0,0 +1,35 @@
+package com.blankj.main.app;
+
+import android.content.Context;
+
+import com.blankj.common.CommonApplication;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/12
+ * desc :
+ *
+ */
+public class MainApp extends CommonApplication {
+
+ private static MainApp sInstance;
+
+ public static MainApp getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ sInstance = this;
+ }
+}
+
+
diff --git a/feature/main/pkg/.gitignore b/feature/main/pkg/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/main/pkg/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/main/pkg/build.gradle b/feature/main/pkg/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/main/pkg/proguard-rules.pro b/feature/main/pkg/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/main/pkg/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/main/pkg/src/main/AndroidManifest.xml b/feature/main/pkg/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..1cfdba8f69
--- /dev/null
+++ b/feature/main/pkg/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt b/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt
new file mode 100644
index 0000000000..b00aba9585
--- /dev/null
+++ b/feature/main/pkg/src/main/java/com/blankj/main/pkg/MainActivity.kt
@@ -0,0 +1,74 @@
+package com.blankj.main.pkg
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.ActionBarDrawerToggle
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.subutil.export.api.SubUtilApi
+import com.blankj.utilcode.export.api.UtilCodeApi
+import com.blankj.utilcode.util.ApiUtils
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.ClickUtils
+import com.blankj.utilcode.util.CollectionUtils
+import kotlinx.android.synthetic.main.activity_main.*
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : MainActivity
+ * ```
+ */
+class MainActivity : CommonActivity() {
+
+ override fun isSwipeBack(): Boolean {
+ return false
+ }
+
+ override fun bindDrawer(): Boolean {
+ return true
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.activity_main
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ window.setBackgroundDrawable(null)
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(mainRv, CollectionUtils.newArrayList>(
+ CommonItemClick(R.string.core_util, true) {
+ ApiUtils.getApi(UtilCodeApi::class.java)?.startUtilCodeActivity(this)
+ },
+ CommonItemClick(R.string.sub_util, true) {
+ ApiUtils.getApi(SubUtilApi::class.java)?.startSubUtilActivity(this)
+ }
+ ))
+
+ launcherMainCtl.setExpandedTitleColor(Color.TRANSPARENT)
+ setSupportActionBar(launcherMainToolbar)
+ val toggle = ActionBarDrawerToggle(this,
+ drawerView.mBaseDrawerRootLayout,
+ launcherMainToolbar,
+ R.string.navigation_drawer_open,
+ R.string.navigation_drawer_close)
+ drawerView.mBaseDrawerRootLayout.addDrawerListener(toggle)
+ toggle.syncState()
+
+ BarUtils.setStatusBarColor4Drawer(drawerView.mBaseDrawerRootLayout, launcherMainFakeStatusBar, Color.TRANSPARENT, false)
+ BarUtils.addMarginTopEqualStatusBarHeight(launcherMainToolbar)
+ }
+
+ override fun onBackPressed() {
+ ClickUtils.back2HomeFriendly("Press again to exit.")
+ }
+}
diff --git a/feature/main/pkg/src/main/java/com/blankj/main/pkg/SplashActivity.kt b/feature/main/pkg/src/main/java/com/blankj/main/pkg/SplashActivity.kt
new file mode 100644
index 0000000000..9f842cda06
--- /dev/null
+++ b/feature/main/pkg/src/main/java/com/blankj/main/pkg/SplashActivity.kt
@@ -0,0 +1,7 @@
+package com.blankj.main.pkg
+
+import com.blankj.common.activity.CommonActivity
+
+class SplashActivity : CommonActivity() {
+
+}
\ No newline at end of file
diff --git a/feature/main/pkg/src/main/res/layout/activity_main.xml b/feature/main/pkg/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000..3a33dd0f8e
--- /dev/null
+++ b/feature/main/pkg/src/main/res/layout/activity_main.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/main/pkg/src/main/res/values/strings.xml b/feature/main/pkg/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..7abc06d3ba
--- /dev/null
+++ b/feature/main/pkg/src/main/res/values/strings.xml
@@ -0,0 +1 @@
+
diff --git a/feature/mock/.gitignore b/feature/mock/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/mock/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/mock/build.gradle b/feature/mock/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/mock/proguard-rules.pro b/feature/mock/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/mock/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/mock/src/main/AndroidManifest.xml b/feature/mock/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..8c0f9aa047
--- /dev/null
+++ b/feature/mock/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/feature/mock/src/main/java/com/blankj/mock/subutil/SubUtilApiMock.java b/feature/mock/src/main/java/com/blankj/mock/subutil/SubUtilApiMock.java
new file mode 100644
index 0000000000..6c5af69924
--- /dev/null
+++ b/feature/mock/src/main/java/com/blankj/mock/subutil/SubUtilApiMock.java
@@ -0,0 +1,25 @@
+package com.blankj.mock.subutil;
+
+import android.content.Context;
+
+import com.blankj.subutil.export.api.SubUtilApi;
+import com.blankj.utilcode.util.ApiUtils;
+import com.blankj.utilcode.util.ToastUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/10
+ * desc :
+ *
+ */
+@ApiUtils.Api(isMock = true)
+public class SubUtilApiMock extends SubUtilApi {
+
+ @Override
+ public void startSubUtilActivity(Context context) {
+ ToastUtils.showShort("startSubUtilActivity");
+ }
+
+}
diff --git a/feature/mock/src/main/java/com/blankj/mock/utilcode/UtilCodeApiMock.java b/feature/mock/src/main/java/com/blankj/mock/utilcode/UtilCodeApiMock.java
new file mode 100644
index 0000000000..df22cbf92a
--- /dev/null
+++ b/feature/mock/src/main/java/com/blankj/mock/utilcode/UtilCodeApiMock.java
@@ -0,0 +1,32 @@
+package com.blankj.mock.utilcode;
+
+import android.content.Context;
+
+import com.blankj.utilcode.export.api.UtilCodeApi;
+import com.blankj.utilcode.util.ApiUtils;
+import com.blankj.utilcode.util.ToastUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/10
+ * desc :
+ *
+ */
+@ApiUtils.Api(isMock = true)
+public class UtilCodeApiMock extends UtilCodeApi {
+
+ @Override
+ public void startUtilCodeActivity(Context context) {
+ ToastUtils.showShort("startUtilCodeActivity");
+ }
+
+ @Override
+ public void testCallback(Callback callback) {
+ if (callback != null) {
+ callback.call();
+ }
+ }
+
+}
diff --git a/feature/subutil/app/.gitignore b/feature/subutil/app/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/subutil/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/subutil/app/build.gradle b/feature/subutil/app/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/subutil/app/proguard-rules.pro b/feature/subutil/app/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/subutil/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/subutil/app/src/main/AndroidManifest.xml b/feature/subutil/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..2989dbfebf
--- /dev/null
+++ b/feature/subutil/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/subutil/app/src/main/java/com/blankj/subutil/app/SubUtilApp.kt b/feature/subutil/app/src/main/java/com/blankj/subutil/app/SubUtilApp.kt
new file mode 100644
index 0000000000..9667490cf4
--- /dev/null
+++ b/feature/subutil/app/src/main/java/com/blankj/subutil/app/SubUtilApp.kt
@@ -0,0 +1,32 @@
+package com.blankj.subutil.app
+
+import android.content.Context
+import com.blankj.common.CommonApplication
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/12
+ * desc : app about utils
+ * ```
+ */
+class SubUtilApp : CommonApplication() {
+
+ companion object {
+ var instance: SubUtilApp? = null
+ private set
+ }
+
+ override fun attachBaseContext(base: Context) {
+ super.attachBaseContext(base)
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ instance = this
+ }
+}
+
+
diff --git a/feature/subutil/export/.gitignore b/feature/subutil/export/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/subutil/export/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/subutil/export/build.gradle b/feature/subutil/export/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/subutil/export/proguard-rules.pro b/feature/subutil/export/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/subutil/export/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/subutil/export/src/main/AndroidManifest.xml b/feature/subutil/export/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..de00a6d73e
--- /dev/null
+++ b/feature/subutil/export/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/feature/subutil/export/src/main/java/com/blankj/subutil/export/api/SubUtilApi.java b/feature/subutil/export/src/main/java/com/blankj/subutil/export/api/SubUtilApi.java
new file mode 100644
index 0000000000..c0e4abe037
--- /dev/null
+++ b/feature/subutil/export/src/main/java/com/blankj/subutil/export/api/SubUtilApi.java
@@ -0,0 +1,20 @@
+package com.blankj.subutil.export.api;
+
+import android.content.Context;
+
+import com.blankj.utilcode.util.ApiUtils;
+
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/06/09
+ * desc :
+ *
+ */
+public abstract class SubUtilApi extends ApiUtils.BaseApi {
+
+ public abstract void startSubUtilActivity(Context context);
+
+}
diff --git a/feature/subutil/pkg/.gitignore b/feature/subutil/pkg/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/subutil/pkg/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/subutil/pkg/build.gradle b/feature/subutil/pkg/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/subutil/pkg/proguard-rules.pro b/feature/subutil/pkg/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/subutil/pkg/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/subutil/pkg/src/main/AndroidManifest.xml b/feature/subutil/pkg/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..198eb5c31b
--- /dev/null
+++ b/feature/subutil/pkg/src/main/AndroidManifest.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/Config.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/Config.kt
new file mode 100644
index 0000000000..82a8db84d3
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/Config.kt
@@ -0,0 +1,31 @@
+package com.blankj.subutil.pkg
+
+import android.os.Environment
+import com.blankj.utilcode.util.Utils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/10
+ * desc : config about constants
+ * ```
+ */
+object Config {
+
+ val FILE_SEP = System.getProperty("file.separator")
+ val LINE_SEP = System.getProperty("line.separator")
+ const val TEST_PKG = "com.blankj.testinstall"
+ private val CACHE_PATH: String
+ val TEST_APK_PATH: String
+
+ init {
+ val cacheDir = Utils.getApp().externalCacheDir
+ CACHE_PATH = if (cacheDir != null) {
+ cacheDir.absolutePath
+ } else {
+ Environment.getExternalStorageDirectory().absolutePath
+ } + FILE_SEP
+ TEST_APK_PATH = CACHE_PATH + "test_install.apk"
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/SubUtilApiImpl.java b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/SubUtilApiImpl.java
new file mode 100644
index 0000000000..0b978f1bcd
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/SubUtilApiImpl.java
@@ -0,0 +1,25 @@
+package com.blankj.subutil.pkg;
+
+import android.content.Context;
+
+import com.blankj.subutil.export.api.SubUtilApi;
+import com.blankj.subutil.pkg.feature.SubUtilActivity;
+import com.blankj.utilcode.util.ApiUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/02
+ * desc :
+ *
+ */
+@ApiUtils.Api
+public class SubUtilApiImpl extends SubUtilApi {
+
+ @Override
+ public void startSubUtilActivity(Context context) {
+ SubUtilActivity.Companion.start(context);
+ }
+
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/SubUtilActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/SubUtilActivity.kt
new file mode 100644
index 0000000000..2c6af650ef
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/SubUtilActivity.kt
@@ -0,0 +1,61 @@
+package com.blankj.subutil.pkg.feature
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.pkg.feature.appStore.AppStoreActivity
+import com.blankj.subutil.pkg.feature.battery.BatteryActivity
+import com.blankj.subutil.pkg.feature.country.CountryActivity
+import com.blankj.subutil.pkg.feature.dangerous.DangerousActivity
+import com.blankj.subutil.pkg.feature.location.LocationActivity
+import com.blankj.subutil.pkg.feature.pinyin.PinyinActivity
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : MainActivity
+ * ```
+ */
+class SubUtilActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, SubUtilActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+
+ override fun bindTitleRes(): Int {
+ return R.string.sub_util
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.demo_app_store, true) {
+ AppStoreActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_battery, true) {
+ BatteryActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_country, true) {
+ CountryActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_dangerous, true) {
+ DangerousActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_location, true) {
+ LocationActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_pinyin, true) {
+ PinyinActivity.start(this)
+ }
+ )
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
new file mode 100644
index 0000000000..e7c2953448
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
@@ -0,0 +1,43 @@
+package com.blankj.subutil.pkg.feature.appStore
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.util.AppStoreUtils
+import com.blankj.utilcode.util.ActivityUtils
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/01
+ * desc : demo about AppStore
+ * ```
+ */
+class AppStoreActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, AppStoreActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_app_store
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.app_store_system, true) {
+ AppStoreUtils.getAppStoreIntent("com.tencent.mm").apply {
+ ActivityUtils.startActivity(this)
+ }
+ }
+ )
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/battery/BatteryActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/battery/BatteryActivity.kt
new file mode 100644
index 0000000000..8e04163c4f
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/battery/BatteryActivity.kt
@@ -0,0 +1,56 @@
+package com.blankj.subutil.pkg.feature.battery
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.util.BatteryUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 20/03/31
+ * desc : demo about Battery
+ * ```
+ */
+class BatteryActivity : CommonActivity(), BatteryUtils.OnBatteryStatusChangedListener {
+
+ private val titleItem: CommonItemTitle = CommonItemTitle("", true);
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BatteryActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_battery
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(titleItem)
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ BatteryUtils.registerBatteryStatusChangedListener(this)
+ }
+
+ override fun onBatteryStatusChanged(status: BatteryUtils.Status) {
+ titleItem.title = status.toString()
+ ToastUtils.showShort(status.toString())
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ BatteryUtils.unregisterBatteryStatusChangedListener(this)
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
new file mode 100644
index 0000000000..c2daa6ef50
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
@@ -0,0 +1,41 @@
+package com.blankj.subutil.pkg.feature.country
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.util.CountryUtils
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/01
+ * desc : demo about Country
+ * ```
+ */
+class CountryActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, CountryActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_country
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getCountryCodeBySim", CountryUtils.getCountryCodeBySim("Default")),
+ CommonItemTitle("getCountryCodeByLanguage", CountryUtils.getCountryCodeByLanguage("Default")),
+ CommonItemTitle("getCountryBySim", CountryUtils.getCountryBySim()),
+ CommonItemTitle("getCountryByLanguage", CountryUtils.getCountryByLanguage())
+ )
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
new file mode 100644
index 0000000000..cc5c60f470
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
@@ -0,0 +1,123 @@
+package com.blankj.subutil.pkg.feature.dangerous
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.subutil.pkg.Config
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.util.DangerousUtils
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/01
+ * desc : demo about dangerous
+ * ```
+ */
+class DangerousActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, DangerousActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.STORAGE, PermissionConstants.SMS)
+ }
+ }
+
+ private val listener = object : OnReleasedListener {
+ override fun onReleased() {
+ if (DangerousUtils.installAppSilent(Config.TEST_APK_PATH)) {
+ ToastUtils.showShort(R.string.dangerous_install_successfully)
+ } else {
+ ToastUtils.showShort(R.string.dangerous_install_unsuccessfully)
+ }
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_dangerous
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.dangerous_install_silent) {
+ if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+ ToastUtils.showShort(R.string.dangerous_app_install_tips)
+ } else {
+ if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
+ ReleaseInstallApkTask(listener).execute()
+ } else {
+ listener.onReleased()
+ }
+ }
+ },
+ CommonItemClick(R.string.dangerous_uninstall_silent) {
+ if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+ if (DangerousUtils.uninstallAppSilent(Config.TEST_PKG, false)) {
+ ToastUtils.showShort(R.string.dangerous_uninstall_successfully)
+ } else {
+ ToastUtils.showShort(R.string.dangerous_uninstall_unsuccessfully)
+ }
+ } else {
+ ToastUtils.showShort(R.string.dangerous_app_uninstall_tips)
+ }
+ },
+ CommonItemClick(R.string.dangerous_shutdown) {
+ ToastUtils.showShort(DangerousUtils.shutdown().toString())
+ },
+ CommonItemClick(R.string.dangerous_reboot) {
+ ToastUtils.showShort(DangerousUtils.reboot().toString())
+ },
+ CommonItemClick(R.string.dangerous_reboot_to_recovery) {
+ ToastUtils.showShort(DangerousUtils.reboot2Recovery().toString())
+ },
+ CommonItemClick(R.string.dangerous_reboot_to_bootloader) {
+ ToastUtils.showShort(DangerousUtils.reboot2Bootloader().toString())
+ },
+ CommonItemSwitch(
+ R.string.dangerous_data_enabled,
+ { NetworkUtils.getMobileDataEnabled() },
+ {
+ if (AppUtils.isAppSystem()) {
+ DangerousUtils.setMobileDataEnabled(it)
+ }
+ }
+ ),
+ CommonItemClick(R.string.dangerous_send_sms_silent) {
+ DangerousUtils.sendSmsSilent("10000", "sendSmsSilent")
+ }
+ )
+ }
+}
+
+class ReleaseInstallApkTask(private val mListener: OnReleasedListener) : ThreadUtils.SimpleTask() {
+
+ override fun doInBackground() {
+ ResourceUtils.copyFileFromAssets("test_install", Config.TEST_APK_PATH)
+ }
+
+ override fun onSuccess(result: Unit) {
+ mListener.onReleased()
+ }
+
+ fun execute() {
+ ThreadUtils.executeByIo(this)
+ }
+}
+
+interface OnReleasedListener {
+ fun onReleased()
+}
\ No newline at end of file
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
new file mode 100755
index 0000000000..8f4217c96c
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
@@ -0,0 +1,100 @@
+package com.blankj.subutil.pkg.feature.location
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.subutil.pkg.R
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.PermissionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about LocationUtils
+ * ```
+ */
+class LocationActivity : CommonActivity() {
+
+ private var lastLatitude: String = "unknown"
+ private var lastLongitude: String = "unknown"
+ private var latitude: String = "unknown"
+ private var longitude: String = "unknown"
+ private var country: String = "unknown"
+ private var locality: String = "unknown"
+ private var street: String = "unknown"
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, LocationActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.LOCATION)
+ }
+ }
+
+ private lateinit var mLocationService: LocationService
+
+ private var conn: ServiceConnection = object : ServiceConnection {
+ override fun onServiceDisconnected(name: ComponentName) {}
+
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ mLocationService = (service as LocationService.LocationBinder).service
+ mLocationService.setOnGetLocationListener(object : LocationService.OnGetLocationListener {
+ override fun getLocation(lastLatitude: String, lastLongitude: String, latitude: String,
+ longitude: String, country: String, locality: String, street: String) {
+ this@LocationActivity.apply {
+ this.lastLatitude = lastLatitude
+ this.lastLongitude = lastLongitude
+ this.latitude = latitude
+ this.longitude = longitude
+ this.country = country
+ this.locality = locality
+ this.street = street
+ }
+ runOnUiThread {
+ itemsView.updateItems(bindItems())
+ }
+ }
+ })
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_location
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("lastLatitude", lastLatitude),
+ CommonItemTitle("lastLongitude", lastLongitude),
+ CommonItemTitle("latitude", latitude),
+ CommonItemTitle("longitude", longitude),
+ CommonItemTitle("getCountryName", country),
+ CommonItemTitle("getLocality", locality),
+ CommonItemTitle("getStreet", street)
+ )
+ }
+
+ override fun doBusiness() {
+ bindService(Intent(this, LocationService::class.java), conn, Context.BIND_AUTO_CREATE)
+ }
+
+ override fun onDestroy() {
+ unbindService(conn)
+ super.onDestroy()
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationService.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationService.kt
new file mode 100755
index 0000000000..8322500d63
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationService.kt
@@ -0,0 +1,95 @@
+package com.blankj.subutil.pkg.feature.location
+
+import android.app.Service
+import android.content.Intent
+import android.location.Location
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.os.Looper
+
+import com.blankj.subutil.util.LocationUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/11/21
+ * desc : demo about LocationUtils
+ * ```
+ */
+class LocationService : Service() {
+
+ private var isSuccess: Boolean = false
+ private var lastLatitude = "loading..."
+ private var lastLongitude = "loading..."
+ private var latitude = "loading..."
+ private var longitude = "loading..."
+ private var country = "loading..."
+ private var locality = "loading..."
+ private var street = "loading..."
+
+ private var mOnGetLocationListener: OnGetLocationListener? = null
+
+ private val mOnLocationChangeListener = object : LocationUtils.OnLocationChangeListener {
+ override fun getLastKnownLocation(location: Location) {
+ lastLatitude = location.latitude.toString()
+ lastLongitude = location.longitude.toString()
+ mOnGetLocationListener?.getLocation(lastLatitude, lastLongitude, latitude, longitude, country, locality, street)
+ }
+
+ override fun onLocationChanged(location: Location) {
+ latitude = location.latitude.toString()
+ longitude = location.longitude.toString()
+ mOnGetLocationListener?.getLocation(lastLatitude, lastLongitude, latitude, longitude, country, locality, street)
+ country = LocationUtils.getCountryName(java.lang.Double.parseDouble(latitude), java.lang.Double.parseDouble(longitude))
+ locality = LocationUtils.getLocality(java.lang.Double.parseDouble(latitude), java.lang.Double.parseDouble(longitude))
+ street = LocationUtils.getStreet(java.lang.Double.parseDouble(latitude), java.lang.Double.parseDouble(longitude))
+ mOnGetLocationListener?.getLocation(lastLatitude, lastLongitude, latitude, longitude, country, locality, street)
+ }
+
+ override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
+ }
+
+ fun setOnGetLocationListener(onGetLocationListener: OnGetLocationListener) {
+ mOnGetLocationListener = onGetLocationListener
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ Thread(Runnable {
+ Looper.prepare()
+ isSuccess = LocationUtils.register(0, 0, mOnLocationChangeListener)
+ if (isSuccess) ToastUtils.showShort("init success")
+ Looper.loop()
+ }).start()
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ return LocationBinder()
+ }
+
+ inner class LocationBinder : Binder() {
+ val service: LocationService
+ get() = this@LocationService
+ }
+
+ override fun onDestroy() {
+ LocationUtils.unregister()
+ // 一定要制空,否则内存泄漏
+ mOnGetLocationListener = null
+ super.onDestroy()
+ }
+
+ /**
+ * 获取位置监听器
+ */
+ interface OnGetLocationListener {
+ fun getLocation(
+ lastLatitude: String, lastLongitude: String,
+ latitude: String, longitude: String,
+ country: String, locality: String, street: String
+ )
+ }
+}
diff --git a/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
new file mode 100644
index 0000000000..648dcb295d
--- /dev/null
+++ b/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
@@ -0,0 +1,56 @@
+package com.blankj.subutil.pkg.feature.pinyin
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.subutil.pkg.R
+import com.blankj.subutil.util.PinyinUtils
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/01
+ * desc : demo about PinyinUtils
+ * ```
+ */
+class PinyinActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, PinyinActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_pinyin
+ }
+
+ override fun bindItems(): MutableList> {
+ val surnames = "乐乘乜仇会便区单参句召员宓弗折曾朴查洗盖祭种秘繁缪能蕃覃解谌适都阿难黑"
+ val size = surnames.length
+ val sb = StringBuilder("澹台: " + PinyinUtils.getSurnamePinyin("澹台")
+ + "\n尉迟: " + PinyinUtils.getSurnamePinyin("尉迟")
+ + "\n万俟: " + PinyinUtils.getSurnamePinyin("万俟")
+ + "\n单于: " + PinyinUtils.getSurnamePinyin("单于"))
+ for (i in 0 until size) {
+ val surname = surnames[i].toString()
+ sb.append(String.format(
+ "\n%s 正确: %-8s 错误: %-8s",
+ surname,
+ PinyinUtils.getSurnamePinyin(surname),
+ PinyinUtils.ccs2Pinyin(surname)
+ ))
+ }
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("汉字转拼音", PinyinUtils.ccs2Pinyin("汉字转拼音", " ")),
+ CommonItemTitle("获取首字母", PinyinUtils.getPinyinFirstLetters("获取首字母", " ")),
+ CommonItemTitle("测试姓氏", sb.toString())
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/subutil/pkg/src/main/res/values/strings.xml b/feature/subutil/pkg/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..e758c294a0
--- /dev/null
+++ b/feature/subutil/pkg/src/main/res/values/strings.xml
@@ -0,0 +1,29 @@
+
+
+ App Store Demo
+ Battery Demo
+ Country Demo
+ Dangerous Demo
+ LocationUtils Demo
+ PinyinUtils Demo
+
+
+ Go System App Store In WeChat Page
+
+ Install Test App Silently
+ Uninstall App Silently
+ Test app have installed
+ Install successfully
+ Install unsuccessfully
+ Please install test app first
+ Uninstall successfully
+ Uninstall unsuccessfully
+ Shutdown
+ Reboot
+ Reboot To Recovery
+ Reboot To Bootloader
+ Send SMS Silent
+ Mobile Data Enabled
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/app/.gitignore b/feature/utilcode/app/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/utilcode/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/utilcode/app/build.gradle b/feature/utilcode/app/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/utilcode/app/proguard-rules.pro b/feature/utilcode/app/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/utilcode/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/utilcode/app/src/main/AndroidManifest.xml b/feature/utilcode/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..34308fcb79
--- /dev/null
+++ b/feature/utilcode/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/app/src/main/java/com/blankj/utilcode/app/UtilCodeApp.kt b/feature/utilcode/app/src/main/java/com/blankj/utilcode/app/UtilCodeApp.kt
new file mode 100644
index 0000000000..42d2909041
--- /dev/null
+++ b/feature/utilcode/app/src/main/java/com/blankj/utilcode/app/UtilCodeApp.kt
@@ -0,0 +1,30 @@
+package com.blankj.utilcode.app
+
+import com.blankj.common.CommonApplication
+import com.blankj.utilcode.util.Utils
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/12
+ * desc : app about utils
+ * ```
+ */
+class UtilCodeApp : CommonApplication() {
+
+ companion object {
+ lateinit var instance: UtilCodeApp
+ private set
+ }
+
+ override fun onCreate() {
+ Utils.init(this)
+ super.onCreate()
+ instance = this
+// BusUtils.register("com.blankj.androidutilcode")
+ }
+}
+
+
diff --git a/feature/utilcode/export/.gitignore b/feature/utilcode/export/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/utilcode/export/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/utilcode/export/build.gradle b/feature/utilcode/export/build.gradle
new file mode 100644
index 0000000000..30e59272ee
--- /dev/null
+++ b/feature/utilcode/export/build.gradle
@@ -0,0 +1,8 @@
+ext {
+ groupId = Config.modules.feature_utilcode_export.groupId
+ artifactId = Config.modules.feature_utilcode_export.artifactId
+ version = Config.modules.feature_utilcode_export.version
+ website = "https://github.com/Blankj/AndroidUtilCode"
+}
+//apply from: "${rootDir.path}/config/publish.gradle"
+//./gradlew :feature_utilcode_export:mavenLocal // 上传到本地 mavenLocal
\ No newline at end of file
diff --git a/feature/utilcode/export/proguard-rules.pro b/feature/utilcode/export/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/utilcode/export/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/utilcode/export/src/main/AndroidManifest.xml b/feature/utilcode/export/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..9bbbcc3210
--- /dev/null
+++ b/feature/utilcode/export/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/feature/utilcode/export/src/main/java/com/blankj/utilcode/export/api/UtilCodeApi.java b/feature/utilcode/export/src/main/java/com/blankj/utilcode/export/api/UtilCodeApi.java
new file mode 100644
index 0000000000..ea7d5291be
--- /dev/null
+++ b/feature/utilcode/export/src/main/java/com/blankj/utilcode/export/api/UtilCodeApi.java
@@ -0,0 +1,26 @@
+package com.blankj.utilcode.export.api;
+
+import android.content.Context;
+
+import com.blankj.utilcode.util.ApiUtils;
+
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/01
+ * desc :
+ *
+ */
+public abstract class UtilCodeApi extends ApiUtils.BaseApi {
+
+ public abstract void startUtilCodeActivity(Context context);
+
+ public abstract void testCallback(Callback callback);
+
+ public interface Callback {
+ void call();
+ }
+
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/.gitignore b/feature/utilcode/pkg/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/feature/utilcode/pkg/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/feature/utilcode/pkg/build.gradle b/feature/utilcode/pkg/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/utilcode/pkg/proguard-rules.pro b/feature/utilcode/pkg/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/feature/utilcode/pkg/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/feature/utilcode/pkg/src/main/AndroidManifest.xml b/feature/utilcode/pkg/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..8da0667a23
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/AndroidManifest.xml
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/assets/fonts/dnmbhs.ttf b/feature/utilcode/pkg/src/main/assets/fonts/dnmbhs.ttf
new file mode 100644
index 0000000000..8ac8dadba1
Binary files /dev/null and b/feature/utilcode/pkg/src/main/assets/fonts/dnmbhs.ttf differ
diff --git a/feature/utilcode/pkg/src/main/assets/test/sub/test.txt b/feature/utilcode/pkg/src/main/assets/test/sub/test.txt
new file mode 100644
index 0000000000..f7bc1649eb
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/assets/test/sub/test.txt
@@ -0,0 +1,2 @@
+1st line
+2nd line
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/assets/test/test.txt b/feature/utilcode/pkg/src/main/assets/test/test.txt
new file mode 100644
index 0000000000..f7bc1649eb
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/assets/test/test.txt
@@ -0,0 +1,2 @@
+1st line
+2nd line
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/Config.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/Config.kt
new file mode 100644
index 0000000000..51bb0b7e66
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/Config.kt
@@ -0,0 +1,19 @@
+package com.blankj.utilcode.pkg
+
+import com.blankj.utilcode.util.PathUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/10
+ * desc : config about constants
+ * ```
+ */
+object Config {
+ val FILE_SEP = System.getProperty("file.separator")
+ val LINE_SEP = System.getProperty("line.separator")
+ const val TEST_PKG = "com.blankj.testinstall"
+ val CACHE_PATH = PathUtils.getCachePathExternalFirst() + FILE_SEP
+ val TEST_APK_PATH: String = CACHE_PATH + "test_install.apk"
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/UtilCodeApiImpl.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/UtilCodeApiImpl.java
new file mode 100644
index 0000000000..076858b3d1
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/UtilCodeApiImpl.java
@@ -0,0 +1,31 @@
+package com.blankj.utilcode.pkg;
+
+import android.content.Context;
+
+import com.blankj.utilcode.export.api.UtilCodeApi;
+import com.blankj.utilcode.pkg.feature.CoreUtilActivity;
+import com.blankj.utilcode.util.ApiUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/01
+ * desc :
+ *
+ */
+@ApiUtils.Api
+public class UtilCodeApiImpl extends UtilCodeApi {
+
+ @Override
+ public void startUtilCodeActivity(Context context) {
+ CoreUtilActivity.Companion.start(context);
+ }
+
+ @Override
+ public void testCallback(Callback callback) {
+ if (callback != null) {
+ callback.call();
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/CoreUtilActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/CoreUtilActivity.kt
new file mode 100644
index 0000000000..2640191959
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/CoreUtilActivity.kt
@@ -0,0 +1,226 @@
+package com.blankj.utilcode.pkg.feature
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.widget.TextView
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.feature.activity.ActivityActivity
+import com.blankj.utilcode.pkg.feature.adaptScreen.AdaptScreenActivity
+import com.blankj.utilcode.pkg.feature.api.ApiActivity
+import com.blankj.utilcode.pkg.feature.app.AppActivity
+import com.blankj.utilcode.pkg.feature.bar.BarActivity
+import com.blankj.utilcode.pkg.feature.brightness.BrightnessActivity
+import com.blankj.utilcode.pkg.feature.bus.BusActivity
+import com.blankj.utilcode.pkg.feature.clean.CleanActivity
+import com.blankj.utilcode.pkg.feature.click.ClickActivity
+import com.blankj.utilcode.pkg.feature.clipboard.ClipboardActivity
+import com.blankj.utilcode.pkg.feature.device.DeviceActivity
+import com.blankj.utilcode.pkg.feature.file.FileActivity
+import com.blankj.utilcode.pkg.feature.flashlight.FlashlightActivity
+import com.blankj.utilcode.pkg.feature.fragment.FragmentActivity
+import com.blankj.utilcode.pkg.feature.image.ImageActivity
+import com.blankj.utilcode.pkg.feature.intent.IntentActivity
+import com.blankj.utilcode.pkg.feature.keyboard.KeyboardActivity
+import com.blankj.utilcode.pkg.feature.language.LanguageActivity
+import com.blankj.utilcode.pkg.feature.log.LogActivity
+import com.blankj.utilcode.pkg.feature.messenger.MessengerActivity
+import com.blankj.utilcode.pkg.feature.metaData.MetaDataActivity
+import com.blankj.utilcode.pkg.feature.mvp.MvpActivity
+import com.blankj.utilcode.pkg.feature.network.NetworkActivity
+import com.blankj.utilcode.pkg.feature.notification.NotificationActivity
+import com.blankj.utilcode.pkg.feature.path.PathActivity
+import com.blankj.utilcode.pkg.feature.permission.PermissionActivity
+import com.blankj.utilcode.pkg.feature.phone.PhoneActivity
+import com.blankj.utilcode.pkg.feature.process.ProcessActivity
+import com.blankj.utilcode.pkg.feature.reflect.ReflectActivity
+import com.blankj.utilcode.pkg.feature.resource.ResourceActivity
+import com.blankj.utilcode.pkg.feature.rom.RomActivity
+import com.blankj.utilcode.pkg.feature.screen.ScreenActivity
+import com.blankj.utilcode.pkg.feature.sdcard.SDCardActivity
+import com.blankj.utilcode.pkg.feature.shadow.ShadowActivity
+import com.blankj.utilcode.pkg.feature.snackbar.SnackbarActivity
+import com.blankj.utilcode.pkg.feature.spStatic.SPStaticActivity
+import com.blankj.utilcode.pkg.feature.span.SpanActivity
+import com.blankj.utilcode.pkg.feature.toast.ToastActivity
+import com.blankj.utilcode.pkg.feature.uiMessage.UiMessageActivity
+import com.blankj.utilcode.pkg.feature.vibrate.VibrateActivity
+import com.blankj.utilcode.pkg.feature.volume.VolumeActivity
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.LogUtils
+import com.blankj.utilcode.util.ThreadUtils
+import com.blankj.utilcode.util.UtilsTransActivity
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc :
+ * ```
+ */
+class CoreUtilActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, CoreUtilActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.core_util
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.demo_activity, true) {
+ ActivityActivity.start(this)
+ ThreadUtils.runOnUiThreadDelayed(Runnable {
+
+ }, 2000)
+ },
+ CommonItemClick(R.string.demo_adapt_screen, true) {
+ AdaptScreenActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_api, true) {
+ ApiActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_app, true) {
+ AppActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_bar, true) {
+ BarActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_brightness, true) {
+ BrightnessActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_bus, true) {
+ BusActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_clean, true) {
+ CleanActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_click, true) {
+ ClickActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_clipboard, true) {
+ ClipboardActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_crash) {
+ throw NullPointerException("crash test")
+ },
+ CommonItemClick(R.string.demo_device, true) {
+ DeviceActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_file, true) {
+ FileActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_flashlight, true) {
+ FlashlightActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_fragment, true) {
+ FragmentActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_image, true) {
+ ImageActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_intent, true) {
+ IntentActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_keyboard, true) {
+ KeyboardActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_language, true) {
+ LanguageActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_log, true) {
+ LogActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_messenger, true) {
+ MessengerActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_meta_data, true) {
+ MetaDataActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_mvp, true) {
+ MvpActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_network, true) {
+ NetworkActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_notification, true) {
+ NotificationActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_path, true) {
+ PathActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_permission, true) {
+ PermissionActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_phone, true) {
+ PhoneActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_process, true) {
+ ProcessActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_reflect, true) {
+ ReflectActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_resource, true) {
+ ResourceActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_rom, true) {
+ RomActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_screen, true) {
+ ScreenActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_sdcard, true) {
+ SDCardActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_shadow, true) {
+ ShadowActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_snackbar, true) {
+ SnackbarActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_spStatic, true) {
+ SPStaticActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_span, true) {
+ SpanActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_toast, true) {
+ ToastActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_trans_activity, true) {
+ UtilsTransActivity.start(this, object : UtilsTransActivity.TransActivityDelegate() {
+ override fun onCreated(activity: UtilsTransActivity, savedInstanceState: Bundle?) {
+ super.onCreated(activity, savedInstanceState)
+ activity.setContentView(R.layout.common_dialog_loading)
+ activity.findViewById(R.id.utilActionLoadingMsgTv).text = "Trans Activity is showing..."
+ }
+ })
+ },
+ CommonItemClick(R.string.demo_uiMessage, true) {
+ UiMessageActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_vibrate, true) {
+ VibrateActivity.start(this)
+ },
+ CommonItemClick(R.string.demo_volume, true) {
+ VolumeActivity.start(this)
+ }
+ )
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ LogUtils.e(requestCode, requestCode)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
new file mode 100644
index 0000000000..97023b94c2
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/ActivityActivity.kt
@@ -0,0 +1,194 @@
+package com.blankj.utilcode.pkg.feature.activity
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.BitmapDrawable
+import android.os.Bundle
+import android.widget.ImageView
+import androidx.core.app.ActivityOptionsCompat
+import com.blankj.base.rv.ItemViewHolder
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemImage
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.feature.CoreUtilActivity
+import com.blankj.utilcode.util.ActivityUtils
+import com.blankj.utilcode.util.AppUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.StringUtils
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about ActivityUtils
+ * ```
+ */
+class ActivityActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ActivityActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_activity
+ }
+
+ override fun bindItems(): List> {
+ val elementItem = ActivityItem()
+ val intent = Intent(this, SubActivityActivity::class.java)
+ val intents = arrayOfNulls(2)
+ intents[0] = intent
+ intents[1] = Intent(this, SubActivityActivity::class.java)
+
+ return CollectionUtils.newArrayList(
+ elementItem,
+ CommonItemTitle("isActivityExists(${SubActivityActivity::class.java.name})", ActivityUtils.isActivityExists(AppUtils.getAppPackageName(), SubActivityActivity::class.java.name).toString()),
+ CommonItemTitle("getLauncherActivity", ActivityUtils.getLauncherActivity(AppUtils.getAppPackageName())),
+ CommonItemTitle("getMainActivities", ActivityUtils.getMainActivities().toString()),
+ CommonItemTitle("getActivityList", CollectionUtils.collect(ActivityUtils.getActivityList()) { input -> input.javaClass.simpleName }.toString()),
+ CommonItemTitle("getTopActivity", ActivityUtils.getTopActivity().toString()),
+ CommonItemTitle("isActivityExistsInStack", ActivityUtils.isActivityExistsInStack(CoreUtilActivity::class.java).toString()),
+ CommonItemImage("getActivityIcon") {
+ it.setImageDrawable(ActivityUtils.getActivityIcon(ActivityActivity::class.java))
+ },
+ CommonItemImage("getActivityLogo") {
+ it.setImageDrawable(ActivityUtils.getActivityLogo(ActivityActivity::class.java))
+ },
+
+ CommonItemClick(R.string.activity_clz, true) {
+ ActivityUtils.startActivity(SubActivityActivity::class.java)
+ },
+ CommonItemClick(R.string.activity_clz_opt, true) {
+ ActivityUtils.startActivity(SubActivityActivity::class.java, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_clz_anim, true) {
+ ActivityUtils.startActivity(SubActivityActivity::class.java, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_act_clz, true) {
+ ActivityUtils.startActivity(this, SubActivityActivity::class.java)
+ },
+ CommonItemClick(R.string.activity_act_clz_shared_element, true) {
+ ActivityUtils.startActivity(this, SubActivityActivity::class.java, elementItem.element)
+ },
+ CommonItemClick(R.string.activity_act_clz_anim, true) {
+ ActivityUtils.startActivity(this, SubActivityActivity::class.java, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_pkg_cls, true) {
+ ActivityUtils.startActivity(this.packageName, SubActivityActivity::class.java.name)
+ },
+ CommonItemClick(R.string.activity_pkg_cls_opt, true) {
+ ActivityUtils.startActivity(this.packageName, SubActivityActivity::class.java.name, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_pkg_cls_anim, true) {
+ ActivityUtils.startActivity(this.packageName, SubActivityActivity::class.java.name, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_act_pkg_cls, true) {
+ ActivityUtils.startActivity(this, this.packageName, SubActivityActivity::class.java.name)
+ },
+ CommonItemClick(R.string.activity_act_pkg_cls_opt, true) {
+ ActivityUtils.startActivity(this, this.packageName, SubActivityActivity::class.java.name, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_act_pkg_cls_shared_element, true) {
+ ActivityUtils.startActivity(this, this.packageName, SubActivityActivity::class.java.name, elementItem.element)
+ },
+ CommonItemClick(R.string.activity_act_pkg_cls_anim, true) {
+ ActivityUtils.startActivity(this, this.packageName, SubActivityActivity::class.java.name, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_intent, true) {
+ ActivityUtils.startActivity(this, intent)
+ },
+ CommonItemClick(R.string.activity_intent_opt, true) {
+ ActivityUtils.startActivity(this, intent, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_intent_shared_element, true) {
+ ActivityUtils.startActivity(this, intent, elementItem.element)
+ },
+ CommonItemClick(R.string.activity_intent_anim, true) {
+ ActivityUtils.startActivity(this, intent, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_intents, true) {
+ ActivityUtils.startActivities(intents)
+ },
+ CommonItemClick(R.string.activity_intents_opt, true) {
+ ActivityUtils.startActivities(intents, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_intents_anim, true) {
+ ActivityUtils.startActivities(intents, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_act_intents, true) {
+ ActivityUtils.startActivities(this, intents, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_act_intents_opt, true) {
+ ActivityUtils.startActivities(this, intents, getOption(elementItem))
+ },
+ CommonItemClick(R.string.activity_act_intents_anim, true) {
+ ActivityUtils.startActivities(this, intents, R.anim.fade_in_1000, R.anim.fade_out_1000)
+ },
+ CommonItemClick(R.string.activity_start_home_activity, true) {
+ ActivityUtils.startHomeActivity()
+ },
+ CommonItemClick(R.string.activity_start_launcher_activity, true) {
+ ActivityUtils.startLauncherActivity()
+ },
+ CommonItemClick(R.string.activity_finish_activity, false) {
+ ActivityUtils.finishActivity(CoreUtilActivity::class.java)
+ },
+ CommonItemClick(R.string.activity_finish_to_activity, true) {
+ ActivityUtils.finishToActivity(CoreUtilActivity::class.java, false, true)
+ },
+ CommonItemClick(R.string.activity_finish_all_activities_except_newest, true) {
+ ActivityUtils.finishAllActivitiesExceptNewest()
+ },
+ CommonItemClick(R.string.activity_finish_all_activities, true) {
+ ActivityUtils.finishAllActivities()
+ }
+ )
+ }
+
+ private fun getOption(activityItem: ActivityItem): Bundle? {
+ when (Random().nextInt(5)) {
+ 0 -> return ActivityOptionsCompat.makeCustomAnimation(this,
+ R.anim.slide_right_in_1000,
+ R.anim.slide_left_out_1000)
+ .toBundle()
+ 1 -> return ActivityOptionsCompat.makeScaleUpAnimation(activityItem.element,
+ activityItem.element.width / 2,
+ activityItem.element.height / 2,
+ 0, 0)
+ .toBundle()
+ 2 -> return ActivityOptionsCompat.makeThumbnailScaleUpAnimation(activityItem.element,
+ (activityItem.element.drawable as BitmapDrawable).bitmap,
+ 0, 0)
+ .toBundle()
+ 3 -> return ActivityOptionsCompat.makeSceneTransitionAnimation(this,
+ activityItem.element,
+ StringUtils.getString(R.string.activity_shared_element))
+ .toBundle()
+ else -> return ActivityOptionsCompat.makeClipRevealAnimation(activityItem.element,
+ activityItem.element.width / 2,
+ activityItem.element.height / 2,
+ 0, 0)
+ .toBundle()
+ }
+ }
+}
+
+class ActivityItem : CommonItem {
+
+ lateinit var element: ImageView;
+
+ constructor() : super(R.layout.activity_item_shared_element_activity)
+
+ override fun bind(holder: ItemViewHolder, position: Int) {
+ super.bind(holder, position)
+ element = holder.findViewById(R.id.activityViewSharedElement)
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
new file mode 100644
index 0000000000..3505709cd2
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/activity/SubActivityActivity.kt
@@ -0,0 +1,47 @@
+package com.blankj.utilcode.pkg.feature.activity
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import androidx.core.app.ActivityCompat
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.ColorUtils
+import kotlinx.android.synthetic.main.activity_sub_activity.*
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about ActivityUtils
+ * ```
+ */
+class SubActivityActivity : CommonActivity() {
+
+ override fun bindLayout(): Int {
+ return R.layout.activity_sub_activity
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ contentView?.setBackgroundColor(ColorUtils.getRandomColor(false))
+ activityViewSharedElement.setOnClickListener {
+ val result = Intent()
+ result.putExtra("data", "data")
+ this@SubActivityActivity.setResult(Activity.RESULT_OK, result)
+ this@SubActivityActivity.finish()
+ }
+ }
+
+ override fun onBackPressed() {
+ super.onBackPressed()
+ ActivityCompat.finishAfterTransition(this)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptCloseActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptCloseActivity.kt
new file mode 100644
index 0000000000..007724289c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptCloseActivity.kt
@@ -0,0 +1,34 @@
+package com.blankj.utilcode.pkg.feature.adaptScreen
+
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.os.Bundle
+import android.view.View
+import android.view.WindowManager
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.AdaptScreenUtils
+
+class AdaptCloseActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, AdaptCloseActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.adaptscreen_close_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
+ }
+
+ override fun getResources(): Resources {
+ return AdaptScreenUtils.closeAdapt(super.getResources())
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptHeightActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptHeightActivity.kt
new file mode 100644
index 0000000000..f00eedc77c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptHeightActivity.kt
@@ -0,0 +1,41 @@
+package com.blankj.utilcode.pkg.feature.adaptScreen
+
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.os.Bundle
+import android.view.View
+import android.view.WindowManager
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.AdaptScreenUtils
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.LogUtils
+
+class AdaptHeightActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, AdaptHeightActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.adaptscreen_height_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ LogUtils.e(BarUtils.getStatusBarHeight())
+ }
+
+ override fun getResources(): Resources {
+ return AdaptScreenUtils.adaptHeight(super.getResources(), 1920)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptScreenActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptScreenActivity.kt
new file mode 100644
index 0000000000..9219c75bb5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptScreenActivity.kt
@@ -0,0 +1,37 @@
+package com.blankj.utilcode.pkg.feature.adaptScreen
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+
+class AdaptScreenActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, AdaptScreenActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_adapt_screen
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.adaptScreen_adapt_width, true) {
+ AdaptWidthActivity.start(this)
+ },
+ CommonItemClick(R.string.adaptScreen_adapt_height, true) {
+ AdaptHeightActivity.start(this)
+ },
+ CommonItemClick(R.string.adaptScreen_adapt_close, true) {
+ AdaptCloseActivity.start(this)
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptWidthActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptWidthActivity.kt
new file mode 100644
index 0000000000..6ccd3f45a0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/adaptScreen/AdaptWidthActivity.kt
@@ -0,0 +1,37 @@
+package com.blankj.utilcode.pkg.feature.adaptScreen
+
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.view.WindowManager
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.AdaptScreenUtils
+import kotlinx.android.synthetic.main.adaptscreen_width_activity.*
+
+class AdaptWidthActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, AdaptWidthActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.adaptscreen_width_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
+ adaptScreenWidthWebView.setBackgroundColor(Color.parseColor("#f0d26d"))
+ }
+
+ override fun getResources(): Resources {
+ return AdaptScreenUtils.adaptWidth(super.getResources(), 1080)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt
new file mode 100644
index 0000000000..8e11495b09
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/ApiActivity.kt
@@ -0,0 +1,45 @@
+package com.blankj.utilcode.pkg.feature.api
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.feature.api.other.export.OtherModuleApi
+import com.blankj.utilcode.util.ApiUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/03/12
+ * desc : demo about ApiUtils
+ * ```
+ */
+class ApiActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ApiActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_api
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.api_invoke_with_params) {
+ ApiUtils.getApi(OtherModuleApi::class.java)?.invokeWithParams(OtherModuleApi.ApiBean("params"))
+ },
+ CommonItemClick(R.string.api_invoke_with_return_value) {
+ ToastUtils.showShort(ApiUtils.getApi(OtherModuleApi::class.java)?.invokeWithReturnValue()?.name)
+ }
+ );
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/export/OtherModuleApi.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/export/OtherModuleApi.java
new file mode 100644
index 0000000000..5879724b01
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/export/OtherModuleApi.java
@@ -0,0 +1,27 @@
+package com.blankj.utilcode.pkg.feature.api.other.export;
+
+import com.blankj.utilcode.util.ApiUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/10
+ * desc : demo about ApiUtils
+ *
+ */
+public abstract class OtherModuleApi extends ApiUtils.BaseApi {
+
+ public abstract void invokeWithParams(ApiBean bean);
+
+ public abstract ApiBean invokeWithReturnValue();
+
+ public static class ApiBean {
+
+ public String name;
+
+ public ApiBean(String name) {
+ this.name = name;
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/pkg/OtherPkgApiImpl.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/pkg/OtherPkgApiImpl.java
new file mode 100644
index 0000000000..b3efb7af7a
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/api/other/pkg/OtherPkgApiImpl.java
@@ -0,0 +1,28 @@
+package com.blankj.utilcode.pkg.feature.api.other.pkg;
+
+import com.blankj.utilcode.pkg.feature.api.other.export.OtherModuleApi;
+import com.blankj.utilcode.util.ApiUtils;
+import com.blankj.utilcode.util.ToastUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/10
+ * desc : demo about ApiUtils
+ *
+ */
+@ApiUtils.Api
+public class OtherPkgApiImpl extends OtherModuleApi {
+
+ @Override
+ public void invokeWithParams(ApiBean bean) {
+ ToastUtils.showShort(bean.name);
+ }
+
+ @Override
+ public ApiBean invokeWithReturnValue() {
+ String value = "value";
+ return new ApiBean(value);
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
new file mode 100644
index 0000000000..21eb351146
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/app/AppActivity.kt
@@ -0,0 +1,162 @@
+package com.blankj.utilcode.pkg.feature.app
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.*
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.Config
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about AppUtils
+ * ```
+ */
+class AppActivity : CommonActivity(), Utils.OnAppStatusChangedListener {
+
+ var isRegisterAppStatusChangedListener: Boolean = false
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, AppActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.STORAGE)
+ }
+ }
+
+ private val listener = object : OnReleasedListener {
+ override fun onReleased() {
+ return AppUtils.installApp(Config.TEST_APK_PATH)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_app
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ LogUtils.e(requestCode, resultCode)
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemSwitch(
+ "registerAppStatusChangedListener",
+ { isRegisterAppStatusChangedListener },
+ {
+ isRegisterAppStatusChangedListener = it
+ if (it) {
+ AppUtils.registerAppStatusChangedListener(this)
+ } else {
+ AppUtils.unregisterAppStatusChangedListener(this)
+ }
+ }),
+ CommonItemTitle("isAppRoot", AppUtils.isAppRoot().toString()),
+ CommonItemTitle("isAppDebug", AppUtils.isAppDebug().toString()),
+ CommonItemTitle("isAppSystem", AppUtils.isAppSystem().toString()),
+ CommonItemTitle(
+ "isAppForeground",
+ AppUtils.isAppForeground(AppUtils.getAppPackageName()).toString()
+ ),
+ CommonItemTitle(
+ "isAppRunning",
+ AppUtils.isAppRunning(AppUtils.getAppPackageName()).toString()
+ ),
+ CommonItemImage("getAppIcon") {
+ it.setImageDrawable(AppUtils.getAppIcon())
+ },
+ CommonItemTitle("getAppPackageName", AppUtils.getAppPackageName()),
+ CommonItemTitle("getAppName", AppUtils.getAppName()),
+ CommonItemTitle("getAppPath", AppUtils.getAppPath()),
+ CommonItemTitle("getAppVersionName", AppUtils.getAppVersionName()),
+ CommonItemTitle("getAppVersionCode", AppUtils.getAppVersionCode().toString()),
+ CommonItemTitle("getAppMinSdkVersion", AppUtils.getAppMinSdkVersion().toString()),
+ CommonItemTitle("getAppTargetSdkVersion", AppUtils.getAppTargetSdkVersion().toString()),
+ CommonItemTitle("getAppSignaturesSHA1", AppUtils.getAppSignaturesSHA1().toString()),
+ CommonItemTitle("getAppSignaturesSHA256", AppUtils.getAppSignaturesSHA256().toString()),
+ CommonItemTitle("getAppSignaturesMD5", AppUtils.getAppSignaturesMD5().toString()),
+ CommonItemTitle("getAppUid", AppUtils.getAppUid().toString()),
+ CommonItemTitle("getApkInfo", AppUtils.getApkInfo(AppUtils.getAppPath()).toString()),
+
+ CommonItemClick(R.string.app_install) {
+ if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+ ToastUtils.showShort(R.string.app_install_tips)
+ } else {
+ if (!FileUtils.isFileExists(Config.TEST_APK_PATH)) {
+ ReleaseInstallApkTask(listener).execute()
+ } else {
+ listener.onReleased()
+ }
+ }
+ },
+ CommonItemClick(R.string.app_uninstall) {
+ if (AppUtils.isAppInstalled(Config.TEST_PKG)) {
+ AppUtils.uninstallApp(Config.TEST_PKG)
+ } else {
+ ToastUtils.showShort(R.string.app_uninstall_tips)
+ }
+ },
+ CommonItemClick(R.string.app_launch) {
+ AppUtils.launchApp(this.packageName)
+ },
+ CommonItemClick(R.string.app_relaunch) {
+ AppUtils.relaunchApp()
+ },
+ CommonItemClick(R.string.app_launch_details_settings, true) {
+ AppUtils.launchAppDetailsSettings()
+ },
+ CommonItemClick(R.string.app_exit) {
+ AppUtils.exitApp()
+ }
+ )
+ }
+
+ override fun onForeground(activity: Activity) {
+ ToastUtils.showShort("onForeground\n${activity.javaClass.simpleName}")
+ }
+
+ override fun onBackground(activity: Activity) {
+ ToastUtils.showShort("onBackground\n${activity.javaClass.simpleName}")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (isRegisterAppStatusChangedListener) {
+ AppUtils.unregisterAppStatusChangedListener(this)
+ }
+ }
+}
+
+class ReleaseInstallApkTask(private val mListener: OnReleasedListener) :
+ ThreadUtils.SimpleTask() {
+
+ override fun doInBackground() {
+ ResourceUtils.copyFileFromAssets("test_install", Config.TEST_APK_PATH)
+ }
+
+ override fun onSuccess(result: Unit) {
+ mListener.onReleased()
+ }
+
+ fun execute() {
+ ThreadUtils.executeByIo(this)
+ }
+}
+
+interface OnReleasedListener {
+ fun onReleased()
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarActivity.kt
new file mode 100644
index 0000000000..26801106a0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/BarActivity.kt
@@ -0,0 +1,71 @@
+package com.blankj.utilcode.pkg.feature.bar
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.feature.bar.nav.BarNavActivity
+import com.blankj.utilcode.pkg.feature.bar.notification.BarNotificationActivity
+import com.blankj.utilcode.pkg.feature.bar.status.*
+import com.blankj.utilcode.pkg.feature.bar.status.fragment.BarStatusFragmentActivity
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bar
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle(R.string.bar_about_status_bar, true),
+ CommonItemClick(R.string.bar_status_about, true) {
+ BarStatusActivity.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_color, true) {
+ BarStatusActivityColor.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_alpha, true) {
+ BarStatusActivityAlpha.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_image_view, true) {
+ BarStatusActivityImageView.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_custom, true) {
+ BarStatusActivityCustom.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_fragment, true) {
+ BarStatusFragmentActivity.start(this)
+ },
+ CommonItemClick(R.string.bar_status_set_drawer, true) {
+ BarStatusActivityDrawer.start(this)
+ },
+ CommonItemTitle(R.string.bar_about_notification_bar, true),
+ CommonItemClick(R.string.bar_notification_about, true) {
+ BarNotificationActivity.start(this)
+ },
+ CommonItemTitle(R.string.bar_about_nav_bar, true),
+ CommonItemClick(R.string.bar_nav_about, true) {
+ BarNavActivity.start(this)
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
new file mode 100644
index 0000000000..48a738ecd7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/nav/BarNavActivity.kt
@@ -0,0 +1,88 @@
+package com.blankj.utilcode.pkg.feature.bar.nav
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarNavActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarNavActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bar
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList>().apply {
+ add(CommonItemTitle("navHeight", BarUtils.getNavBarHeight().toString()))
+ add(CommonItemTitle("isSupportNavBar", BarUtils.isSupportNavBar().toString()))
+ if (BarUtils.isSupportNavBar()) {
+ add(CommonItemSwitch(
+ R.string.bar_nav_visibility,
+ { BarUtils.isNavBarVisible(this@BarNavActivity) },
+ { BarUtils.setNavBarVisibility(this@BarNavActivity, it) }
+ ))
+
+ add(CommonItemSwitch(
+ R.string.bar_nav_light_mode,
+ { BarUtils.isNavBarLightMode(this@BarNavActivity) },
+ { BarUtils.setNavBarLightMode(this@BarNavActivity, it) }
+ ))
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ add(
+ CommonItemClick(
+ "getNavBarColor: ${
+ ColorUtils.int2ArgbString(
+ BarUtils.getNavBarColor(
+ this@BarNavActivity
+ )
+ )
+ }"
+ ).setOnItemClickListener() { _, item, _ ->
+ BarUtils.setNavBarColor(
+ this@BarNavActivity,
+ ColorUtils.getRandomColor()
+ )
+ itemsView.updateItems(bindItems())
+ item.title = "getNavBarColor: ${
+ ColorUtils.int2ArgbString(
+ BarUtils.getNavBarColor(this@BarNavActivity)
+ )
+ }"
+ })
+ }
+ add(CommonItemClick("transparentNavBar").setOnItemClickListener() { _, item, _ ->
+ BarUtils.transparentNavBar(this@BarNavActivity)
+ })
+ }
+ }
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ itemsView.updateItems(bindItems())
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/notification/BarNotificationActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/notification/BarNotificationActivity.kt
new file mode 100644
index 0000000000..5504912ee6
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/notification/BarNotificationActivity.kt
@@ -0,0 +1,49 @@
+package com.blankj.utilcode.pkg.feature.bar.notification
+
+import android.content.Context
+import android.content.Intent
+import android.os.Handler
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarNotificationActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarNotificationActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private val mHandler = Handler()
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bar
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.bar_notification_show) {
+ BarUtils.setNotificationBarVisibility(true)
+ mHandler.postDelayed({ BarUtils.setNotificationBarVisibility(false) }, 2000)
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mHandler.removeCallbacksAndMessages(null)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt
new file mode 100644
index 0000000000..da20870e79
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivity.kt
@@ -0,0 +1,55 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.Utils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bar
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getStatusBarHeight", BarUtils.getStatusBarHeight().toString()),
+ CommonItemSwitch(
+ R.string.bar_status_visibility,
+ { BarUtils.isStatusBarVisible(this) },
+ { BarUtils.setStatusBarVisibility(this, it) }
+ ),
+ CommonItemSwitch(
+ R.string.bar_status_light_mode,
+ { BarUtils.isStatusBarLightMode(this) },
+ { BarUtils.setStatusBarLightMode(this, it) }
+ )
+ )
+ }
+
+ override fun onResume() {
+ super.onResume()
+ itemsView.updateItems(bindItems())
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt
new file mode 100644
index 0000000000..fa886e5be5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityAlpha.kt
@@ -0,0 +1,67 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivityAlpha : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivityAlpha::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private var mAlpha: Int = 112
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_alpha_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ updateStatusBar()
+ }
+
+ private fun getItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return mAlpha
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ mAlpha = progress
+ updateStatusBar()
+ }
+ }).apply {
+ backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 0.5f)
+ }
+ )
+ }
+
+ private fun updateStatusBar() {
+ BarUtils.setStatusBarColor(this, Color.argb(mAlpha, 0, 0, 0))
+ BarUtils.addMarginTopEqualStatusBarHeight(findViewById(R.id.commonItemRv))// 其实这个只需要调用一次即可
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityColor.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityColor.kt
new file mode 100644
index 0000000000..74b6368e1b
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityColor.kt
@@ -0,0 +1,53 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivityColor : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivityColor::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private var mColor: Int = ColorUtils.getColor(R.color.colorPrimary)
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemClick(R.string.bar_status_random_color, ColorUtils.int2ArgbString(mColor)).setOnClickUpdateContentListener {
+ mColor = ColorUtils.getRandomColor()
+ updateStatusBar()
+ return@setOnClickUpdateContentListener ColorUtils.int2ArgbString(mColor)
+ }
+ )
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ updateStatusBar()
+ }
+
+ private fun updateStatusBar() {
+ BarUtils.setStatusBarColor(this, mColor)
+ BarUtils.addMarginTopEqualStatusBarHeight(findViewById(R.id.commonItemRv))// 其实这个只需要调用一次即可
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityCustom.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityCustom.kt
new file mode 100644
index 0000000000..0cea718cf9
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityCustom.kt
@@ -0,0 +1,34 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/01/14
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivityCustom : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivityCustom::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ BarUtils.setStatusBarColor(this, Color.TRANSPARENT).setBackgroundResource(R.drawable.bar_status_custom)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt
new file mode 100644
index 0000000000..d8e092d466
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityDrawer.kt
@@ -0,0 +1,116 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+import kotlinx.android.synthetic.main.bar_status_drawer_activity.*
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivityDrawer : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivityDrawer::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private var mColor: Int = ColorUtils.getColor(R.color.colorPrimary)
+ private var mAlpha: Int = 112
+
+ private var mAlphaStatus: Boolean = false
+ private var mFrontStatus: Boolean = false
+
+ override fun isSwipeBack(): Boolean {
+ return false
+ }
+
+ override fun bindDrawer(): Boolean {
+ return true
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_drawer_activity
+ }
+
+ private fun getItems(): MutableList> {
+ val randomColorItem = CommonItemClick(R.string.bar_status_random_color, ColorUtils.int2ArgbString(mColor)).setOnClickUpdateContentListener {
+ mColor = ColorUtils.getRandomColor()
+ updateStatusBar()
+ return@setOnClickUpdateContentListener ColorUtils.int2ArgbString(mColor)
+ }
+
+ val alphaItem: CommonItem<*> = CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return mAlpha
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ mAlpha = progress
+ updateStatusBar()
+ }
+ })
+
+ return CollectionUtils.newArrayList(
+ CommonItemSwitch(
+ R.string.bar_status_title_alpha,
+ {
+ updateStatusBar()
+ mAlphaStatus
+ },
+ {
+ mAlphaStatus = it
+ if (mAlphaStatus) {
+ barStatusDrawerRootLl.setBackgroundResource(R.drawable.image_lena)
+ commonItemAdapter.replaceItem(2, alphaItem, true)
+ } else {
+ barStatusDrawerRootLl.setBackgroundColor(Color.TRANSPARENT)
+ commonItemAdapter.replaceItem(2, randomColorItem, true)
+ }
+ }
+ ),
+ CommonItemSwitch(
+ R.string.bar_status_is_front,
+ { mFrontStatus },
+ {
+ mFrontStatus = it
+ updateStatusBar()
+ }
+ ),
+ randomColorItem
+ )
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ }
+
+ private fun updateStatusBar() {
+ if (mAlphaStatus) {
+ BarUtils.setStatusBarColor4Drawer(drawerView.mBaseDrawerRootLayout, barStatusDrawerFakeStatusBar, Color.argb(mAlpha, 0, 0, 0), mFrontStatus)
+ } else {
+ BarUtils.setStatusBarColor4Drawer(drawerView.mBaseDrawerRootLayout, barStatusDrawerFakeStatusBar, mColor, mFrontStatus)
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt
new file mode 100644
index 0000000000..86542caec5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/BarStatusActivityImageView.kt
@@ -0,0 +1,63 @@
+package com.blankj.utilcode.pkg.feature.bar.status
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusActivityImageView : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusActivityImageView::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private var mAlpha: Int = 112
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_image_view_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ updateStatusBar()
+ }
+
+ private fun getItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return mAlpha
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ mAlpha = progress
+ updateStatusBar()
+ }
+ })
+ )
+ }
+
+ private fun updateStatusBar() {
+ BarUtils.setStatusBarColor(this, Color.argb(mAlpha, 0, 0, 0), true)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentActivity.kt
new file mode 100644
index 0000000000..6df145b5be
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentActivity.kt
@@ -0,0 +1,101 @@
+package com.blankj.utilcode.pkg.feature.bar.status.fragment
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentPagerAdapter
+import androidx.viewpager.widget.ViewPager
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import kotlinx.android.synthetic.main.bar_status_fragment_activity.*
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/05/27
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusFragmentActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BarStatusFragmentActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private val itemIds = intArrayOf(
+ R.id.barStatusFragmentNavigationColor,
+ R.id.barStatusFragmentNavigationAlpha,
+ R.id.barStatusFragmentNavigationImageView,
+ R.id.barStatusFragmentNavigationCustom
+ )
+
+ private val mFragmentList = ArrayList()
+
+ private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener l@{ item ->
+ when (item.itemId) {
+ R.id.barStatusFragmentNavigationColor -> {
+ barStatusFragmentVp.currentItem = 0
+ return@l true
+ }
+ R.id.barStatusFragmentNavigationAlpha -> {
+ barStatusFragmentVp.currentItem = 1
+ return@l true
+ }
+ R.id.barStatusFragmentNavigationImageView -> {
+ barStatusFragmentVp.currentItem = 2
+ return@l true
+ }
+ R.id.barStatusFragmentNavigationCustom -> {
+ barStatusFragmentVp.currentItem = 3
+ return@l true
+ }
+ else -> false
+ }
+ }
+
+ override fun isSwipeBack(): Boolean {
+ return false
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_fragment_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ mFragmentList.add(BarStatusFragmentColor.newInstance())
+ mFragmentList.add(BarStatusFragmentAlpha.newInstance())
+ mFragmentList.add(BarStatusFragmentImageView.newInstance())
+ mFragmentList.add(BarStatusFragmentCustom.newInstance())
+
+ barStatusFragmentVp.offscreenPageLimit = mFragmentList.size - 1
+ barStatusFragmentVp.adapter = object : FragmentPagerAdapter(supportFragmentManager) {
+ override fun getItem(position: Int): Fragment {
+ return mFragmentList[position]
+ }
+
+ override fun getCount(): Int {
+ return mFragmentList.size
+ }
+ }
+ barStatusFragmentVp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
+ override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
+
+ override fun onPageSelected(position: Int) {
+ barStatusFragmentNav.selectedItemId = itemIds[position]
+ }
+
+ override fun onPageScrollStateChanged(state: Int) {}
+ })
+
+ barStatusFragmentNav.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt
new file mode 100644
index 0000000000..ab368c0295
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentAlpha.kt
@@ -0,0 +1,68 @@
+package com.blankj.utilcode.pkg.feature.bar.status.fragment
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+import kotlinx.android.synthetic.main.bar_status_alpha_fragment.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/07/01
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusFragmentAlpha : CommonFragment() {
+
+ companion object {
+ fun newInstance(): BarStatusFragmentAlpha {
+ return BarStatusFragmentAlpha()
+ }
+ }
+
+ override fun isLazy(): Boolean {
+ return true
+ }
+
+ private var mAlpha: Int = 112
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_alpha_fragment
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ updateFakeStatusBar()
+ }
+
+ private fun getItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return mAlpha
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ mAlpha = progress
+ updateFakeStatusBar()
+ }
+ }).apply {
+ backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 0.5f)
+ }
+ )
+ }
+
+ fun updateFakeStatusBar() {
+ BarUtils.setStatusBarColor(barStatusAlphaFragmentFakeStatusBar, Color.argb(mAlpha, 0, 0, 0))
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentColor.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentColor.kt
new file mode 100644
index 0000000000..029523e59d
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentColor.kt
@@ -0,0 +1,59 @@
+package com.blankj.utilcode.pkg.feature.bar.status.fragment
+
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+import kotlinx.android.synthetic.main.bar_status_color_fragment.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/07/01
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusFragmentColor : CommonFragment() {
+
+ companion object {
+ fun newInstance(): BarStatusFragmentColor {
+ return BarStatusFragmentColor()
+ }
+ }
+
+ private var mColor: Int = ColorUtils.getColor(R.color.colorPrimary)
+
+ override fun isLazy(): Boolean {
+ return true
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_color_fragment
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ updateFakeStatusBar()
+ }
+
+ private fun getItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemClick(R.string.bar_status_random_color, ColorUtils.int2ArgbString(mColor)).setOnClickUpdateContentListener {
+ mColor = ColorUtils.getRandomColor()
+ updateFakeStatusBar()
+ return@setOnClickUpdateContentListener ColorUtils.int2ArgbString(mColor)
+ }
+ )
+ }
+
+ private fun updateFakeStatusBar() {
+ BarUtils.setStatusBarColor(barStatusColorFragmentFakeStatusBar, mColor)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentCustom.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentCustom.kt
new file mode 100644
index 0000000000..e8dbcd927c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentCustom.kt
@@ -0,0 +1,38 @@
+package com.blankj.utilcode.pkg.feature.bar.status.fragment
+
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import kotlinx.android.synthetic.main.bar_status_custom_fragment.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/07/01
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusFragmentCustom : CommonFragment() {
+
+ companion object {
+ fun newInstance(): BarStatusFragmentCustom {
+ return BarStatusFragmentCustom()
+ }
+ }
+
+ override fun isLazy(): Boolean {
+ return true
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_custom_fragment
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ BarUtils.setStatusBarCustom(barStatusCustomFragmentFakeStatusBar)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt
new file mode 100644
index 0000000000..686e50995c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bar/status/fragment/BarStatusFragmentImageView.kt
@@ -0,0 +1,65 @@
+package com.blankj.utilcode.pkg.feature.bar.status.fragment
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.CollectionUtils
+import kotlinx.android.synthetic.main.bar_status_image_view_fragment.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/07/01
+ * desc : demo about BarUtils
+ * ```
+ */
+class BarStatusFragmentImageView : CommonFragment() {
+
+ companion object {
+ fun newInstance(): BarStatusFragmentImageView {
+ return BarStatusFragmentImageView()
+ }
+ }
+
+ private var mAlpha: Int = 112
+
+ override fun isLazy(): Boolean {
+ return true
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.bar_status_image_view_fragment
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ updateFakeStatusBar()
+ }
+
+ private fun getItems(): List> {
+ return CollectionUtils.newArrayList>(
+ CommonItemSeekBar("Status Bar Alpha", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return mAlpha
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ mAlpha = progress
+ updateFakeStatusBar()
+ }
+ })
+ )
+ }
+
+ fun updateFakeStatusBar() {
+ BarUtils.setStatusBarColor(barStatusImageViewFragmentFakeStatusBar, Color.argb(mAlpha, 0, 0, 0))
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt
new file mode 100644
index 0000000000..435a1ecbed
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/brightness/BrightnessActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.brightness
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.widget.SeekBar
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/02/08
+ * desc : demo about BrightnessUtils
+ * ```
+ */
+class BrightnessActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ PermissionUtils.requestWriteSettings(object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, BrightnessActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ ToastUtils.showLong("No permission of write settings.")
+ }
+ })
+ } else {
+ val starter = Intent(context, BrightnessActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+ }
+
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_brightness
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemSeekBar("getBrightness", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return BrightnessUtils.getBrightness()
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ BrightnessUtils.setBrightness(progress)
+ }
+ }),
+ CommonItemSeekBar("getWindowBrightness", 255, object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return BrightnessUtils.getWindowBrightness(window)
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ BrightnessUtils.setWindowBrightness(window, progress)
+ }
+ }),
+ CommonItemSwitch(
+ R.string.brightness_auto_brightness,
+ { BrightnessUtils.isAutoBrightnessEnabled() },
+ { BrightnessUtils.setAutoBrightnessEnabled(it) }
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusActivity.kt
new file mode 100644
index 0000000000..9bd7c870d0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusActivity.kt
@@ -0,0 +1,119 @@
+package com.blankj.utilcode.pkg.feature.bus
+
+import android.content.Context
+import android.content.Intent
+import androidx.annotation.Keep
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BusUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ThreadUtils
+import kotlin.random.Random
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/03/12
+ * desc : demo about BusUtils
+ * ```
+ */
+class BusActivity : CommonActivity() {
+
+ private val titleItem: CommonItemTitle = CommonItemTitle("", true);
+
+ @BusUtils.Bus(tag = TAG_BASIC_TYPE)
+ fun test(param: Int) {
+ titleItem.title = param.toString()
+ }
+
+ @BusUtils.Bus(tag = TAG_BUS, priority = 5)
+ fun test(param: String) {
+ titleItem.title = param
+ }
+
+ @BusUtils.Bus(tag = TAG_BUS, priority = 1)
+ fun testSameTag(param: String) {
+ if (titleItem.title.toString() == TAG_BUS) {
+ titleItem.title = "${titleItem.title} * 2"
+ }
+ }
+
+ @BusUtils.Bus(tag = TAG_STICKY_BUS, sticky = true)
+ fun testSticky(callback: Callback) {
+ titleItem.title = callback.call()
+ }
+
+ @BusUtils.Bus(tag = TAG_IO, threadMode = BusUtils.ThreadMode.IO)
+ fun testIo() {
+ val currentThread = Thread.currentThread().toString()
+ ThreadUtils.runOnUiThread(Runnable {
+ titleItem.title = currentThread
+ })
+ }
+
+ companion object {
+ const val TAG_BASIC_TYPE = "tag_basic_type"
+ const val TAG_BUS = "tag_bus"
+ const val TAG_STICKY_BUS = "tag_sticky_bus"
+ const val TAG_IO = "tag_io"
+
+ fun start(context: Context) {
+ val starter = Intent(context, BusActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bus
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ titleItem,
+ CommonItemClick(R.string.bus_register) {
+ BusUtils.register(this)
+ },
+ CommonItemClick(R.string.bus_unregister) {
+ BusUtils.unregister(this)
+ },
+ CommonItemClick(R.string.bus_post) {
+ BusUtils.post(TAG_BUS, TAG_BUS)
+ },
+ CommonItemClick(R.string.bus_post_basic_type) {
+ BusUtils.post(TAG_BASIC_TYPE, Random(System.currentTimeMillis()).nextInt())
+ },
+ CommonItemClick(R.string.bus_post_sticky) {
+ BusUtils.postSticky(TAG_STICKY_BUS, object : Callback {
+ override fun call(): String {
+ return TAG_STICKY_BUS
+ }
+ })
+ },
+ CommonItemClick(R.string.bus_post_to_io_thread) {
+ BusUtils.post(TAG_IO)
+ },
+ CommonItemClick(R.string.bus_remove_sticky) {
+ BusUtils.removeSticky(TAG_STICKY_BUS)
+ },
+ CommonItemClick(R.string.bus_start_compare, true) {
+ BusCompareActivity.start(this)
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ BusUtils.removeSticky(TAG_STICKY_BUS)
+ BusUtils.unregister(this)
+ }
+}
+
+@Keep
+interface Callback {
+ fun call(): String
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusCompareActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusCompareActivity.kt
new file mode 100644
index 0000000000..3064666c41
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/bus/BusCompareActivity.kt
@@ -0,0 +1,281 @@
+package com.blankj.utilcode.pkg.feature.bus
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BusUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ThreadUtils
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import java.util.*
+import java.util.concurrent.CopyOnWriteArrayList
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/07/14
+ * desc : demo about BusUtils
+ * ```
+ */
+class BusCompareActivity : CommonActivity() {
+
+ private val titleItem: CommonItemTitle = CommonItemTitle("", true)
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, BusCompareActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_bus
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ titleItem,
+ CommonItemClick(R.string.bus_compare_register_10000_times) {
+ compareRegister10000Times()
+ },
+ CommonItemClick(R.string.bus_compare_post_to_1_subscriber_1000000_times) {
+ comparePostTo1Subscriber1000000Times()
+ },
+ CommonItemClick(R.string.bus_compare_post_to_100_subscriber_100000_times) {
+ comparePostTo100Subscribers100000Times()
+ },
+ CommonItemClick(R.string.bus_compare_unregister_10000_times) {
+ compareUnregister10000Times()
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ ThreadUtils.cancel(ThreadUtils.getCpuPool())
+ }
+
+ /**
+ * 注册 10000 个订阅者,共执行 10 次取平均值
+ */
+ private fun compareRegister10000Times() {
+ val eventBusTests = CopyOnWriteArrayList()
+ val busUtilsTests = CopyOnWriteArrayList()
+
+ compareWithEventBus("Register 10000 times.", 10, 10000, object : CompareCallback {
+ override fun runEventBus() {
+ val test = BusEvent()
+ EventBus.getDefault().register(test)
+ eventBusTests.add(test)
+ }
+
+ override fun runBusUtils() {
+ val test = BusEvent()
+ BusUtils.register(test)
+ busUtilsTests.add(test)
+ }
+
+ override fun restState() {
+ for (test in eventBusTests) {
+ EventBus.getDefault().unregister(test)
+ }
+ eventBusTests.clear()
+
+ for (test in busUtilsTests) {
+ BusUtils.unregister(test)
+ }
+ busUtilsTests.clear()
+ }
+ }, object : OnFinishCallback {
+ override fun onFinish() {
+ for (test in eventBusTests) {
+ EventBus.getDefault().unregister(test)
+ }
+ eventBusTests.clear()
+
+ for (test in busUtilsTests) {
+ BusUtils.unregister(test)
+ }
+ busUtilsTests.clear()
+ }
+ })
+ }
+
+ /**
+ * 向 1 个订阅者发送 * 1000000 次,共执行 10 次取平均值
+ */
+ private fun comparePostTo1Subscriber1000000Times() {
+ comparePostTemplate("Post to 1 subscriber 1000000 times.", 1, 1000000)
+ }
+
+ /**
+ * 向 100 个订阅者发送 * 100000 次,共执行 10 次取平均值
+ */
+ private fun comparePostTo100Subscribers100000Times() {
+ comparePostTemplate("Post to 100 subscribers 100000 times.", 100, 100000)
+ }
+
+ private fun comparePostTemplate(name: String, subscribeNum: Int, postTimes: Int) {
+ val tests = java.util.ArrayList()
+ for (i in 0 until subscribeNum) {
+ val test = BusEvent()
+ EventBus.getDefault().register(test)
+ BusUtils.register(test)
+ tests.add(test)
+ }
+
+ compareWithEventBus(name, 10, postTimes, object : CompareCallback {
+ override fun runEventBus() {
+ EventBus.getDefault().post("EventBus")
+ }
+
+ override fun runBusUtils() {
+ BusUtils.post("busUtilsFun", "BusUtils")
+ }
+
+ override fun restState() {
+
+ }
+ }, object : OnFinishCallback {
+ override fun onFinish() {
+ for (test in tests) {
+ EventBus.getDefault().unregister(test)
+ BusUtils.unregister(test)
+ }
+ }
+ })
+ }
+
+ /**
+ * 注销 10000 个订阅者,共执行 10 次取平均值
+ */
+ private fun compareUnregister10000Times() {
+ showLoading()
+ ThreadUtils.executeBySingle(object : ThreadUtils.SimpleTask>() {
+ override fun doInBackground(): List {
+ val tests = ArrayList()
+ for (i in 0..9999) {
+ val test = BusEvent()
+ EventBus.getDefault().register(test)
+ BusUtils.register(test)
+ tests.add(test)
+ }
+ return tests
+ }
+
+ override fun onSuccess(tests: List) {
+ compareWithEventBus("Unregister 10000 times.", 10, 1, object : CompareCallback {
+ override fun runEventBus() {
+ for (test in tests) {
+ EventBus.getDefault().unregister(test)
+ }
+ }
+
+ override fun runBusUtils() {
+ for (test in tests) {
+ BusUtils.unregister(test)
+ }
+ }
+
+ override fun restState() {
+ for (test in tests) {
+ EventBus.getDefault().register(test)
+ BusUtils.register(test)
+ }
+ }
+ }, object : OnFinishCallback {
+ override fun onFinish() {
+ for (test in tests) {
+ EventBus.getDefault().unregister(test)
+ BusUtils.unregister(test)
+ }
+ }
+ })
+ }
+ })
+ }
+
+ /**
+ * @param name 传入的测试函数名
+ * @param sampleSize 样本数
+ * @param times 每次执行的次数
+ * @param callback 比较的回调函数
+ * @param onFinishCallback 执行结束的回调
+ */
+ private fun compareWithEventBus(name: String, sampleSize: Int, times: Int,
+ callback: CompareCallback, onFinishCallback: OnFinishCallback) {
+ showLoading()
+ ThreadUtils.executeByCpu(object : ThreadUtils.Task() {
+ override fun doInBackground(): String {
+ val dur = Array(2) { LongArray(sampleSize) }
+ for (i in 0 until sampleSize) {
+ var cur = System.currentTimeMillis()
+ for (j in 0 until times) {
+ callback.runEventBus()
+ }
+ dur[0][i] = System.currentTimeMillis() - cur
+ cur = System.currentTimeMillis()
+ for (j in 0 until times) {
+ callback.runBusUtils()
+ }
+ dur[1][i] = System.currentTimeMillis() - cur
+ callback.restState()
+ }
+ var eventBusAverageTime: Long = 0
+ var busUtilsAverageTime: Long = 0
+ for (i in 0 until sampleSize) {
+ eventBusAverageTime += dur[0][i]
+ busUtilsAverageTime += dur[1][i]
+ }
+ return name +
+ "\nEventBusCostTime: " + eventBusAverageTime / sampleSize +
+ "\nBusUtilsCostTime: " + busUtilsAverageTime / sampleSize;
+ }
+
+ override fun onSuccess(result: String?) {
+ onFinishCallback.onFinish()
+ dismissLoading()
+ titleItem?.title = result
+ }
+
+ override fun onCancel() {
+ onFinishCallback.onFinish()
+ dismissLoading()
+ }
+
+ override fun onFail(t: Throwable?) {
+ onFinishCallback.onFinish()
+ dismissLoading()
+ }
+ })
+ }
+}
+
+interface CompareCallback {
+ fun runEventBus()
+
+ fun runBusUtils()
+
+ fun restState()
+}
+
+interface OnFinishCallback {
+ fun onFinish()
+}
+
+class BusEvent {
+ @Subscribe
+ fun eventBusFun(param: String) {
+ }
+
+ @BusUtils.Bus(tag = "busUtilsFun")
+ fun busUtilsFun(param: String) {
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt
new file mode 100644
index 0000000000..f0b8620eca
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clean/CleanActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.clean
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CleanUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.SDCardUtils
+import com.blankj.utilcode.util.SnackbarUtils
+import java.io.File
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : demo about CleanUtils
+ * ```
+ */
+class CleanActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, CleanActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_clean
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList>().apply {
+ add(CommonItemClick(R.string.clean_internal_cache) {
+ showSnackbar(CleanUtils.cleanInternalCache(), cacheDir.path)
+ })
+ add(CommonItemClick(R.string.clean_internal_files) {
+ showSnackbar(CleanUtils.cleanInternalFiles(), filesDir.path)
+ })
+ add(CommonItemClick(R.string.clean_internal_databases) {
+ showSnackbar(CleanUtils.cleanInternalDbs(), filesDir.parent + File.separator + "databases")
+ })
+ add(CommonItemClick(R.string.clean_internal_sp) {
+ showSnackbar(CleanUtils.cleanInternalSp(), filesDir.parent + File.separator + "shared_prefs")
+ })
+ if (SDCardUtils.isSDCardEnableByEnvironment()) {
+ add(CommonItemClick(R.string.clean_external_cache) {
+ showSnackbar(CleanUtils.cleanExternalCache(), externalCacheDir?.absolutePath)
+ })
+ }
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ add(CommonItemClick(R.string.clean_app_user_data) {
+ CleanUtils.cleanAppUserData()
+ })
+ }
+ }
+ }
+
+ private fun showSnackbar(isSuccess: Boolean, path: String?) {
+ SnackbarUtils.with(mContentView)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .apply {
+ if (isSuccess) {
+ setMessage("clean \"$path\" dir successful.")
+ showSuccess()
+ } else {
+ setMessage("clean \"$path\" dir failed.")
+ showError()
+ }
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/click/ClickActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/click/ClickActivity.kt
new file mode 100644
index 0000000000..7a6a112c15
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/click/ClickActivity.kt
@@ -0,0 +1,115 @@
+package com.blankj.utilcode.pkg.feature.click
+
+import android.content.Context
+import android.content.Intent
+import android.view.View
+import android.widget.TextView
+import androidx.annotation.StringRes
+import com.blankj.base.rv.ItemViewHolder
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : demo about ClickUtils
+ * ```
+ */
+class ClickActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ClickActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_click
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ ClickItem(R.string.click_view_scale_default, Utils.Consumer {
+ ClickUtils.applyPressedViewScale(it)
+ }),
+ ClickItem(R.string.click_view_scale_half, Utils.Consumer {
+ ClickUtils.applyPressedViewScale(it, -0.5f)
+ }),
+ ClickItem(R.string.click_view_alpha_default, Utils.Consumer {
+ ClickUtils.applyPressedViewAlpha(it)
+ }),
+ ClickItem(R.string.click_bg_alpha_default, Utils.Consumer {
+ ClickUtils.applyPressedBgAlpha(it, 0.6f)
+ }),
+ ClickItem(R.string.click_bg_dark_default, Utils.Consumer {
+ ClickUtils.applyPressedBgDark(it)
+ }),
+ ClickItem(R.string.click_single_debouncing, Utils.Consumer {
+ ClickUtils.applyPressedBgDark(it)
+ ClickUtils.applySingleDebouncing(it, 5000) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(StringUtils.getString(R.string.click_single_tip))
+ .setBgColor(ColorUtils.getRandomColor(false))
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .show()
+ }
+ }),
+ ClickItem(R.string.click_global_debouncing, Utils.Consumer {
+ ClickUtils.applyPressedBgDark(it)
+ ClickUtils.applySingleDebouncing(it, 5000) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(StringUtils.getString(R.string.click_global_tip))
+ .setBgColor(ColorUtils.getRandomColor(false))
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .show()
+ }
+ }),
+ ClickItem(R.string.click_multi, Utils.Consumer {
+ ClickUtils.applyPressedBgDark(it)
+ it.setOnClickListener(object : ClickUtils.OnMultiClickListener(5) {
+ override fun onTriggerClick(v: View) {
+ ToastUtils.showShort("onTriggerClick")
+ }
+
+ override fun onBeforeTriggerClick(v: View, count: Int) {
+ ToastUtils.showShort(count)
+ }
+ })
+ })
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ SnackbarUtils.dismiss()
+ }
+}
+
+class ClickItem : CommonItem {
+
+ private val mConsumer: Utils.Consumer;
+ private val mTitle: String
+
+ constructor(@StringRes title: Int, consumer: Utils.Consumer) : super(R.layout.common_item_title_click) {
+ mConsumer = consumer
+ mTitle = StringUtils.getString(title)
+ }
+
+ override fun bind(holder: ItemViewHolder, position: Int) {
+ super.bind(holder, position)
+ holder.findViewById(R.id.commonItemTitleTv).text = mTitle
+ holder.itemView.setOnClickListener() {
+ SnackbarUtils.with(it)
+ .setMessage(mTitle)
+ .setBgColor(ColorUtils.getRandomColor(false))
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .show()
+ }
+ mConsumer.accept(holder.itemView)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt
new file mode 100644
index 0000000000..824fdf02ca
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/clipboard/ClipboardActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.clipboard
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.ClipboardUtils
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2020/09/11
+ * desc : demo about ClipboardUtils
+ * ```
+ */
+class ClipboardActivity : CommonActivity() {
+
+ private var index: Int = 0
+ private var isAddListener: Boolean = false
+ private var listener = {
+ ToastUtils.showShort(ClipboardUtils.getText())
+ }
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ClipboardActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_clipboard
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getText", ClipboardUtils.getText()),
+ CommonItemTitle("getLabel", ClipboardUtils.getLabel()),
+ CommonItemClick("copyText: value{$index}").setOnItemClickListener { _, _, _ ->
+ ClipboardUtils.copyText("value{${index++}}")
+ itemsView.updateItems(bindItems())
+ },
+ CommonItemClick("clear").setOnItemClickListener { _, _, _ ->
+ ClipboardUtils.clear()
+ itemsView.updateItems(bindItems())
+ },
+ CommonItemSwitch("clipChangeListener", { isAddListener }, {
+ isAddListener = it
+ if (isAddListener) {
+ ClipboardUtils.addChangedListener(listener)
+ } else {
+ ClipboardUtils.removeChangedListener(listener)
+ }
+ })
+ )
+ }
+
+ override fun onResume() {
+ super.onResume()
+ itemsView.updateItems(bindItems())
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (isAddListener) {
+ ClipboardUtils.removeChangedListener(listener)
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt
new file mode 100644
index 0000000000..d70fe14e93
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/device/DeviceActivity.kt
@@ -0,0 +1,56 @@
+package com.blankj.utilcode.pkg.feature.device
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.DeviceUtils
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/27
+ * desc : demo about DeviceUtils
+ * ```
+ */
+class DeviceActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, DeviceActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_device
+ }
+
+ override fun bindItems(): List> {
+ return arrayListOf>().apply {
+ add(CommonItemTitle("isRoot", DeviceUtils.isDeviceRooted().toString()))
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ add(CommonItemTitle("isAdbEnabled", DeviceUtils.isAdbEnabled().toString()))
+ }
+ add(CommonItemTitle("getSDKVersionName", DeviceUtils.getSDKVersionName()))
+ add(CommonItemTitle("getSDKVersionCode", DeviceUtils.getSDKVersionCode().toString()))
+ add(CommonItemTitle("getAndroidID", DeviceUtils.getAndroidID()))
+ add(CommonItemTitle("getMacAddress", DeviceUtils.getMacAddress()))
+ add(CommonItemTitle("getManufacturer", DeviceUtils.getManufacturer()))
+ add(CommonItemTitle("getModel", DeviceUtils.getModel()))
+ add(CommonItemTitle("getABIs", Arrays.asList(*DeviceUtils.getABIs()).toString()))
+ add(CommonItemTitle("isTablet", DeviceUtils.isTablet().toString()))
+ add(CommonItemTitle("isEmulator", DeviceUtils.isEmulator().toString()))
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ add(CommonItemTitle("isDevelopmentSettingsEnabled", DeviceUtils.isDevelopmentSettingsEnabled().toString()))
+ }
+ add(CommonItemTitle("getUniqueDeviceId", DeviceUtils.getUniqueDeviceId("util")))
+ add(CommonItemTitle("isSameDevice", DeviceUtils.isSameDevice(DeviceUtils.getUniqueDeviceId()).toString()))
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/file/FileActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/file/FileActivity.kt
new file mode 100644
index 0000000000..de8220dd18
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/file/FileActivity.kt
@@ -0,0 +1,59 @@
+package com.blankj.utilcode.pkg.feature.file
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.Config.CACHE_PATH
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.FileUtils
+import com.blankj.utilcode.util.PathUtils
+import com.blankj.utilcode.util.SnackbarUtils
+import java.io.File
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : demo about FileUtils
+ * ```
+ */
+class FileActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, FileActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ val TEST_FILE_PATH: String = CACHE_PATH + "test_file.txt"
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_file
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("isFileExists: " + PathUtils.getInternalAppFilesPath(), "" + FileUtils.isFileExists(PathUtils.getInternalAppFilesPath())),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalAppFilesPath(), "" + FileUtils.isFileExists(PathUtils.getExternalAppFilesPath())),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalStoragePath(), "" + FileUtils.isFileExists(PathUtils.getExternalStoragePath())),
+ CommonItemTitle("isFileExists: " + PathUtils.getDownloadCachePath(), "" + FileUtils.isFileExists(PathUtils.getDownloadCachePath())),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalDownloadsPath(), "" + FileUtils.isFileExists(PathUtils.getExternalDownloadsPath())),
+
+ CommonItemTitle("isFileExists: " + PathUtils.getInternalAppFilesPath(), "" + FileUtils.isFileExists(File(PathUtils.getInternalAppFilesPath()))),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalAppFilesPath(), "" + FileUtils.isFileExists(File(PathUtils.getExternalAppFilesPath()))),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalStoragePath(), "" + FileUtils.isFileExists(File(PathUtils.getExternalStoragePath()))),
+ CommonItemTitle("isFileExists: " + PathUtils.getDownloadCachePath(), "" + FileUtils.isFileExists(File(PathUtils.getDownloadCachePath()))),
+ CommonItemTitle("isFileExists: " + PathUtils.getExternalDownloadsPath(), "" + FileUtils.isFileExists(File(PathUtils.getExternalDownloadsPath())))
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ SnackbarUtils.dismiss()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt
new file mode 100644
index 0000000000..c5f602b9e3
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/flashlight/FlashlightActivity.kt
@@ -0,0 +1,64 @@
+package com.blankj.utilcode.pkg.feature.flashlight
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/04/27
+ * desc : demo about FlashlightUtils
+ * ```
+ */
+class FlashlightActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ if (!FlashlightUtils.isFlashlightEnable()) {
+ ToastUtils.showLong("Didn't support flashlight.")
+ return
+ }
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, FlashlightActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ LogUtils.e("permission denied")
+ }
+ }, PermissionConstants.CAMERA)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_flashlight
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList>().apply {
+ add(CommonItemTitle("isFlashlightEnable", FlashlightUtils.isFlashlightEnable().toString()))
+ if (FlashlightUtils.isFlashlightEnable()) {
+ add(CommonItemSwitch(
+ R.string.flashlight_status,
+ { FlashlightUtils.isFlashlightOn() },
+ { FlashlightUtils.setFlashlightStatus(it) }
+ ))
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ FlashlightUtils.destroy()
+ super.onDestroy()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ChildFragment.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ChildFragment.kt
new file mode 100644
index 0000000000..a4b1450de5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ChildFragment.kt
@@ -0,0 +1,81 @@
+package com.blankj.utilcode.pkg.feature.fragment
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.FragmentManager
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+import com.blankj.utilcode.util.FragmentUtils
+import com.blankj.utilcode.util.SpanUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/02
+ * desc : demo about FragmentUtils
+ * ```
+ */
+class ChildFragment : CommonFragment() {
+
+ companion object {
+ fun newInstance(): ChildFragment {
+ val args = Bundle()
+ val fragment = ChildFragment()
+ fragment.arguments = args
+ return fragment
+ }
+ }
+
+ private lateinit var fm: FragmentManager
+ private val mBgColor = ColorUtils.getRandomColor(false)
+
+ override fun bindLayout(): Int {
+ return R.layout.fragment_child
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ FragmentUtils.setBackgroundColor(this, mBgColor)
+ fm = fragmentManager!!
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ }
+
+ private fun getItems(): MutableList> {
+ return CollectionUtils.newArrayList>(
+ CommonItemClick(R.string.fragment_show_stack) {
+ DialogHelper.showFragmentDialog(
+ SpanUtils().appendLine("top: " + FragmentUtils.getSimpleName(FragmentUtils.getTop(fm)))
+ .appendLine("topInStack: " + FragmentUtils.getSimpleName(FragmentUtils.getTopInStack(fm)))
+ .appendLine("topShow: " + FragmentUtils.getSimpleName(FragmentUtils.getTopShow(fm)))
+ .appendLine("topShowInStack: " + FragmentUtils.getSimpleName(FragmentUtils.getTopShowInStack(fm)))
+ .appendLine()
+ .appendLine("---all of fragments---")
+ .appendLine(FragmentUtils.getAllFragments(fm).toString())
+ .appendLine("----------------------")
+ .appendLine()
+ .appendLine("---stack top---")
+ .appendLine(FragmentUtils.getAllFragmentsInStack(fm).toString())
+ .appendLine("---stack bottom---")
+ .create()
+ )
+ },
+ CommonItemClick(R.string.fragment_pop) {
+ FragmentUtils.pop(fm)
+ },
+ CommonItemClick(R.string.fragment_remove) {
+ FragmentUtils.remove(this)
+ },
+ SharedElementItem()
+ ).apply {
+ for (ci: CommonItem<*> in this) {
+ ci.backgroundColor = mBgColor
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
new file mode 100644
index 0000000000..e21eb521fb
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/ContainerFragment.kt
@@ -0,0 +1,178 @@
+package com.blankj.utilcode.pkg.feature.fragment
+
+import android.os.Build
+import android.os.Bundle
+import android.transition.*
+import android.view.View
+import android.widget.ImageView
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.FragmentManager
+import com.blankj.base.rv.ItemViewHolder
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.*
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/02
+ * desc : demo about FragmentUtils
+ * ```
+ */
+class ContainerFragment : CommonFragment(), FragmentUtils.OnBackClickListener {
+
+ companion object {
+ fun newInstance(): ContainerFragment {
+ val args = Bundle()
+ val fragment = ContainerFragment()
+ fragment.arguments = args
+ return fragment
+ }
+ }
+
+ private lateinit var fm: FragmentManager
+ private val mBgColor = ColorUtils.getRandomColor(false)
+
+ override fun bindLayout(): Int {
+ return R.layout.fragment_container
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ mContentView.setBackgroundColor(mBgColor)
+ fm = fragmentManager!!
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ }
+
+ private fun getItems(): ArrayList>? {
+ val item = SharedElementItem()
+ return CollectionUtils.newArrayList>(
+ CommonItemClick(R.string.fragment_show_stack) {
+ DialogHelper.showFragmentDialog(
+ SpanUtils().appendLine("top: " + FragmentUtils.getSimpleName(FragmentUtils.getTop(fm)))
+ .appendLine("topInStack: " + FragmentUtils.getSimpleName(FragmentUtils.getTopInStack(fm)))
+ .appendLine("topShow: " + FragmentUtils.getSimpleName(FragmentUtils.getTopShow(fm)))
+ .appendLine("topShowInStack: " + FragmentUtils.getSimpleName(FragmentUtils.getTopShowInStack(fm)))
+ .appendLine()
+ .appendLine("---all of fragments---")
+ .appendLine(FragmentUtils.getAllFragments(fm).toString())
+ .appendLine("----------------------")
+ .appendLine()
+ .appendLine("---stack top---")
+ .appendLine(FragmentUtils.getAllFragmentsInStack(fm).toString())
+ .appendLine("---stack bottom---")
+ .create()
+ )
+ },
+ CommonItemClick(R.string.fragment_add_child) {
+ FragmentUtils.add(
+ fm,
+ ChildFragment.newInstance(),
+ id
+ )
+ },
+ CommonItemClick(R.string.fragment_add_child_stack) {
+ FragmentUtils.add(
+ fm,
+ ChildFragment.newInstance(),
+ id,
+ false,
+ true
+ )
+ },
+ CommonItemClick(R.string.fragment_add_hide) {
+ FragmentUtils.add(
+ fm,
+ ChildFragment.newInstance(),
+ id,
+ true
+ )
+ },
+ CommonItemClick(R.string.fragment_add_hide_stack) {
+ FragmentUtils.add(
+ fm,
+ ChildFragment.newInstance(),
+ id,
+ true,
+ true
+ )
+ },
+ CommonItemClick(R.string.fragment_add_demo1_show) {
+ FragmentUtils.add(
+ fm,
+ addSharedElement(ChildFragment.newInstance()),
+ id,
+ false,
+ false
+ )
+ },
+ CommonItemClick(R.string.fragment_pop_to_root) {
+ FragmentUtils.popTo(
+ fm,
+ ChildFragment::class.java,
+ true
+ )
+ },
+ CommonItemClick(R.string.fragment_hide_demo0_show_demo1) {
+ val fragment1 = FragmentUtils.findFragment(fm, ChildFragment::class.java)
+ if (fragment1 != null) {
+ FragmentUtils.showHide(this, fragment1)
+ } else {
+ ToastUtils.showLong("please add demo1 first!")
+ }
+ },
+ CommonItemClick(R.string.fragment_replace) {
+ FragmentUtils.replace(
+ fm,
+ addSharedElement(ChildFragment.newInstance()),
+ id,
+ true,
+ item.element
+ )
+ },
+ item
+ ).apply {
+ for (ci: CommonItem<*> in this) {
+ ci.backgroundColor = mBgColor
+ }
+ }
+ }
+
+ private fun addSharedElement(fragment: androidx.fragment.app.Fragment): androidx.fragment.app.Fragment {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ fragment.sharedElementEnterTransition = DetailTransition()
+ fragment.enterTransition = Fade()
+ fragment.sharedElementReturnTransition = DetailTransition()
+ }
+ return fragment
+ }
+
+ override fun onBackClick(): Boolean {
+ return false
+ }
+}
+
+class SharedElementItem : CommonItem {
+
+ lateinit var element: ImageView;
+
+ constructor() : super(R.layout.fragment_item_shared_element)
+
+ override fun bind(holder: ItemViewHolder, position: Int) {
+ super.bind(holder, position)
+ element = holder.findViewById(R.id.fragmentRootSharedElementIv)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+class DetailTransition() : TransitionSet() {
+ init {
+ ordering = ORDERING_TOGETHER
+ addTransition(ChangeBounds()).addTransition(ChangeTransform()).addTransition(ChangeImageTransform())
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
new file mode 100644
index 0000000000..5b337e48d5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/FragmentActivity.kt
@@ -0,0 +1,91 @@
+package com.blankj.utilcode.pkg.feature.fragment
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.PersistableBundle
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import androidx.fragment.app.Fragment
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.FragmentUtils
+import kotlinx.android.synthetic.main.fragment_activity.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/01
+ * desc : demo about FragmentUtils
+ * ```
+ */
+class FragmentActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, FragmentActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private val mFragments = arrayListOf()
+ private var curIndex: Int = 0
+
+ private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
+ when (item.itemId) {
+ R.id.fragmentNavigation0 -> {
+ showCurrentFragment(0)
+ return@OnNavigationItemSelectedListener true
+ }
+ R.id.fragmentNavigation1 -> {
+ showCurrentFragment(1)
+ return@OnNavigationItemSelectedListener true
+ }
+ R.id.fragmentNavigation2 -> {
+ showCurrentFragment(2)
+ return@OnNavigationItemSelectedListener true
+ }
+ else -> false
+ }
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.fragment_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ if (savedInstanceState != null) {
+ curIndex = savedInstanceState.getInt("curIndex")
+ }
+ fragmentNav.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
+
+ mFragments.add(RootFragment.newInstance())
+ mFragments.add(RootFragment.newInstance())
+ mFragments.add(RootFragment.newInstance())
+ FragmentUtils.add(
+ supportFragmentManager,
+ mFragments,
+ R.id.fragmentContainer,
+ arrayOf("RootFragment0", "RootFragment1", "RootFragment2"),
+ curIndex
+ )
+ }
+
+ override fun onBackPressed() {
+ if (!FragmentUtils.dispatchBackPress(mFragments[curIndex])) {
+ super.onBackPressed()
+ }
+ }
+
+ private fun showCurrentFragment(index: Int) {
+ curIndex = index
+ FragmentUtils.showHide(index, mFragments)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
+ super.onSaveInstanceState(outState, outPersistentState)
+ outState.putInt("curIndex", curIndex)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/RootFragment.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/RootFragment.kt
new file mode 100644
index 0000000000..d2a9ac7bab
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/fragment/RootFragment.kt
@@ -0,0 +1,54 @@
+package com.blankj.utilcode.pkg.feature.fragment
+
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.fragment.CommonFragment
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.BarUtils
+import com.blankj.utilcode.util.ColorUtils
+import com.blankj.utilcode.util.FragmentUtils
+import kotlinx.android.synthetic.main.fragment_root.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 17/02/02
+ * desc : demo about FragmentUtils
+ * ```
+ */
+class RootFragment : CommonFragment(), FragmentUtils.OnBackClickListener {
+
+ companion object {
+ fun newInstance(): RootFragment {
+ val args = Bundle()
+ val fragment = RootFragment()
+ fragment.arguments = args
+ return fragment
+ }
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.fragment_root
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ BarUtils.setStatusBarColor(rootFragmentFakeStatusBar, ColorUtils.getColor(R.color.colorPrimary))
+ FragmentUtils.add(
+ childFragmentManager,
+ ContainerFragment.newInstance(),
+ R.id.rootFragmentContainer
+ )
+ }
+
+ override fun onBackClick(): Boolean {
+ if (FragmentUtils.dispatchBackPress(childFragmentManager)) return true
+ return if (childFragmentManager.backStackEntryCount == 0) {
+ false
+ } else {
+ childFragmentManager.popBackStack()
+ true
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
new file mode 100644
index 0000000000..995bbb22c1
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/image/ImageActivity.kt
@@ -0,0 +1,206 @@
+package com.blankj.utilcode.pkg.feature.image
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemImage
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.Config
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+import java.io.File
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/26
+ * desc : demo about ImageUtils
+ * ```
+ */
+class ImageActivity : CommonActivity() {
+
+ private val savePath = Config.CACHE_PATH + "lena.jpg"
+ private val titleItem: CommonItemTitle = CommonItemTitle("isImage: $savePath", "");
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, ImageActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.STORAGE)
+ }
+ }
+
+ private val bgTask: ThreadUtils.SimpleTask>> = object : ThreadUtils.SimpleTask>>() {
+ override fun doInBackground(): List> {
+ return bindItems()
+ }
+
+ override fun onSuccess(result: List>) {
+ dismissLoading()
+ itemsView.updateItems(result)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_image
+ }
+
+ override fun bindItems(): ArrayList> {
+ if (ThreadUtils.isMainThread()) return arrayListOf()
+ val src = ImageUtils.getBitmap(R.drawable.image_lena)
+ val round = ImageUtils.getBitmap(R.drawable.common_avatar_round)
+ val watermark = ImageUtils.getBitmap(R.mipmap.ic_launcher)
+
+ val width = src.width
+ val height = src.height
+
+ titleItem.setContent(ImageUtils.isImage(savePath).toString())
+
+ return CollectionUtils.newArrayList>().apply {
+ add(titleItem)
+ add(CommonItemClick("Save to $savePath") {
+ ThreadUtils.executeBySingle(object : ThreadUtils.SimpleTask() {
+ override fun doInBackground(): Boolean {
+ return ImageUtils.save(src, savePath, Bitmap.CompressFormat.JPEG)
+ }
+
+ override fun onSuccess(result: Boolean) {
+ titleItem.setContent(ImageUtils.isImage(savePath).toString())
+ titleItem.update()
+ SnackbarUtils.with(mContentView)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .apply {
+ if (result) {
+ setMessage("save successful.")
+ .showSuccess(true)
+ } else {
+ setMessage("save failed.")
+ .showError(true)
+ }
+ }
+ }
+ })
+ })
+ add(CommonItemClick("Save to Album") {
+ ThreadUtils.executeBySingle(object : ThreadUtils.SimpleTask() {
+ override fun doInBackground(): File? {
+ return ImageUtils.save2Album(src, Bitmap.CompressFormat.JPEG)
+ }
+
+ override fun onSuccess(result: File?) {
+ SnackbarUtils.with(mContentView)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .apply {
+ if (result != null) {
+ setMessage("save successful.")
+ .showSuccess(true)
+ } else {
+ setMessage("save failed.")
+ .showError(true)
+ }
+ }
+ }
+ })
+ })
+ add(CommonItemImage(R.string.image_src) {
+ it.setImageBitmap(src)
+ })
+ add(CommonItemImage(R.string.image_add_color) {
+ it.setImageBitmap(ImageUtils.drawColor(src, Color.parseColor("#8000FF00")))
+ })
+ add(CommonItemImage(R.string.image_scale) {
+ it.setImageBitmap(ImageUtils.scale(src, width / 2, height / 2))
+ })
+ add(CommonItemImage(R.string.image_clip) {
+ it.setImageBitmap(ImageUtils.clip(src, 0, 0, width / 2, height / 2))
+ })
+ add(CommonItemImage(R.string.image_skew) {
+ it.setImageBitmap(ImageUtils.skew(src, 0.2f, 0.1f))
+ })
+ add(CommonItemImage(R.string.image_rotate) {
+ it.setImageBitmap(ImageUtils.rotate(src, 90, (width / 2).toFloat(), (height / 2).toFloat()))
+ })
+ add(CommonItemImage(R.string.image_to_round) {
+ it.setImageBitmap(ImageUtils.toRound(src))
+ })
+ add(CommonItemImage(R.string.image_to_round_border) {
+ it.setImageBitmap(ImageUtils.toRound(src, 16, Color.GREEN))
+ })
+ add(CommonItemImage(R.string.image_to_round_corner) {
+ it.setImageBitmap(ImageUtils.toRoundCorner(src, 80f))
+ })
+ add(CommonItemImage(R.string.image_to_round_corner_border) {
+ it.setImageBitmap(ImageUtils.toRoundCorner(src, 80f, 16f, Color.GREEN))
+ })
+ add(CommonItemImage(R.string.image_to_round_corner_border) {
+ it.setImageBitmap(ImageUtils.toRoundCorner(src, floatArrayOf(0f, 0f, 80f, 80f, 0f, 0f, 80f, 80f), 16f, Color.GREEN))
+ })
+ add(CommonItemImage(R.string.image_add_corner_border) {
+ it.setImageBitmap(ImageUtils.addCornerBorder(src, 16f, Color.GREEN, 80f))
+ })
+ add(CommonItemImage(R.string.image_add_corner_border) {
+ it.setImageBitmap(ImageUtils.addCornerBorder(src, 16f, Color.GREEN, floatArrayOf(0f, 0f, 80f, 80f, 0f, 0f, 80f, 80f)))
+ })
+ add(CommonItemImage(R.string.image_add_circle_border) {
+ it.setImageBitmap(ImageUtils.addCircleBorder(src, 16f, Color.GREEN))
+ })
+ add(CommonItemImage(R.string.image_add_reflection) {
+ it.setImageBitmap(ImageUtils.addReflection(src, 80))
+ })
+ add(CommonItemImage(R.string.image_add_text_watermark) {
+ it.setImageBitmap(ImageUtils.addTextWatermark(src, "blankj", 40, Color.GREEN, 0f, 0f))
+ })
+ add(CommonItemImage(R.string.image_add_image_watermark) {
+ it.setImageBitmap(ImageUtils.addImageWatermark(src, watermark, 0, 0, 0x88))
+ })
+ add(CommonItemImage(R.string.image_to_gray) {
+ it.setImageBitmap(ImageUtils.toGray(src))
+ })
+ add(CommonItemImage(R.string.image_fast_blur) {
+ it.setImageBitmap(ImageUtils.fastBlur(src, 0.1f, 5f))
+ })
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ add(CommonItemImage(R.string.image_render_script_blur) {
+ it.setImageBitmap(ImageUtils.renderScriptBlur(src, 10f))
+ })
+ }
+ add(CommonItemImage(R.string.image_stack_blur) {
+ it.setImageBitmap(ImageUtils.stackBlur(src, 10))
+ })
+ add(CommonItemImage(R.string.image_compress_by_scale) {
+ it.setImageBitmap(ImageUtils.compressByScale(src, 0.5f, 0.5f))
+ })
+ add(CommonItemImage(R.string.image_compress_by_sample_size) {
+ it.setImageBitmap(ImageUtils.compressBySampleSize(src, 2))
+ })
+ }
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ showLoading()
+ ThreadUtils.executeByIo(bgTask)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ ThreadUtils.cancel(bgTask)
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/intent/IntentActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/intent/IntentActivity.kt
new file mode 100644
index 0000000000..06650d0b45
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/intent/IntentActivity.kt
@@ -0,0 +1,77 @@
+package com.blankj.utilcode.pkg.feature.intent
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.Config
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2020/05/29
+ * desc : demo about IntentUtils
+ * ```
+ */
+class IntentActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, IntentActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_intent
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick("LaunchApp") {
+ startActivity(IntentUtils.getLaunchAppIntent(packageName))
+ },
+ CommonItemClick("LaunchAppDetailsSettings") {
+ startActivityForResult(IntentUtils.getLaunchAppDetailsSettingsIntent(packageName), 1)
+ },
+ CommonItemClick("ShareText") {
+ startActivity(IntentUtils.getShareTextIntent("share content"))
+ },
+ CommonItemClick("ShareImage") {
+ startActivity(IntentUtils.getShareImageIntent(getShareImagePath()[0]));
+ },
+ CommonItemClick("ShareTextImage") {
+ startActivity(IntentUtils.getShareTextImageIntent("share content", getShareImagePath()[0]));
+ },
+ CommonItemClick("ShareImages") {
+ startActivity(IntentUtils.getShareImageIntent(getShareImagePath()));
+ },
+ CommonItemClick("ShareTextImages") {
+ startActivity(IntentUtils.getShareTextImageIntent("share content", getShareImagePath()));
+ }
+ )
+ }
+
+ private fun getShareImagePath(): LinkedList {
+ val shareImagePath0 = Config.CACHE_PATH + "share.jpg"
+ if (!FileUtils.isFile(shareImagePath0)) {
+ ImageUtils.save(ImageUtils.getBitmap(R.drawable.image_lena), shareImagePath0, Bitmap.CompressFormat.JPEG)
+ }
+ val shareImagePath1 = Config.CACHE_PATH + "cheetah.jpg"
+ if (!FileUtils.isFile(shareImagePath1)) {
+ ImageUtils.save(ImageUtils.getBitmap(R.drawable.span_cheetah), shareImagePath1, Bitmap.CompressFormat.JPEG)
+ }
+ return CollectionUtils.newLinkedList(shareImagePath0, shareImagePath1)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ LogUtils.d("onActivityResult() called with: requestCode = $requestCode, resultCode = $resultCode, data = $data")
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt
new file mode 100644
index 0000000000..5ed25ae4fe
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/keyboard/KeyboardActivity.kt
@@ -0,0 +1,73 @@
+package com.blankj.utilcode.pkg.feature.keyboard
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.*
+import kotlinx.android.synthetic.main.keyboard_activity.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/27
+ * desc : demo about KeyboardUtils
+ * ```
+ */
+class KeyboardActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, KeyboardActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private var titleItem: CommonItemTitle = CommonItemTitle("", true)
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_keyboard
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.keyboard_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ KeyboardUtils.fixAndroidBug5497(this)
+ setCommonItems(findViewById(R.id.commonItemRv), getItems())
+ KeyboardUtils.registerSoftInputChangedListener(this) { height ->
+ titleItem.title = "isSoftInputVisible: " + KeyboardUtils.isSoftInputVisible(this@KeyboardActivity) + "\nkeyboardHeight: $height"
+ if (height > 0) {
+ keyboardEt.requestFocus()
+ }
+ }
+ }
+
+ private fun getItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ titleItem,
+ CommonItemClick(R.string.keyboard_hide_soft_input) {
+ KeyboardUtils.hideSoftInput(this)
+ },
+ CommonItemClick(R.string.keyboard_show_soft_input) {
+ KeyboardUtils.showSoftInput(this)
+ },
+ CommonItemClick(R.string.keyboard_toggle_soft_input) {
+ KeyboardUtils.toggleSoftInput()
+ },
+ CommonItemClick(R.string.keyboard_show_dialog) {
+ keyboardEt.clearFocus()
+ DialogHelper.showKeyboardDialog(this)
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt
new file mode 100644
index 0000000000..c928da21fa
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/language/LanguageActivity.kt
@@ -0,0 +1,73 @@
+package com.blankj.utilcode.pkg.feature.language
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.LanguageUtils
+import com.blankj.utilcode.util.SPStaticUtils
+import com.blankj.utilcode.util.StringUtils
+import java.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/12/29
+ * desc : demo about VibrateUtils
+ * ```
+ */
+class LanguageActivity : CommonActivity() {
+
+ companion object {
+
+ const val SP_KEY_IS_RELAUNCH_APP = "SP_KEY_IS_RELAUNCH_APP"
+
+ fun start(context: Context) {
+ val starter = Intent(context, LanguageActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_language
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("isAppliedLanguage", LanguageUtils.isAppliedLanguage().toString()),
+ CommonItemTitle("isAppliedLanguage(SIMPLIFIED_CHINESE)", LanguageUtils.isAppliedLanguage(Locale.SIMPLIFIED_CHINESE).toString()),
+ CommonItemTitle("getAppliedLanguage", (LanguageUtils.getAppliedLanguage() ?: "null").toString()),
+ CommonItemTitle("getActivityContextLanguage", LanguageUtils.getContextLanguage(this).toString()),
+ CommonItemTitle("getAppContextLanguage", LanguageUtils.getAppContextLanguage().toString()),
+ CommonItemTitle("getSystemLanguage", LanguageUtils.getSystemLanguage().toString()),
+ CommonItemSwitch(
+ StringUtils.getString(R.string.language_relaunch_app),
+ { isRelaunchApp() },
+ { SPStaticUtils.put(SP_KEY_IS_RELAUNCH_APP, it) }
+ ),
+ CommonItemClick(R.string.language_apply_simple_chinese) {
+ LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, isRelaunchApp())
+ },
+ CommonItemClick(R.string.language_apply_american) {
+ LanguageUtils.applyLanguage(Locale.US, isRelaunchApp())
+ },
+ CommonItemClick(R.string.language_apply_english) {
+ LanguageUtils.applyLanguage(Locale.ENGLISH, isRelaunchApp())
+ },
+ CommonItemClick(R.string.language_apply_arabic) {
+ LanguageUtils.applyLanguage(Locale("ar"), isRelaunchApp())
+ },
+ CommonItemClick(R.string.language_apply_system) {
+ LanguageUtils.applySystemLanguage(isRelaunchApp())
+ }
+ )
+ }
+
+ private fun isRelaunchApp() = SPStaticUtils.getBoolean(SP_KEY_IS_RELAUNCH_APP)
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
new file mode 100644
index 0000000000..096df003e4
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/log/LogActivity.kt
@@ -0,0 +1,270 @@
+package com.blankj.utilcode.pkg.feature.log
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import com.blankj.base.BaseApplication
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+import java.io.File
+import java.util.*
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/03/22
+ * desc : demo about LogUtils
+ * ```
+ */
+class LogActivity : CommonActivity() {
+
+ companion object {
+ private const val TAG = "CMJ"
+ private const val JSON = "{\"tools\": [{ \"name\":\"css format\" , \"site\":\"http://tools.w3cschool.cn/code/css/" },{ \"name\":\"JSON format\" , \"site\":\"http://tools.w3cschool.cn/code/JSON/" },{ \"name\":\"pwd check\" , \"site\":\"http://tools.w3cschool.cn/password/my_password_safe/" }]}"
+ private const val XML = "Jack Herrington PHP Hacks O'Reilly Jack Herrington Podcasting Hacks O'Reilly "
+ private val ONE_D_ARRAY = intArrayOf(1, 2, 3)
+ private val TWO_D_ARRAY = arrayOf(intArrayOf(1, 2, 3), intArrayOf(4, 5, 6), intArrayOf(7, 8, 9))
+ private val THROWABLE = NullPointerException()
+ private val BUNDLE = Bundle()
+ private val INTENT = Intent()
+ private val LIST = ArrayList()
+ private val MAP = HashMap()
+
+ private val LONG_STR: String
+
+ init {
+ val sb = StringBuilder()
+ sb.append("len = 10400\ncontent = \"")
+ for (i in 0..1024) {
+ sb.append("Hello world. ")
+ }
+ sb.append("\"")
+ LONG_STR = sb.toString()
+
+ BUNDLE.putByte("byte", (-1).toByte())
+ BUNDLE.putChar("char", 'c')
+ BUNDLE.putCharArray("charArray", charArrayOf('c', 'h', 'a', 'r', 'A', 'r', 'r', 'a', 'y'))
+ BUNDLE.putCharSequence("charSequence", "charSequence")
+ BUNDLE.putCharSequenceArray("charSequenceArray", arrayOf("char", "Sequence", "Array"))
+ BUNDLE.putBundle("bundle", BUNDLE)
+ BUNDLE.putBoolean("boolean", true)
+ BUNDLE.putInt("int", 1)
+ BUNDLE.putFloat("float", 1f)
+ BUNDLE.putLong("long", 1L)
+ BUNDLE.putShort("short", 1.toShort())
+
+ INTENT.action = "LogUtils action"
+ INTENT.addCategory("LogUtils category")
+ INTENT.data = Uri.parse("intent data")
+ INTENT.type = "intent type"
+ INTENT.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ INTENT.setPackage(AppUtils.getAppPackageName())
+ INTENT.component = ComponentName(AppUtils.getAppPackageName(), LogActivity::class.java.toString())
+ INTENT.putExtra("int", 1)
+ INTENT.putExtra("float", 1f)
+ INTENT.putExtra("char", 'c')
+ INTENT.putExtra("string", "string")
+ INTENT.putExtra("intArray", ONE_D_ARRAY)
+ val list = ArrayList()
+ list.add("ArrayList")
+ list.add("is")
+ list.add("serializable")
+ INTENT.putExtra("serializable", list)
+ INTENT.putExtra("bundle", BUNDLE)
+
+ LIST.add("hello")
+ LIST.add("log")
+ LIST.add("utils")
+
+ MAP["name"] = "AndroidUtilCode"
+ MAP["class"] = "LogUtils"
+ }
+
+ fun start(context: Context) {
+ val starter = Intent(context, LogActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private val mConfig = LogUtils.getConfig()
+
+ private val mRunnable = Runnable {
+ LogUtils.v("verbose")
+ LogUtils.d("debug")
+ LogUtils.i("info")
+ LogUtils.w("warn")
+ LogUtils.e("error")
+ LogUtils.a("assert")
+ }
+
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_log
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getLogFiles", LogUtils.getLogFiles().toString()),
+ CommonItemSwitch(
+ R.string.log_switch,
+ { mConfig.isLogSwitch },
+ { mConfig.isLogSwitch = it }
+ ),
+ CommonItemSwitch(
+ R.string.log_console_switch,
+ { mConfig.isLog2ConsoleSwitch },
+ { mConfig.setConsoleSwitch(it) }
+ ),
+ CommonItemSwitch(
+ R.string.log_console_listener_switch,
+ { mConfig.haveSetOnConsoleOutputListener() },
+ { mConfig.setOnConsoleOutputListener { type, tag, content -> Log.println(type, tag, content) } }
+ ),
+ CommonItemClick("Global Tag", if (mConfig.globalTag == "") "null" else mConfig.globalTag).setOnClickUpdateContentListener {
+ if (StringUtils.isSpace(mConfig.globalTag)) {
+ mConfig.globalTag = TAG
+ } else {
+ mConfig.globalTag = ""
+ }
+ return@setOnClickUpdateContentListener if (mConfig.globalTag == "") "\"\"" else mConfig.globalTag
+ },
+ CommonItemSwitch(
+ R.string.log_head_switch,
+ { mConfig.isLogHeadSwitch },
+ { mConfig.isLogHeadSwitch = it }
+ ),
+ CommonItemSwitch(
+ R.string.log_file_switch,
+ { mConfig.isLog2FileSwitch },
+ { mConfig.isLog2FileSwitch = it }
+ ),
+ CommonItemSwitch(
+ R.string.log_file_listener_switch,
+ { mConfig.haveSetOnFileOutputListener() },
+ { mConfig.setOnFileOutputListener { filePath, content -> Log.d("LogActivity", filePath + "\n" + content) } }
+ ),
+ CommonItemClick("Dir", mConfig.dir).setOnClickUpdateContentListener {
+ if (mConfig.dir != mConfig.defaultDir) {
+ mConfig.dir = mConfig.defaultDir
+ } else {
+ mConfig.setDir(File(PathUtils.getExternalAppFilesPath(), "log"))
+ }
+ return@setOnClickUpdateContentListener mConfig.dir
+ },
+ CommonItemSwitch(
+ R.string.log_border_switch,
+ { mConfig.isLogBorderSwitch },
+ { mConfig.setBorderSwitch(it) }
+ ),
+ CommonItemSwitch(
+ R.string.log_single_tag_switch,
+ { mConfig.isSingleTagSwitch },
+ { mConfig.setSingleTagSwitch(it) }
+ ),
+ CommonItemSwitch(
+ R.string.log_single_tag_switch,
+ { mConfig.isSingleTagSwitch },
+ { mConfig.setSingleTagSwitch(it) }
+ ),
+ CommonItemClick("ConsoleFilter", mConfig.consoleFilter.toString()).setOnClickUpdateContentListener {
+ mConfig.setConsoleFilter(if (mConfig.consoleFilter == 'V') LogUtils.W else LogUtils.V)
+ return@setOnClickUpdateContentListener mConfig.consoleFilter.toString()
+ },
+ CommonItemClick("FileFilter", mConfig.fileFilter.toString()).setOnClickUpdateContentListener {
+ mConfig.setFileFilter(if (mConfig.fileFilter == 'V') LogUtils.W else LogUtils.V)
+ return@setOnClickUpdateContentListener mConfig.fileFilter.toString()
+ },
+ CommonItemClick(R.string.log_with_no_tag) {
+ LogUtils.v("verbose")
+ LogUtils.d("debug")
+ LogUtils.i("info")
+ LogUtils.w("warn")
+ LogUtils.e("error")
+ LogUtils.a("assert")
+ },
+ CommonItemClick(R.string.log_with_tag) {
+ LogUtils.vTag("customTag", "verbose")
+ LogUtils.dTag("customTag", "debug")
+ LogUtils.iTag("customTag", "info")
+ LogUtils.wTag("customTag", "warn")
+ LogUtils.eTag("customTag", "error")
+ LogUtils.aTag("customTag", "assert")
+ },
+ CommonItemClick(R.string.log_in_new_thread) {
+ val thread = Thread(mRunnable)
+ thread.start()
+ },
+ CommonItemClick(R.string.log_null) {
+ LogUtils.v(null)
+ LogUtils.d(null)
+ LogUtils.i(null)
+ LogUtils.w(null)
+ LogUtils.e(null)
+ LogUtils.a(null)
+ },
+ CommonItemClick(R.string.log_many_params) {
+ LogUtils.v("verbose0", "verbose1")
+ LogUtils.vTag("customTag", "verbose0", "verbose1")
+ LogUtils.d("debug0", "debug1")
+ LogUtils.dTag("customTag", "debug0", "debug1")
+ LogUtils.i("info0", "info1")
+ LogUtils.iTag("customTag", "info0", "info1")
+ LogUtils.w("warn0", "warn1")
+ LogUtils.wTag("customTag", "warn0", "warn1")
+ LogUtils.e("error0", "error1")
+ LogUtils.eTag("customTag", "error0", "error1")
+ LogUtils.a("assert0", "assert1")
+ LogUtils.aTag("customTag", "assert0", "assert1")
+ },
+ CommonItemClick(R.string.log_long_string) {
+ LogUtils.d(LONG_STR)
+ },
+ CommonItemClick(R.string.log_to_file) {
+ LogUtils.file("test0 log to file")
+ LogUtils.file(LogUtils.I, "test0 log to file")
+ },
+ CommonItemClick(R.string.log_json) {
+ LogUtils.json(JSON)
+ LogUtils.json(LogUtils.I, JSON)
+ },
+ CommonItemClick(R.string.log_xml) {
+ LogUtils.xml(XML)
+ LogUtils.xml(LogUtils.I, XML)
+ },
+ CommonItemClick(R.string.log_array) {
+ LogUtils.e(ONE_D_ARRAY)
+ LogUtils.e(TWO_D_ARRAY)
+ },
+ CommonItemClick(R.string.log_throwable) {
+ LogUtils.e(THROWABLE)
+ },
+ CommonItemClick(R.string.log_bundle) {
+ LogUtils.e(BUNDLE)
+ },
+ CommonItemClick(R.string.log_intent) {
+ LogUtils.e(INTENT)
+ },
+ CommonItemClick(R.string.log_array_list) {
+ LogUtils.e(LIST)
+ },
+ CommonItemClick(R.string.log_map) {
+ LogUtils.e(MAP)
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ BaseApplication.getInstance().initLog()
+ super.onDestroy()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerActivity.kt
new file mode 100644
index 0000000000..3d00af0e1a
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerActivity.kt
@@ -0,0 +1,71 @@
+package com.blankj.utilcode.pkg.feature.messenger
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.activity.CommonActivityItemsView
+import com.blankj.common.activity.CommonActivityTitleView
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.MessengerUtils
+import com.blankj.utilcode.util.SnackbarUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/03/12
+ * desc : demo about MessengerUtils
+ * ```
+ */
+class MessengerActivity : CommonActivity() {
+
+ companion object {
+ const val MESSENGER_KEY = "MessengerActivity"
+
+ fun start(context: Context) {
+ val starter = Intent(context, MessengerActivity::class.java)
+ context.startActivity(starter)
+ MessengerUtils.register()
+ }
+
+ val BUNDLE = Bundle()
+
+ init {
+ BUNDLE.putString(MESSENGER_KEY, "MessengerActivity")
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_messenger
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.messenger_post_to_main_server) {
+ MessengerUtils.post(MESSENGER_KEY, BUNDLE)
+ },
+ CommonItemClick(R.string.messenger_start_remote) {
+ MessengerRemoteActivity.start(this)
+ }
+ )
+ }
+
+ override fun doBusiness() {
+ MessengerUtils.subscribe(MESSENGER_KEY) { data ->
+ SnackbarUtils.with(mContentView)
+ .setMessage(data.getString(MESSENGER_KEY) ?: "")
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .show()
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ MessengerUtils.unregister()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerRemoteActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerRemoteActivity.kt
new file mode 100644
index 0000000000..acd6c58fde
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/messenger/MessengerRemoteActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.messenger
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.activity.CommonActivityItemsView
+import com.blankj.common.activity.CommonActivityTitleView
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.MessengerUtils
+import com.blankj.utilcode.util.SnackbarUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/03/12
+ * desc : demo about MessengerUtils
+ * ```
+ */
+class MessengerRemoteActivity : CommonActivity() {
+
+ companion object {
+ const val MESSENGER_KEY = "MessengerRemoteActivity"
+
+ fun start(context: Context) {
+ val starter = Intent(context, MessengerRemoteActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ val BUNDLE = Bundle()
+
+ init {
+ BUNDLE.putString(MESSENGER_KEY, "MessengerRemoteActivity")
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_messenger
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.messenger_register_remote_client) {
+ MessengerUtils.register()
+ },
+ CommonItemClick(R.string.messenger_unregister_remote_client) {
+ MessengerUtils.unregister()
+ },
+ CommonItemClick(R.string.messenger_post_to_self_client) {
+ MessengerUtils.post(MESSENGER_KEY, BUNDLE)
+ },
+ CommonItemClick(R.string.messenger_post_to_main_server) {
+ MessengerUtils.post(MessengerActivity.MESSENGER_KEY, MessengerActivity.BUNDLE)
+ }
+ )
+ }
+
+ override fun doBusiness() {
+ MessengerUtils.subscribe(MESSENGER_KEY) { data ->
+ SnackbarUtils.with(mContentView)
+ .setMessage(data.getString(MESSENGER_KEY) ?: "")
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .show()
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ MessengerUtils.unsubscribe(MESSENGER_KEY)
+ MessengerUtils.unregister()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt
new file mode 100644
index 0000000000..77bb5f8e82
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/metaData/MetaDataActivity.kt
@@ -0,0 +1,39 @@
+package com.blankj.utilcode.pkg.feature.metaData
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.MetaDataUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/05/15
+ * desc : demo about MetaDataUtils
+ * ```
+ */
+class MetaDataActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, MetaDataActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_meta_data
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getMetaDataInApp", MetaDataUtils.getMetaDataInApp("app_meta_data")),
+ CommonItemTitle("getMetaDataInActivity", MetaDataUtils.getMetaDataInActivity(this, "activity_meta_data").substring(1))
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java
new file mode 100644
index 0000000000..7fff29f4a7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpActivity.java
@@ -0,0 +1,43 @@
+package com.blankj.utilcode.pkg.feature.mvp;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+import com.blankj.common.activity.CommonActivity;
+import com.blankj.utilcode.pkg.R;
+
+import androidx.annotation.Nullable;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/09
+ * desc :
+ *
+ */
+public class MvpActivity extends CommonActivity {
+
+ public static void start(Context context) {
+ Intent starter = new Intent(context, MvpActivity.class);
+ context.startActivity(starter);
+ }
+
+ @Override
+ public int bindTitleRes() {
+ return R.string.demo_mvp;
+ }
+
+ @Override
+ public int bindLayout() {
+ return R.layout.mvp_activity;
+ }
+
+ @Override
+ public void initView(@Nullable Bundle savedInstanceState, @Nullable View contentView) {
+ super.initView(savedInstanceState, contentView);
+ new MvpView(this).addPresenter(new MvpPresenter());
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java
new file mode 100644
index 0000000000..e16b4f1934
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpModel.java
@@ -0,0 +1,44 @@
+package com.blankj.utilcode.pkg.feature.mvp;
+
+import com.blankj.base.mvp.BaseModel;
+import com.blankj.utilcode.util.ThreadUtils;
+import com.blankj.utilcode.util.Utils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/26
+ * desc :
+ *
+ */
+public class MvpModel extends BaseModel implements MvpMvp.Model {
+
+ private int index;
+
+ @Override
+ public void onCreate() {
+ index = 0;
+ }
+
+ @Override
+ public void requestUpdateMsg(final Utils.Consumer consumer) {
+ ThreadUtils.executeByCached(new ThreadUtils.SimpleTask() {
+ @Override
+ public String doInBackground() throws Throwable {
+ Thread.sleep(2000);
+ return "msg: " + index++;
+ }
+
+ @Override
+ public void onSuccess(String result) {
+ consumer.accept(result);
+ }
+ });
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java
new file mode 100644
index 0000000000..d0335ef203
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpMvp.java
@@ -0,0 +1,28 @@
+package com.blankj.utilcode.pkg.feature.mvp;
+
+import com.blankj.utilcode.util.Utils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/26
+ * desc :
+ *
+ */
+public interface MvpMvp {
+
+ interface View {
+ void setLoadingVisible(boolean visible);
+
+ void showMsg(CharSequence msg);
+ }
+
+ interface Presenter {
+ void updateMsg();
+ }
+
+ interface Model {
+ void requestUpdateMsg(final Utils.Consumer consumer);
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java
new file mode 100644
index 0000000000..fcb68bd3ed
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpPresenter.java
@@ -0,0 +1,37 @@
+package com.blankj.utilcode.pkg.feature.mvp;
+
+import com.blankj.base.mvp.BasePresenter;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.Utils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/26
+ * desc :
+ *
+ */
+public class MvpPresenter extends BasePresenter
+ implements MvpMvp.Presenter {
+
+ @Override
+ public void onBindView() {
+ }
+
+ @Override
+ public void updateMsg() {
+ getView().setLoadingVisible(true);
+ getModel(MvpModel.class).requestUpdateMsg(new Utils.Consumer() {
+ @Override
+ public void accept(String s) {
+ if (isAlive()) {
+ getView().showMsg(s);
+ getView().setLoadingVisible(false);
+ } else {
+ LogUtils.iTag(MvpView.TAG, "destroyed");
+ }
+ }
+ });
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java
new file mode 100644
index 0000000000..e916398e48
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/mvp/MvpView.java
@@ -0,0 +1,78 @@
+package com.blankj.utilcode.pkg.feature.mvp;
+
+import android.text.Layout;
+import android.view.View;
+import android.widget.TextView;
+
+import com.blankj.base.mvp.BaseView;
+import com.blankj.utilcode.pkg.R;
+import com.blankj.utilcode.util.ClickUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SizeUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+import com.blankj.utilcode.util.ToastUtils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/26
+ * desc :
+ *
+ */
+public class MvpView extends BaseView
+ implements MvpMvp.View {
+
+ private TextView mvpTv;
+ private TextView mvpMeasureWidthTv;
+ private int i = 0;
+
+ public MvpView(MvpActivity activity) {
+ super(activity);
+ mvpTv = activity.findViewById(R.id.mvpUpdateTv);
+ ClickUtils.applyPressedBgDark(mvpTv);
+ mvpTv.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getPresenter(MvpPresenter.class).updateMsg();
+ }
+ });
+
+ mvpMeasureWidthTv = activity.findViewById(R.id.mvpMeasureWidthTv);
+
+ measure();
+ }
+
+ private void measure() {
+ ThreadUtils.runOnUiThreadDelayed(new Runnable() {
+ @Override
+ public void run() {
+ float textWidth = Layout.getDesiredWidth(mvpMeasureWidthTv.getText(), mvpMeasureWidthTv.getPaint()) + SizeUtils.dp2px(16);
+ float textWidth2 = mvpMeasureWidthTv.getPaint().measureText(mvpMeasureWidthTv.getText().toString()) + SizeUtils.dp2px(16);
+ LogUtils.i(mvpMeasureWidthTv.getWidth(), textWidth, textWidth2);
+ mvpMeasureWidthTv.setText(mvpMeasureWidthTv.getText().toString() + i);
+ measure();
+ }
+ }, 1000);
+ }
+
+ @Override
+ public void setLoadingVisible(boolean visible) {
+ final MvpActivity activity = getActivity();
+ if (visible) {
+ activity.showLoading(new Runnable() {
+ @Override
+ public void run() {
+ activity.finish();
+ }
+ });
+ } else {
+ activity.dismissLoading();
+ }
+ }
+
+ @Override
+ public void showMsg(CharSequence msg) {
+ ToastUtils.showLong(msg);
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt
new file mode 100644
index 0000000000..452040376d
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/network/NetworkActivity.kt
@@ -0,0 +1,151 @@
+package com.blankj.utilcode.pkg.feature.network
+
+import android.content.Context
+import android.content.Intent
+import android.net.wifi.ScanResult
+import android.net.wifi.WifiManager
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about NetworkUtils
+ * ```
+ */
+class NetworkActivity : CommonActivity(), NetworkUtils.OnNetworkStatusChangedListener {
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, NetworkActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.LOCATION)
+ }
+ }
+
+ private lateinit var itemsTask: ThreadUtils.SimpleTask>>
+ private lateinit var wifiScanResultItem: CommonItemTitle
+ private val consumer = Utils.Consumer { t ->
+ wifiScanResultItem.setContent(scanResults2String(t.filterResults))
+ wifiScanResultItem.update()
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_network
+ }
+
+ private fun getItemsTask(): ThreadUtils.SimpleTask>> {
+ itemsTask = object : ThreadUtils.SimpleTask>>() {
+ override fun doInBackground(): List> {
+ return bindItems()
+ }
+
+ override fun onSuccess(result: List>) {
+ dismissLoading()
+ itemsView.updateItems(result)
+ }
+ }
+ return itemsTask
+ }
+
+ override fun bindItems(): List> {
+ if (ThreadUtils.isMainThread()) return arrayListOf()
+ wifiScanResultItem = CommonItemTitle("getWifiScanResult", scanResults2String(NetworkUtils.getWifiScanResult().filterResults))
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("isConnected", NetworkUtils.isConnected().toString()),
+ CommonItemTitle("getMobileDataEnabled", NetworkUtils.getMobileDataEnabled().toString()),
+ CommonItemTitle("isMobileData", NetworkUtils.isMobileData().toString()),
+ CommonItemTitle("is4G", NetworkUtils.is4G().toString()),
+ CommonItemTitle("is5G", NetworkUtils.is5G().toString()),
+ CommonItemTitle("isWifiConnected", NetworkUtils.isWifiConnected().toString()),
+ CommonItemTitle("getNetworkOperatorName", NetworkUtils.getNetworkOperatorName()),
+ CommonItemTitle("getNetworkTypeName", NetworkUtils.getNetworkType().toString()),
+ CommonItemTitle("getBroadcastIpAddress", NetworkUtils.getBroadcastIpAddress()),
+ CommonItemTitle("getIpAddressByWifi", NetworkUtils.getIpAddressByWifi()),
+ CommonItemTitle("getGatewayByWifi", NetworkUtils.getGatewayByWifi()),
+ CommonItemTitle("getNetMaskByWifi", NetworkUtils.getNetMaskByWifi()),
+ CommonItemTitle("getServerAddressByWifi", NetworkUtils.getServerAddressByWifi()),
+ CommonItemTitle("getSSID", NetworkUtils.getSSID()),
+
+ CommonItemTitle("getIPv4Address", NetworkUtils.getIPAddress(true)),
+ CommonItemTitle("getIPv6Address", NetworkUtils.getIPAddress(false)),
+ CommonItemTitle("isWifiAvailable", NetworkUtils.isWifiAvailable().toString()),
+ CommonItemTitle("isAvailable", NetworkUtils.isAvailable().toString()),
+ CommonItemTitle("getBaiduDomainAddress", NetworkUtils.getDomainAddress("baidu.com")),
+ wifiScanResultItem,
+
+ CommonItemSwitch(
+ R.string.network_wifi_enabled,
+ {
+ val wifiEnabled = NetworkUtils.getWifiEnabled()
+ if (wifiEnabled) {
+ NetworkUtils.addOnWifiChangedConsumer(consumer)
+ } else {
+ NetworkUtils.removeOnWifiChangedConsumer(consumer)
+ }
+ wifiEnabled
+ },
+ {
+ NetworkUtils.setWifiEnabled(it)
+ ThreadUtils.executeByIo(getItemsTask())
+ }
+ ),
+ CommonItemClick(R.string.network_open_wireless_settings) {
+ NetworkUtils.openWirelessSettings()
+ }
+ )
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ NetworkUtils.registerNetworkStatusChangedListener(this)
+ updateItems()
+ }
+
+ override fun onDisconnected() {
+ ToastUtils.showLong("onDisconnected")
+ updateItems()
+ }
+
+ override fun onConnected(networkType: NetworkUtils.NetworkType) {
+ ToastUtils.showLong("onConnected: ${networkType.name}")
+ updateItems()
+ }
+
+ private fun updateItems() {
+ showLoading()
+ ThreadUtils.executeByIo(getItemsTask())
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ ThreadUtils.cancel(itemsTask)
+ NetworkUtils.unregisterNetworkStatusChangedListener(this)
+ NetworkUtils.removeOnWifiChangedConsumer(consumer)
+ }
+
+ private fun scanResults2String(results: List): String {
+ val sb: StringBuilder = StringBuilder()
+ for (result in results) {
+ sb.append(String.format("${result.SSID}, Level: ${WifiManager.calculateSignalLevel(result.level, 4)}\n"))
+ }
+ return sb.toString()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/notification/NotificationActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/notification/NotificationActivity.kt
new file mode 100644
index 0000000000..d69c30b6cd
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/notification/NotificationActivity.kt
@@ -0,0 +1,69 @@
+package com.blankj.utilcode.pkg.feature.notification
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.NotificationUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/10/22
+ * desc : demo about NotificationUtils
+ * ```
+ */
+class NotificationActivity : CommonActivity() {
+
+ private var id: Int = 0
+ private var cancelId: Int = 0
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, NotificationActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_notification
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("areNotificationsEnabled", NotificationUtils.areNotificationsEnabled().toString()),
+ CommonItemClick(R.string.notification_notify) {
+ NotificationUtils.notify(id++) { param ->
+ intent.putExtra("id", id);
+ param.setSmallIcon(R.mipmap.ic_launcher)
+ .setContentTitle("title")
+ .setContentText("content text: $id")
+ .setContentIntent(PendingIntent.getActivity(mActivity, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
+ .setAutoCancel(true)
+ null
+ }
+ },
+ CommonItemClick(R.string.notification_cancel) {
+ if (cancelId < id) {
+ NotificationUtils.cancel(cancelId++)
+ } else {
+ ToastUtils.showShort("No notification.")
+ }
+ },
+ CommonItemClick(R.string.notification_cancel_all) {
+ NotificationUtils.cancelAll()
+ cancelId = id;
+ },
+ CommonItemClick(R.string.notification_show) {
+ NotificationUtils.setNotificationBarVisibility(true)
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/path/PathActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/path/PathActivity.kt
new file mode 100644
index 0000000000..b5f657286d
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/path/PathActivity.kt
@@ -0,0 +1,76 @@
+package com.blankj.utilcode.pkg.feature.path
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.PathUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about PathUtils
+ * ```
+ */
+class PathActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, PathActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_path
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getRootPath", PathUtils.getRootPath()),
+ CommonItemTitle("getDataPath", PathUtils.getDataPath()),
+ CommonItemTitle("getDownloadCachePath", PathUtils.getDownloadCachePath()),
+
+ CommonItemTitle("getInternalAppDataPath", PathUtils.getInternalAppDataPath()),
+ CommonItemTitle("getInternalAppCodeCacheDir", PathUtils.getInternalAppCodeCacheDir()),
+ CommonItemTitle("getInternalAppCachePath", PathUtils.getInternalAppCachePath()),
+ CommonItemTitle("getInternalAppDbsPath", PathUtils.getInternalAppDbsPath()),
+ CommonItemTitle("getInternalAppDbPath", PathUtils.getInternalAppDbPath("demo")),
+ CommonItemTitle("getInternalAppFilesPath", PathUtils.getInternalAppFilesPath()),
+ CommonItemTitle("getInternalAppSpPath", PathUtils.getInternalAppSpPath()),
+ CommonItemTitle("getInternalAppNoBackupFilesPath", PathUtils.getInternalAppNoBackupFilesPath()),
+
+ CommonItemTitle("getExternalStoragePath", PathUtils.getExternalStoragePath()),
+ CommonItemTitle("getExternalMusicPath", PathUtils.getExternalMusicPath()),
+ CommonItemTitle("getExternalPodcastsPath", PathUtils.getExternalPodcastsPath()),
+ CommonItemTitle("getExternalRingtonesPath", PathUtils.getExternalRingtonesPath()),
+ CommonItemTitle("getExternalAlarmsPath", PathUtils.getExternalAlarmsPath()),
+ CommonItemTitle("getExternalNotificationsPath", PathUtils.getExternalNotificationsPath()),
+ CommonItemTitle("getExternalPicturesPath", PathUtils.getExternalPicturesPath()),
+ CommonItemTitle("getExternalMoviesPath", PathUtils.getExternalMoviesPath()),
+ CommonItemTitle("getExternalDownloadsPath", PathUtils.getExternalDownloadsPath()),
+ CommonItemTitle("getExternalDcimPath", PathUtils.getExternalDcimPath()),
+ CommonItemTitle("getExternalDocumentsPath", PathUtils.getExternalDocumentsPath()),
+
+ CommonItemTitle("getExternalAppDataPath", PathUtils.getExternalAppDataPath()),
+ CommonItemTitle("getExternalAppCachePath", PathUtils.getExternalAppCachePath()),
+ CommonItemTitle("getExternalAppFilesPath", PathUtils.getExternalAppFilesPath()),
+ CommonItemTitle("getExternalAppMusicPath", PathUtils.getExternalAppMusicPath()),
+ CommonItemTitle("getExternalAppPodcastsPath", PathUtils.getExternalAppPodcastsPath()),
+ CommonItemTitle("getExternalAppRingtonesPath", PathUtils.getExternalAppRingtonesPath()),
+ CommonItemTitle("getExternalAppAlarmsPath", PathUtils.getExternalAppAlarmsPath()),
+ CommonItemTitle("getExternalAppNotificationsPath", PathUtils.getExternalAppNotificationsPath()),
+ CommonItemTitle("getExternalAppPicturesPath", PathUtils.getExternalAppPicturesPath()),
+ CommonItemTitle("getExternalAppMoviesPath", PathUtils.getExternalAppMoviesPath()),
+ CommonItemTitle("getExternalAppDownloadPath", PathUtils.getExternalAppDownloadPath()),
+ CommonItemTitle("getExternalAppDcimPath", PathUtils.getExternalAppDcimPath()),
+ CommonItemTitle("getExternalAppDocumentsPath", PathUtils.getExternalAppDocumentsPath()),
+ CommonItemTitle("getExternalAppObbPath", PathUtils.getExternalAppObbPath())
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt
new file mode 100644
index 0000000000..c55d9c945b
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/permission/PermissionActivity.kt
@@ -0,0 +1,200 @@
+package com.blankj.utilcode.pkg.feature.permission
+
+import android.Manifest.permission
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/01/01
+ * desc : demo about PermissionUtils
+ * ```
+ */
+class PermissionActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, PermissionActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private val permissions: String
+
+ init {
+ val permissionList = PermissionUtils.getPermissions()
+ if (permissionList.isEmpty()) {
+ permissions = ""
+ } else {
+ val sb = StringBuilder()
+ for (permission in permissionList) {
+ sb.append("\n").append(permission.substring(permission.lastIndexOf('.') + 1))
+ }
+ permissions = sb.deleteCharAt(0).toString()
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_permission
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList>().apply {
+ add(CommonItemTitle("Permissions", permissions))
+ add(CommonItemClick(R.string.permission_open_app_settings, true) { PermissionUtils.launchAppDetailsSettings() })
+ add(CommonItemSwitch(
+ R.string.permission_calendar_status,
+ { PermissionUtils.isGranted(PermissionConstants.CALENDAR) },
+ { requestCalendar() }
+ ))
+ add(CommonItemSwitch(
+ R.string.permission_record_audio_status,
+ { PermissionUtils.isGranted(PermissionConstants.MICROPHONE) },
+ { requestRecordAudio() }
+ ))
+ add(CommonItemSwitch(
+ R.string.permission_calendar_and_record_audio_status,
+ { PermissionUtils.isGranted(PermissionConstants.CALENDAR, PermissionConstants.MICROPHONE) },
+ { requestCalendarAndRecordAudio() }
+ ))
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ add(CommonItemSwitch(
+ R.string.permission_write_settings_status,
+ { PermissionUtils.isGrantedWriteSettings() },
+ { requestWriteSettings() }
+ ))
+ add(CommonItemSwitch(
+ R.string.permission_write_settings_status,
+ { PermissionUtils.isGrantedDrawOverlays() },
+ { requestDrawOverlays() }
+ ))
+ }
+ }
+ }
+
+ private fun requestCalendar() {
+ PermissionUtils.permissionGroup(PermissionConstants.CALENDAR)
+ .rationale { activity, shouldRequest -> PermissionHelper.showRationaleDialog(activity, shouldRequest) }
+ .callback(object : PermissionUtils.FullCallback {
+ override fun onGranted(permissionsGranted: List) {
+ LogUtils.d(permissionsGranted)
+ showSnackbar(true, "Calendar is granted")
+ itemsView.updateItems(bindItems())
+ }
+
+ override fun onDenied(permissionsDeniedForever: List,
+ permissionsDenied: List) {
+ LogUtils.d(permissionsDeniedForever, permissionsDenied)
+ if (permissionsDeniedForever.isNotEmpty()) {
+ showSnackbar(false, "Calendar is denied forever")
+ } else {
+ showSnackbar(false, "Calendar is denied")
+ }
+ itemsView.updateItems(bindItems())
+ }
+ })
+ .theme { activity -> ScreenUtils.setFullScreen(activity) }
+ .request()
+ }
+
+ private fun requestRecordAudio() {
+ PermissionUtils.permissionGroup(PermissionConstants.MICROPHONE)
+ .rationale { activity, shouldRequest -> PermissionHelper.showRationaleDialog(activity, shouldRequest) }
+ .callback(object : PermissionUtils.FullCallback {
+ override fun onGranted(permissionsGranted: List) {
+ LogUtils.d(permissionsGranted)
+ showSnackbar(true, "Microphone is granted")
+ itemsView.updateItems(bindItems())
+ }
+
+ override fun onDenied(permissionsDeniedForever: List,
+ permissionsDenied: List) {
+ LogUtils.d(permissionsDeniedForever, permissionsDenied)
+ if (permissionsDeniedForever.isNotEmpty()) {
+ showSnackbar(false, "Microphone is denied forever")
+ } else {
+ showSnackbar(false, "Microphone is denied")
+ }
+ itemsView.updateItems(bindItems())
+ }
+ })
+ .request()
+ }
+
+ private fun requestCalendarAndRecordAudio() {
+ PermissionUtils.permission(permission.READ_CALENDAR, permission.RECORD_AUDIO)
+ .explain { activity, denied, shouldRequest -> PermissionHelper.showExplainDialog(activity, denied, shouldRequest) }
+ .callback { isAllGranted, granted, deniedForever, denied ->
+ LogUtils.d(granted, deniedForever, denied)
+ itemsView.updateItems(bindItems())
+ if (isAllGranted) {
+ showSnackbar(true, "Calendar and Microphone are granted")
+ return@callback
+ }
+ if (deniedForever.isNotEmpty()) {
+ showSnackbar(false, "Calendar or Microphone is denied forever")
+ } else {
+ showSnackbar(false, "Calendar or Microphone is denied")
+ }
+ }
+ .request()
+ }
+
+ private fun requestWriteSettings() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ PermissionUtils.requestWriteSettings(object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ showSnackbar(true, "Write Settings is granted")
+ itemsView.updateItems(bindItems())
+ }
+
+ override fun onDenied() {
+ showSnackbar(false, "Write Settings is denied")
+ itemsView.updateItems(bindItems())
+ }
+ })
+ }
+ }
+
+ private fun requestDrawOverlays() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ PermissionUtils.requestDrawOverlays(object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ showSnackbar(true, "Draw Overlays is granted")
+ itemsView.updateItems(bindItems())
+ }
+
+ override fun onDenied() {
+ showSnackbar(false, "Draw Overlays is denied")
+ itemsView.updateItems(bindItems())
+ }
+ })
+ }
+ }
+
+
+ private fun showSnackbar(isSuccess: Boolean, msg: String) {
+ SnackbarUtils.with(mContentView)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .setMessage(msg)
+ .apply {
+ if (isSuccess) {
+ showSuccess()
+ } else {
+ showError()
+ }
+ }
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt
new file mode 100644
index 0000000000..c9b748cdfa
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/phone/PhoneActivity.kt
@@ -0,0 +1,62 @@
+package com.blankj.utilcode.pkg.feature.phone
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.helper.PermissionHelper
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.PermissionUtils
+import com.blankj.utilcode.util.PhoneUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about PhoneUtils
+ * ```
+ */
+class PhoneActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ PermissionHelper.request(context, object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, PhoneActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ }
+ }, PermissionConstants.PHONE)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_phone
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("isPhone", PhoneUtils.isPhone().toString()),
+ CommonItemTitle("getDeviceId", PhoneUtils.getDeviceId()),
+ CommonItemTitle("getSerial", PhoneUtils.getSerial()),
+ CommonItemTitle("getIMEI", PhoneUtils.getIMEI()),
+ CommonItemTitle("getMEID", PhoneUtils.getMEID()),
+ CommonItemTitle("getIMSI", PhoneUtils.getIMSI()),
+ CommonItemTitle("getPhoneType", PhoneUtils.getPhoneType().toString()),
+ CommonItemTitle("isSimCardReady", PhoneUtils.isSimCardReady().toString()),
+ CommonItemTitle("getSimOperatorName", PhoneUtils.getSimOperatorName()),
+ CommonItemTitle("getSimOperatorByMnc", PhoneUtils.getSimOperatorByMnc()),
+
+ CommonItemClick(R.string.phone_dial) { PhoneUtils.dial("*10000#haha") },
+ CommonItemClick(R.string.phone_call) { PhoneUtils.call("*10000#haha") },
+ CommonItemClick(R.string.phone_send_sms) { PhoneUtils.sendSms("10000", "sendSms") }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/process/ProcessActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/process/ProcessActivity.kt
new file mode 100644
index 0000000000..7753d2f47a
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/process/ProcessActivity.kt
@@ -0,0 +1,67 @@
+package com.blankj.utilcode.pkg.feature.process
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ProcessUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/13
+ * desc : demo about ProcessUtils
+ * ```
+ */
+class ProcessActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ProcessActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_process
+ }
+
+ override fun bindItems(): MutableList> {
+ val set = ProcessUtils.getAllBackgroundProcesses()
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getForegroundProcessName", ProcessUtils.getForegroundProcessName()!!),
+ CommonItemTitle("getAllBackgroundProcesses -> ${set.size}", getSetItems(set)),
+ CommonItemTitle("isMainProcess", ProcessUtils.isMainProcess().toString()),
+ CommonItemTitle("getCurrentProcessName", ProcessUtils.getCurrentProcessName()),
+
+ CommonItemClick(R.string.process_kill_all_background).setOnItemClickListener { _, item, _ ->
+ val bgSet = ProcessUtils.getAllBackgroundProcesses()
+ val killedSet = ProcessUtils.killAllBackgroundProcesses()
+ itemsView.updateItems(
+ CollectionUtils.newArrayList(
+ CommonItemTitle("getForegroundProcessName", ProcessUtils.getForegroundProcessName()),
+ CommonItemTitle("getAllBackgroundProcesses -> ${bgSet.size}", getSetItems(bgSet)),
+ CommonItemTitle("killAllBackgroundProcesses -> ${killedSet.size}", getSetItems(killedSet)),
+ CommonItemTitle("isMainProcess", ProcessUtils.isMainProcess().toString()),
+ CommonItemTitle("getCurrentProcessName", ProcessUtils.getCurrentProcessName()),
+ item
+ )
+ )
+ }
+ )
+ }
+
+ private fun getSetItems(set: Set): String {
+ val iterator = set.iterator()
+ val sb = StringBuilder()
+ while (iterator.hasNext()) {
+ sb.append("\n").append(iterator.next())
+ }
+ return if (sb.isNotEmpty()) sb.deleteCharAt(0).toString() else ""
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/ReflectActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/ReflectActivity.kt
new file mode 100644
index 0000000000..f445acf642
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/ReflectActivity.kt
@@ -0,0 +1,41 @@
+package com.blankj.utilcode.pkg.feature.reflect
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ReflectUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/01/29
+ * desc : demo about ReflectUtils
+ * ```
+ */
+class ReflectActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ReflectActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_reflect
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("source value", TestPrivateStaticFinal.STR),
+ CommonItemTitle("reflect get", ReflectUtils.reflect(TestPrivateStaticFinal::class.java).field("STR").get()),
+ CommonItemTitle("after reflect get", ReflectUtils.reflect(TestPrivateStaticFinal::class.java).field("STR", "reflect success").field("STR").get()),
+ CommonItemTitle("source value", TestPrivateStaticFinal.STR)
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java
new file mode 100644
index 0000000000..b7efb5f4d7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/reflect/TestPrivateStaticFinal.java
@@ -0,0 +1,16 @@
+package com.blankj.utilcode.pkg.feature.reflect;
+
+import androidx.annotation.Keep;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/09/09
+ * desc :
+ *
+ */
+@Keep
+public class TestPrivateStaticFinal {
+ public static final String STR = "str";
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/resource/ResourceActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/resource/ResourceActivity.kt
new file mode 100644
index 0000000000..cf56301068
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/resource/ResourceActivity.kt
@@ -0,0 +1,49 @@
+package com.blankj.utilcode.pkg.feature.resource
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.Config
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ResourceUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/05/07
+ * desc : demo about ResourceUtils
+ * ```
+ */
+class ResourceActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ResourceActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_resource
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("readAssets2String", ResourceUtils.readAssets2String("test/test.txt")),
+ CommonItemTitle("readAssets2List", ResourceUtils.readAssets2List("test/test.txt").toString()),
+ CommonItemTitle("readRaw2List", ResourceUtils.readRaw2List(R.raw.test).toString()),
+
+ CommonItemClick(R.string.resource_copy_file_from_assets_2_cache) {
+ ResourceUtils.copyFileFromAssets("test", Config.CACHE_PATH + "assets/test")
+ },
+ CommonItemClick(R.string.resource_copy_file_from_raw_2_cache) {
+ ResourceUtils.copyFileFromRaw(R.raw.test, Config.CACHE_PATH + "raw/test.txt")
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/rom/RomActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/rom/RomActivity.kt
new file mode 100644
index 0000000000..e2b4a3c7bc
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/rom/RomActivity.kt
@@ -0,0 +1,40 @@
+package com.blankj.utilcode.pkg.feature.rom
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.RomUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/01/29
+ * desc : demo about RomUtils
+ * ```
+ */
+class RomActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, RomActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_rom
+ }
+
+ override fun bindItems(): MutableList> {
+ val romInfo = RomUtils.getRomInfo()
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("Rom Name", romInfo.name),
+ CommonItemTitle("Rom Version", romInfo.version)
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt
new file mode 100644
index 0000000000..88286c4df5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/screen/ScreenActivity.kt
@@ -0,0 +1,101 @@
+package com.blankj.utilcode.pkg.feature.screen
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.widget.ImageView
+import android.widget.TextView
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemSwitch
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.*
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/01/29
+ * desc : demo about RomUtils
+ * ```
+ */
+class ScreenActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ PermissionUtils.requestWriteSettings(object : PermissionUtils.SimpleCallback {
+ override fun onGranted() {
+ val starter = Intent(context, ScreenActivity::class.java)
+ context.startActivity(starter)
+ }
+
+ override fun onDenied() {
+ ToastUtils.showLong("No permission of write settings.")
+ }
+ })
+ } else {
+ val starter = Intent(context, ScreenActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_screen
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("getScreenWidth", ScreenUtils.getScreenWidth().toString()),
+ CommonItemTitle("getScreenHeight", ScreenUtils.getScreenHeight().toString()),
+ CommonItemTitle("getAppScreenWidth", ScreenUtils.getAppScreenWidth().toString()),
+ CommonItemTitle("getAppScreenHeight", ScreenUtils.getAppScreenHeight().toString()),
+ CommonItemTitle("getScreenDensity", ScreenUtils.getScreenDensity().toString()),
+ CommonItemTitle("getScreenDensityDpi", ScreenUtils.getScreenDensityDpi().toString()),
+ CommonItemTitle("getScreenRotation", ScreenUtils.getScreenRotation(this).toString()),
+ CommonItemTitle("isScreenLock", ScreenUtils.isScreenLock().toString()),
+ CommonItemTitle("getSleepDuration", ScreenUtils.getSleepDuration().toString()),
+
+ CommonItemSwitch(
+ "isFullScreen",
+ { ScreenUtils.isFullScreen(this) },
+ {
+ if (it) {
+ ScreenUtils.setFullScreen(this)
+ BarUtils.setStatusBarVisibility(this, false)
+ } else {
+ ScreenUtils.setNonFullScreen(this)
+ BarUtils.setStatusBarVisibility(this, true)
+ }
+ }
+ ),
+ CommonItemSwitch(
+ "isLandscape",
+ { ScreenUtils.isLandscape() },
+ {
+ if (it) {
+ ScreenUtils.setLandscape(this)
+ } else {
+ ScreenUtils.setPortrait(this)
+ }
+ }
+ ),
+ CommonItemClick(R.string.screen_screenshot) {
+ val iv :ImageView = ImageView(this)
+ iv.setImageResource(R.mipmap.ic_launcher)
+
+ val tv: TextView = TextView(this)
+ tv.setText("wowowowwowo")
+
+ DialogHelper.showScreenshotDialog(ImageUtils.view2Bitmap(tv))
+
+// DialogHelper.showScreenshotDialog(ScreenUtils.screenShot(this))
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/sdcard/SDCardActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/sdcard/SDCardActivity.kt
new file mode 100644
index 0000000000..0c51475952
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/sdcard/SDCardActivity.kt
@@ -0,0 +1,46 @@
+package com.blankj.utilcode.pkg.feature.sdcard
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ConvertUtils
+import com.blankj.utilcode.util.SDCardUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/27
+ * desc : demo about SDCardUtils
+ * ```
+ */
+class SDCardActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, SDCardActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_sdcard
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemTitle("isSDCardEnableByEnvironment", SDCardUtils.isSDCardEnableByEnvironment().toString()),
+ CommonItemTitle("getSDCardPathByEnvironment", SDCardUtils.getSDCardPathByEnvironment()),
+ CommonItemTitle("getSDCardInfo", SDCardUtils.getSDCardInfo().toString()),
+ CommonItemTitle("getMountedSDCardPath", SDCardUtils.getMountedSDCardPath().toString()),
+ CommonItemTitle("getExternalTotalSize", ConvertUtils.byte2FitMemorySize(SDCardUtils.getExternalTotalSize(), 2)),
+ CommonItemTitle("getExternalAvailableSize", ConvertUtils.byte2FitMemorySize(SDCardUtils.getExternalAvailableSize(), 2)),
+ CommonItemTitle("getInternalTotalSize", ConvertUtils.byte2FitMemorySize(SDCardUtils.getInternalTotalSize(), 2)),
+ CommonItemTitle("getInternalAvailableSize", ConvertUtils.byte2FitMemorySize(SDCardUtils.getInternalAvailableSize(), 2))
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/shadow/ShadowActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/shadow/ShadowActivity.kt
new file mode 100644
index 0000000000..2ec21ad483
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/shadow/ShadowActivity.kt
@@ -0,0 +1,52 @@
+package com.blankj.utilcode.pkg.feature.shadow
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.ShadowUtils
+import com.blankj.utilcode.util.ShadowUtils.Config
+import com.blankj.utilcode.util.SizeUtils
+import kotlinx.android.synthetic.main.shadow_activity.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/10/22
+ * desc : demo about ShadowUtils
+ * ```
+ */
+class ShadowActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ShadowActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_shadow
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.shadow_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ ShadowUtils.apply(shadowRectView, Config().setShadowColor(0x44000000, 0x55000000))
+ ShadowUtils.apply(shadowRoundRectView, Config().setShadowColor(0x44000000, 0x55000000).setShadowRadius(
+ SizeUtils.dp2px(16f).toFloat()))
+ ShadowUtils.apply(shadowCircleView, Config().setCircle().setShadowColor(0x44000000, 0x55000000))
+
+ ShadowUtils.apply(shadowRectView1, Config().setShadowColor(0x44000000, 0x55000000))
+ ShadowUtils.apply(shadowRoundRectView1, Config().setShadowColor(0x44000000, 0x55000000).setShadowRadius(
+ SizeUtils.dp2px(16f).toFloat()))
+ ShadowUtils.apply(shadowCircleView1, Config().setCircle().setShadowColor(0x44000000, 0x55000000))
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
new file mode 100644
index 0000000000..dcde367a5b
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/snackbar/SnackbarActivity.kt
@@ -0,0 +1,159 @@
+package com.blankj.utilcode.pkg.feature.snackbar
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.text.SpannableStringBuilder
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.annotation.StringRes
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.SnackbarUtils
+import com.blankj.utilcode.util.SpanUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/17
+ * desc : demo about SnackbarUtils
+ * ```
+ */
+class SnackbarActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, SnackbarActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_snackbar
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.snackbar_short) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_short))
+ .setMessageColor(Color.WHITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_short_top) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_short_top))
+ .setMessageColor(Color.WHITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .show(true)
+ },
+ CommonItemClick(R.string.snackbar_short_with_action) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_short_with_action))
+ .setMessageColor(Color.WHITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .setAction(getString(R.string.snackbar_click), Color.YELLOW) { ToastUtils.showShort(getString(R.string.snackbar_click)) }
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_short_with_action_top) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_short_with_action_top))
+ .setMessageColor(Color.WHITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .setAction(getString(R.string.snackbar_click), Color.YELLOW) { ToastUtils.showShort(getString(R.string.snackbar_click)) }
+ .show(true)
+ },
+ CommonItemClick(R.string.snackbar_long) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_long))
+ .setMessageColor(Color.WHITE)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_long_with_action) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_long_with_action))
+ .setMessageColor(Color.WHITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .setDuration(SnackbarUtils.LENGTH_LONG)
+ .setAction(getString(R.string.snackbar_click), Color.YELLOW) { ToastUtils.showShort(getString(R.string.snackbar_click)) }
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_indefinite) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_indefinite))
+ .setMessageColor(Color.WHITE)
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_indefinite_with_action) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_indefinite_with_action))
+ .setMessageColor(Color.WHITE)
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .setBgResource(R.drawable.snackbar_custom_bg)
+ .setAction(getString(R.string.snackbar_click), Color.YELLOW) { ToastUtils.showShort(getString(R.string.snackbar_click)) }
+ .show()
+ },
+ CommonItemClick(R.string.snackbar_add_view) {
+ val params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ SnackbarUtils.with(mContentView)
+ .setBgColor(Color.TRANSPARENT)
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .show()
+ SnackbarUtils.addView(R.layout.snackbar_custom, params)
+ },
+ CommonItemClick(R.string.snackbar_add_view_with_action) {
+ val params: ViewGroup.LayoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ SnackbarUtils.with(mContentView)
+ .setBgColor(Color.TRANSPARENT)
+ .setDuration(SnackbarUtils.LENGTH_INDEFINITE)
+ .show()
+ SnackbarUtils.addView(R.layout.snackbar_custom, params)
+ val snackbarView = SnackbarUtils.getView()
+ if (snackbarView != null) {
+ val tvSnackbarCustom = snackbarView.findViewById(R.id.snackbarCustomTv)
+ tvSnackbarCustom.setText(R.string.snackbar_click_to_dismiss)
+ snackbarView.setOnClickListener { SnackbarUtils.dismiss() }
+ }
+ },
+ CommonItemClick(R.string.snackbar_success) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_success))
+ .showSuccess()
+ },
+ CommonItemClick(R.string.snackbar_warning) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_warning))
+ .showWarning()
+ },
+ CommonItemClick(R.string.snackbar_error) {
+ SnackbarUtils.with(mContentView)
+ .setMessage(getMsg(R.string.snackbar_error))
+ .showError()
+ },
+ CommonItemClick(R.string.snackbar_dismiss) {
+ SnackbarUtils.dismiss()
+ }
+ )
+ }
+
+ private fun getMsg(@StringRes resId: Int): SpannableStringBuilder {
+ return SpanUtils()
+ .appendImage(R.mipmap.ic_launcher, SpanUtils.ALIGN_CENTER)
+ .appendSpace(32)
+ .append(getString(resId)).setFontSize(24, true)
+ .create()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/spStatic/SPStaticActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/spStatic/SPStaticActivity.kt
new file mode 100644
index 0000000000..f0e6abf871
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/spStatic/SPStaticActivity.kt
@@ -0,0 +1,82 @@
+package com.blankj.utilcode.pkg.feature.spStatic
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.SPStaticUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/01/08
+ * desc : demo about SPUtils
+ * ```
+ */
+class SPStaticActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, SPStaticActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_spStatic
+ }
+
+ override fun bindItems(): MutableList> {
+ val itemTitle = CommonItemTitle(sp2String(), true)
+ return CollectionUtils.newArrayList(
+ itemTitle,
+ CommonItemClick(R.string.sp_put_string) {
+ SPStaticUtils.put("STRING", "string")
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_put_int) {
+ SPStaticUtils.put("INT", 21)
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_put_long) {
+ SPStaticUtils.put("LONG", java.lang.Long.MAX_VALUE)
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_put_float) {
+ SPStaticUtils.put("FLOAT", Math.PI.toFloat())
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_put_boolean) {
+ SPStaticUtils.put("BOOLEAN", true)
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_put_string_set) {
+ SPStaticUtils.put("SET", setOf("1", "2"))
+ itemTitle.title = sp2String()
+ },
+ CommonItemClick(R.string.sp_clear) {
+ SPStaticUtils.clear()
+ itemTitle.title = sp2String()
+ }
+ )
+ }
+
+ private fun sp2String(): String {
+ val sb = StringBuilder()
+ val map = SPStaticUtils.getAll()
+ if (map.isEmpty()) return ""
+ for ((key, value) in map) {
+ sb.append("\n")
+ .append(key)
+ .append(": ")
+ .append(value)
+
+ }
+ return sb.deleteCharAt(0).toString()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
new file mode 100644
index 0000000000..84c9f868bb
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/span/SpanActivity.kt
@@ -0,0 +1,285 @@
+package com.blankj.utilcode.pkg.feature.span
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.Intent
+import android.graphics.*
+import android.os.Bundle
+import android.text.Layout
+import android.text.SpannableStringBuilder
+import android.text.TextPaint
+import android.text.style.CharacterStyle
+import android.text.style.ClickableSpan
+import android.text.style.UpdateAppearance
+import android.view.View
+import android.view.animation.LinearInterpolator
+import androidx.annotation.ColorInt
+import com.blankj.common.activity.CommonActivity
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.SpanUtils
+import com.blankj.utilcode.util.ToastUtils
+import kotlinx.android.synthetic.main.span_activity.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/27
+ * desc : demo about SpanUtils
+ * ```
+ */
+class SpanActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, SpanActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ private lateinit var mSpanUtils: SpanUtils
+ private lateinit var animSsb: SpannableStringBuilder
+
+ private var lineHeight: Int = 0
+ private var textSize: Float = 0f
+ private lateinit var valueAnimator: ValueAnimator
+ private lateinit var mShader: Shader
+ private var mShaderWidth: Float = 0f
+ private lateinit var matrix: Matrix
+ private lateinit var mBlurMaskFilterSpan: BlurMaskFilterSpan
+ private lateinit var mShadowSpan: ShadowSpan
+ private lateinit var mForegroundAlphaColorSpan: ForegroundAlphaColorSpan
+ private lateinit var mForegroundAlphaColorSpanGroup: ForegroundAlphaColorSpanGroup
+ private lateinit var mPrinterString: String
+ private var density: Float = 0f
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_span
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.span_activity
+ }
+
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ val clickableSpan = object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ ToastUtils.showShort("事件触发了")
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ ds.color = Color.BLUE
+ ds.isUnderlineText = false
+ }
+ }
+
+ lineHeight = spanAboutTv.lineHeight
+ textSize = spanAboutTv.textSize
+ density = resources.displayMetrics.density
+
+ SpanUtils.with(spanAboutTv)
+ .appendLine("SpanUtils").setBackgroundColor(Color.LTGRAY).setBold().setForegroundColor(Color.YELLOW).setHorizontalAlign(Layout.Alignment.ALIGN_CENTER)
+ .appendLine("前景色").setForegroundColor(Color.GREEN)
+// .appendLine("测试哈哈").setForegroundColor(Color.RED).setBackgroundColor(Color.LTGRAY).setFontSize(10).setLineHeight(280, SpanUtils.ALIGN_BOTTOM)
+ .appendLine("背景色").setBackgroundColor(Color.LTGRAY)
+ .appendLine("行高居中对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_CENTER).setBackgroundColor(Color.LTGRAY)
+ .appendLine("行高底部对齐").setLineHeight(2 * lineHeight, SpanUtils.ALIGN_BOTTOM).setBackgroundColor(Color.GREEN)
+ .appendLine("测试段落缩,首行缩进两字,其他行不缩进").setLeadingMargin(textSize.toInt() * 2, 10).setBackgroundColor(Color.GREEN)
+ .appendLine("测试引用,后面的字是为了凑到两行的效果").setQuoteColor(Color.GREEN, 10, 10).setBackgroundColor(Color.LTGRAY)
+ .appendLine("测试列表项,后面的字是为了凑到两行的效果").setBullet(Color.GREEN, 20, 10).setBackgroundColor(Color.LTGRAY).setBackgroundColor(Color.GREEN)
+ .appendLine("32dp 字体").setFontSize(32, true)
+ .appendLine("2 倍字体").setFontProportion(2f)
+ .appendLine("横向 2 倍字体").setFontXProportion(1.5f)
+ .appendLine("删除线").setStrikethrough()
+ .appendLine("下划线").setUnderline()
+ .append("测试").appendLine("上标").setSuperscript()
+ .append("测试").appendLine("下标").setSubscript()
+ .appendLine("粗体").setBold()
+ .appendLine("斜体").setItalic()
+ .appendLine("粗斜体").setBoldItalic()
+ .appendLine("monospace 字体").setFontFamily("monospace")
+ .appendLine("自定义字体").setTypeface(Typeface.createFromAsset(assets, "fonts/dnmbhs.ttf"))
+ .appendLine("相反对齐").setHorizontalAlign(Layout.Alignment.ALIGN_OPPOSITE)
+ .appendLine("居中对齐").setHorizontalAlign(Layout.Alignment.ALIGN_CENTER)
+ .appendLine("正常对齐").setHorizontalAlign(Layout.Alignment.ALIGN_NORMAL)
+ .append("测试").appendLine("点击事件").setClickSpan(clickableSpan)
+ .append("测试").appendLine("Url").setUrl("https://github.com/Blankj/AndroidUtilCode")
+ .append("测试").appendLine("模糊").setBlur(3f, BlurMaskFilter.Blur.NORMAL)
+ .appendLine("颜色渐变").setShader(LinearGradient(0f, 0f, 64f * density * 4f, 0f, resources.getIntArray(R.array.rainbow), null, Shader.TileMode.REPEAT)).setFontSize(64, true)
+ .appendLine("图片着色").setFontSize(64, true).setShader(BitmapShader(BitmapFactory.decodeResource(resources, R.drawable.span_cheetah), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT))
+ .appendLine("阴影效果").setFontSize(64, true).setBackgroundColor(Color.BLACK).setShadow(24f, 8f, 8f, Color.WHITE)
+
+ .append("小图").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_low, SpanUtils.ALIGN_TOP)
+ .append("顶部").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_low, SpanUtils.ALIGN_CENTER)
+ .append("居中").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_low, SpanUtils.ALIGN_BASELINE)
+ .append("底部").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_low, SpanUtils.ALIGN_BOTTOM)
+ .appendLine("对齐").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_TOP)
+ .append("大图").setBackgroundColor(Color.LTGRAY)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_TOP)
+ .append("顶部").setBackgroundColor(Color.LTGRAY)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_TOP)
+ .appendLine("对齐").setBackgroundColor(Color.LTGRAY)
+
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_CENTER)
+ .append("大图").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_CENTER)
+ .append("居中").setBackgroundColor(Color.GREEN)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_CENTER)
+ .appendLine("对齐").setBackgroundColor(Color.GREEN)
+
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_BOTTOM)
+ .append("大图").setBackgroundColor(Color.LTGRAY)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_BOTTOM)
+ .append("底部").setBackgroundColor(Color.LTGRAY)
+ .appendImage(R.drawable.span_block_high, SpanUtils.ALIGN_BOTTOM)
+ .appendLine("对齐").setBackgroundColor(Color.LTGRAY)
+
+ .append("测试空格").appendSpace(30, Color.LTGRAY).appendSpace(50, Color.GREEN).appendSpace(100).appendSpace(30, Color.LTGRAY).appendSpace(50, Color.GREEN)
+ .create()
+
+ // initAnimSpan();
+ // startAnim();
+ }
+
+ private fun initAnimSpan() {
+ mShaderWidth = 64f * density * 4f
+ mShader = LinearGradient(0f, 0f,
+ mShaderWidth, 0f,
+ resources.getIntArray(R.array.rainbow), null,
+ Shader.TileMode.REPEAT)
+ matrix = Matrix()
+
+ mBlurMaskFilterSpan = BlurMaskFilterSpan(25f)
+
+ mShadowSpan = ShadowSpan(8f, 8f, 8f, Color.WHITE)
+
+ mForegroundAlphaColorSpan = ForegroundAlphaColorSpan(Color.TRANSPARENT)
+
+ mForegroundAlphaColorSpanGroup = ForegroundAlphaColorSpanGroup(0f)
+
+ mPrinterString = "打印动画,后面的文字是为了测试打印效果..."
+
+ mSpanUtils = SpanUtils()
+ .appendLine("彩虹动画").setFontSize(64, true).setShader(mShader)
+ .appendLine("模糊动画").setFontSize(64, true).setSpans(mBlurMaskFilterSpan)
+ .appendLine("阴影动画").setFontSize(64, true).setBackgroundColor(Color.BLACK).setSpans(mShadowSpan)
+ .appendLine("透明动画").setFontSize(64, true).setSpans(mForegroundAlphaColorSpan)
+ var i = 0
+ val len = mPrinterString.length
+ while (i < len) {
+ val span = ForegroundAlphaColorSpan(Color.TRANSPARENT)
+ mSpanUtils.append(mPrinterString.substring(i, i + 1)).setSpans(span)
+ mForegroundAlphaColorSpanGroup.addSpan(span)
+ ++i
+ }
+ animSsb = mSpanUtils.create()
+ }
+
+ private fun startAnim() {
+ valueAnimator = ValueAnimator.ofFloat(0f, 1f)
+ valueAnimator.addUpdateListener { animation ->
+ // shader
+ matrix.reset()
+ matrix.setTranslate(animation.animatedValue as Float * mShaderWidth, 0f)
+ mShader.setLocalMatrix(matrix)
+
+ // blur
+ mBlurMaskFilterSpan.radius = 25 * (1.00001f - animation.animatedValue as Float)
+
+ // shadow
+ mShadowSpan.dx = 16 * (0.5f - animation.animatedValue as Float)
+ mShadowSpan.dy = 16 * (0.5f - animation.animatedValue as Float)
+
+ // alpha
+ mForegroundAlphaColorSpan.setAlpha((255 * animation.animatedValue as Float).toInt())
+
+ // printer
+ mForegroundAlphaColorSpanGroup.alpha = animation.animatedValue as Float
+
+ // showMsg
+ spanAboutAnimTv.text = animSsb
+ }
+
+ valueAnimator.interpolator = LinearInterpolator()
+ valueAnimator.duration = (600 * 3).toLong()
+ valueAnimator.repeatCount = ValueAnimator.INFINITE
+ valueAnimator.start()
+ }
+
+ override fun doBusiness() {}
+
+ override fun onDebouncingClick(view: View) {}
+
+// override fun onDestroy() {
+// if (valueAnimator.isRunning) {
+// valueAnimator.cancel()
+// }
+// super.onDestroy()
+// }
+}
+
+class BlurMaskFilterSpan(private var mRadius: Float) : CharacterStyle(), UpdateAppearance {
+ private var mFilter: MaskFilter? = null
+
+ var radius: Float
+ get() = mRadius
+ set(radius) {
+ mRadius = radius
+ mFilter = BlurMaskFilter(mRadius, BlurMaskFilter.Blur.NORMAL)
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ ds.maskFilter = mFilter
+ }
+}
+
+class ForegroundAlphaColorSpan(@param:ColorInt private var mColor: Int) : CharacterStyle(), UpdateAppearance {
+
+ fun setAlpha(alpha: Int) {
+ mColor = Color.argb(alpha, Color.red(mColor), Color.green(mColor), Color.blue(mColor))
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ ds.color = mColor
+ }
+}
+
+class ForegroundAlphaColorSpanGroup(private val mAlpha: Float) {
+
+ private val mSpans: ArrayList = ArrayList()
+
+ var alpha: Float
+ get() = mAlpha
+ set(alpha) {
+ val size = mSpans.size
+ var total = 1.0f * size.toFloat() * alpha
+ for (index in 0 until size) {
+ val span = mSpans[index]
+ if (total >= 1.0f) {
+ span.setAlpha(255)
+ total -= 1.0f
+ } else {
+ span.setAlpha((total * 255).toInt())
+ total = 0.0f
+ }
+ }
+ }
+
+ fun addSpan(span: ForegroundAlphaColorSpan) {
+ span.setAlpha((mAlpha * 255).toInt())
+ mSpans.add(span)
+ }
+}
+
+class ShadowSpan(private val radius: Float, var dx: Float, var dy: Float, private val shadowColor: Int) : CharacterStyle(), UpdateAppearance {
+
+ override fun updateDrawState(tp: TextPaint) {
+ tp.setShadowLayer(radius, dx, dy, shadowColor)
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
new file mode 100644
index 0000000000..f0b6876ad4
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/CustomToast.kt
@@ -0,0 +1,61 @@
+package com.blankj.utilcode.pkg.feature.toast
+
+import android.widget.TextView
+import androidx.annotation.StringRes
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.StringUtils
+import com.blankj.utilcode.util.ToastUtils
+import com.blankj.utilcode.util.ViewUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/08/31
+ * desc : demo about ToastUtils
+ * ```
+ */
+object CustomToast {
+
+ fun showShort(text: CharSequence) {
+ show(text, false)
+ }
+
+ fun showShort(@StringRes resId: Int) {
+ show(StringUtils.getString(resId), false)
+ }
+
+ fun showShort(@StringRes resId: Int, vararg args: Any) {
+ show(StringUtils.getString(resId, args), false)
+ }
+
+ fun showShort(format: String, vararg args: Any) {
+ show(StringUtils.format(format, args), false)
+ }
+
+ fun showLong(text: CharSequence) {
+ show(text, true)
+ }
+
+ fun showLong(@StringRes resId: Int) {
+ show(StringUtils.getString(resId), true)
+ }
+
+ fun showLong(@StringRes resId: Int, vararg args: Any) {
+ show(StringUtils.getString(resId, args), true)
+ }
+
+ fun showLong(format: String, vararg args: Any) {
+ show(StringUtils.format(format, args), true)
+ }
+
+ private fun show(text: CharSequence, isLong: Boolean) {
+ val textView = ViewUtils.layoutId2View(R.layout.toast_custom) as TextView
+ textView.text = text
+ ToastUtils.make().setDurationIsLong(isLong).show(textView)
+ }
+
+ fun cancel() {
+ ToastUtils.cancel()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
new file mode 100644
index 0000000000..f4267ad3a9
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/toast/ToastActivity.kt
@@ -0,0 +1,101 @@
+package com.blankj.utilcode.pkg.feature.toast
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.view.Gravity
+import androidx.core.content.ContextCompat
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.pkg.helper.DialogHelper
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.ColorUtils
+import com.blankj.utilcode.util.SpanUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/29
+ * desc : demo about ToastUtils
+ * ```
+ */
+class ToastActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, ToastActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_toast
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.toast_show_short) {
+ Thread(Runnable { ToastUtils.showShort(R.string.toast_short) }).start()
+ },
+ CommonItemClick(R.string.toast_show_long) {
+ Thread(Runnable { ToastUtils.showLong(R.string.toast_long) }).start()
+ },
+ CommonItemClick(R.string.toast_show_null) {
+ ToastUtils.showLong(null)
+ },
+ CommonItemClick(R.string.toast_show_empty) {
+ ToastUtils.showLong("")
+ },
+ CommonItemClick(R.string.toast_show_span) {
+ ToastUtils.showLong(
+ SpanUtils()
+ .appendImage(R.mipmap.ic_launcher, SpanUtils.ALIGN_CENTER)
+ .appendSpace(32)
+ .append(getString(R.string.toast_span)).setFontSize(24, true)
+ .create()
+ )
+ },
+ CommonItemClick(R.string.toast_show_long_string) {
+ ToastUtils.showLong(R.string.toast_long_string)
+ },
+ CommonItemClick(R.string.toast_show_green_font) {
+ ToastUtils.make().setTextColor(Color.GREEN).setDurationIsLong(true).show(R.string.toast_green_font)
+ },
+ CommonItemClick(R.string.toast_show_bg_color) {
+ ToastUtils.make().setBgColor(ColorUtils.getColor(R.color.colorAccent)).show(R.string.toast_bg_color)
+ },
+ CommonItemClick(R.string.toast_show_bg_resource) {
+ ToastUtils.make().setBgResource(R.drawable.toast_round_rect).show(R.string.toast_custom_bg)
+ },
+ CommonItemClick(R.string.toast_show_left_icon) {
+ ToastUtils.make().setLeftIcon(R.mipmap.ic_launcher).show(R.string.toast_show_left_icon)
+ },
+ CommonItemClick(R.string.toast_show_dark_mode) {
+ ToastUtils.make().setTopIcon(R.mipmap.ic_launcher).setMode(ToastUtils.MODE.DARK).show(R.string.toast_show_dark_mode)
+ },
+ CommonItemClick(R.string.toast_show_middle) {
+ ToastUtils.make().setGravity(Gravity.CENTER, 0, 0).show(R.string.toast_middle)
+ },
+ CommonItemClick(R.string.toast_show_top) {
+ ToastUtils.make().setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 0).show(R.string.toast_top)
+ },
+ CommonItemClick(R.string.toast_show_custom_view) {
+ Thread(Runnable { CustomToast.showLong(R.string.toast_custom_view) }).start()
+ },
+ CommonItemClick(R.string.toast_cancel) {
+ ToastUtils.cancel()
+ },
+ CommonItemClick(R.string.toast_show_toast_dialog) {
+ DialogHelper.showToastDialog()
+ },
+ CommonItemClick(R.string.toast_show_toast_when_start_activity) {
+ ToastUtils.showLong(R.string.toast_show_toast_when_start_activity)
+ start(this)
+ }
+ )
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/uiMessage/UiMessageActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/uiMessage/UiMessageActivity.kt
new file mode 100644
index 0000000000..a486645654
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/uiMessage/UiMessageActivity.kt
@@ -0,0 +1,78 @@
+package com.blankj.utilcode.pkg.feature.uiMessage
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.common.item.CommonItemTitle
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.UiMessageUtils
+
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2020/04/14
+ * desc : demo about UiMessageUtils
+ * ```
+ */
+class UiMessageActivity : CommonActivity(), UiMessageUtils.UiMessageCallback {
+
+ private val titleItem: CommonItemTitle = CommonItemTitle("", true);
+ private var sendContent: String = ""
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, UiMessageActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_uiMessage
+ }
+
+ override fun bindItems(): List> {
+ return CollectionUtils.newArrayList(
+ titleItem,
+ CommonItemClick(R.string.uiMessage_add_listener_id) {
+ UiMessageUtils.getInstance().addListener(R.id.utilCodeUiMessageAddListenerId, this)
+ },
+ CommonItemClick(R.string.uiMessage_remove_all_id) {
+ UiMessageUtils.getInstance().removeListeners(R.id.utilCodeUiMessageAddListenerId)
+ },
+ CommonItemClick(R.string.uiMessage_add_listener) {
+ UiMessageUtils.getInstance().addListener(this)
+ },
+ CommonItemClick(R.string.uiMessage_remove_listener) {
+ UiMessageUtils.getInstance().removeListener(this)
+ },
+ CommonItemClick(R.string.uiMessage_send) {
+ sendContent = "send: UiMessageActivity#${UiMessageActivity.hashCode()}"
+ titleItem.title = ""
+ UiMessageUtils.getInstance().send(R.id.utilCodeUiMessageAddListenerId, UiMessageActivity)
+ }
+ )
+ }
+
+ override fun handleMessage(localMessage: UiMessageUtils.UiMessage) {
+ if (localMessage.id == R.id.utilCodeUiMessageAddListenerId) {
+ var content: String = sendContent
+ content += "\nreceive: UiMessageActivity#${localMessage.getObject().hashCode()}"
+ titleItem.title = if (titleItem.title.toString().isEmpty()) {
+ content
+ } else {
+ titleItem.title.toString() + "\n" + content
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ UiMessageUtils.getInstance().removeListeners(R.id.utilCodeUiMessageAddListenerId)
+ UiMessageUtils.getInstance().removeListener(this)
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt
new file mode 100644
index 0000000000..5dc337bc5b
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/vibrate/VibrateActivity.kt
@@ -0,0 +1,66 @@
+package com.blankj.utilcode.pkg.feature.vibrate
+
+import android.content.Context
+import android.content.Intent
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.VibrateUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/12/29
+ * desc : demo about VibrateUtils
+ * ```
+ */
+class VibrateActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, VibrateActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_vibrate
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ CommonItemClick(R.string.vibrate_1000ms) {
+ VibrateUtils.vibrate(1000)
+ },
+ CommonItemClick(R.string.vibrate_custom) {
+ VibrateUtils.vibrate(longArrayOf(0, 1000, 1000, 2000, 2000, 1000), 1)
+ },
+ CommonItemClick(R.string.vibrate_background) {
+ backHome()
+ mContentView.postDelayed({
+// VibrateUtils.vibrate(1000) -- can not vibrate in background
+ VibrateUtils.vibrateCompat(longArrayOf(0, 1000, 1000, 2000, 2000, 1000), 1)
+// VibrateUtils.vibrateCompat(1000)
+ }, 1000)
+ },
+ CommonItemClick(R.string.vibrate_cancel) {
+ VibrateUtils.cancel()
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ VibrateUtils.cancel()
+ }
+
+ private fun backHome() {
+ val intent = Intent(Intent.ACTION_MAIN).apply {
+ addCategory(Intent.CATEGORY_HOME)
+ }
+ startActivity(intent)
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
new file mode 100644
index 0000000000..26d67dda07
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
@@ -0,0 +1,63 @@
+package com.blankj.utilcode.pkg.feature.volume
+
+import android.content.Context
+import android.content.Intent
+import android.media.AudioManager
+import android.widget.SeekBar
+import com.blankj.common.activity.CommonActivity
+import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemSeekBar
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.VolumeUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/12/29
+ * desc : demo about VibrateUtils
+ * ```
+ */
+class VolumeActivity : CommonActivity() {
+
+ companion object {
+ fun start(context: Context) {
+ val starter = Intent(context, VolumeActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+
+ override fun bindTitleRes(): Int {
+ return R.string.demo_volume
+ }
+
+ override fun bindItems(): MutableList> {
+ return CollectionUtils.newArrayList(
+ getItemSeekBar("Voice Call", AudioManager.STREAM_VOICE_CALL),
+ getItemSeekBar("System", AudioManager.STREAM_SYSTEM),
+ getItemSeekBar("Music", AudioManager.STREAM_MUSIC),
+ getItemSeekBar("Ring", AudioManager.STREAM_RING),
+ getItemSeekBar("Alarm", AudioManager.STREAM_ALARM),
+ getItemSeekBar("Notification", AudioManager.STREAM_NOTIFICATION),
+ getItemSeekBar("Dtmf", AudioManager.STREAM_DTMF)
+ )
+ }
+
+ private fun getItemSeekBar(title: CharSequence, streamType: Int): CommonItemSeekBar {
+ return CommonItemSeekBar(title, VolumeUtils.getMaxVolume(streamType), object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return VolumeUtils.getVolume(streamType)
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ VolumeUtils.setVolume(streamType, progress, AudioManager.FLAG_SHOW_UI)
+ }
+ })
+ }
+
+ override fun onResume() {
+ super.onResume()
+ itemsView.updateItems(bindItems())
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
new file mode 100644
index 0000000000..7d38fda3ca
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/helper/DialogHelper.kt
@@ -0,0 +1,158 @@
+package com.blankj.utilcode.pkg.helper
+
+import android.content.Context
+import android.content.DialogInterface
+import android.graphics.Bitmap
+import android.graphics.drawable.ColorDrawable
+import android.text.method.ScrollingMovementMethod
+import android.view.Gravity
+import android.view.View
+import android.view.Window
+import android.widget.Button
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.fragment.app.FragmentActivity
+import com.blankj.base.dialog.BaseDialogFragment
+import com.blankj.base.dialog.DialogLayoutCallback
+import com.blankj.utilcode.pkg.R
+import com.blankj.utilcode.util.ActivityUtils
+import com.blankj.utilcode.util.KeyboardUtils
+import com.blankj.utilcode.util.ScreenUtils
+import com.blankj.utilcode.util.ToastUtils
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/01/10
+ * desc : helper about dialog
+ * ```
+ */
+object DialogHelper {
+
+ fun showKeyboardDialog(context: Context) {
+ BaseDialogFragment().init(context, object : DialogLayoutCallback {
+ override fun bindTheme(): Int {
+ return View.NO_ID
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.keyboard_dialog
+ }
+
+ override fun initView(dialog: BaseDialogFragment, contentView: View) {
+ dialog.dialog.setCanceledOnTouchOutside(false)
+
+ val keyboardDialogEt = contentView.findViewById(R.id.keyboardDialogEt)
+ val listener = View.OnClickListener { v ->
+ when (v.id) {
+ R.id.keyboardDialogHideSoftInputBtn -> KeyboardUtils.hideSoftInput(keyboardDialogEt)
+ R.id.keyboardDialogShowSoftInputBtn -> KeyboardUtils.showSoftInput(keyboardDialogEt)
+ R.id.keyboardDialogToggleSoftInputBtn -> KeyboardUtils.toggleSoftInput()
+ R.id.keyboardDialogCloseBtn -> {
+ KeyboardUtils.hideSoftInput(keyboardDialogEt)
+ dialog.dismiss()
+ }
+ }
+ }
+ contentView.findViewById(R.id.keyboardDialogHideSoftInputBtn).setOnClickListener(listener)
+ contentView.findViewById(R.id.keyboardDialogShowSoftInputBtn).setOnClickListener(listener)
+ contentView.findViewById(R.id.keyboardDialogToggleSoftInputBtn).setOnClickListener(listener)
+ contentView.findViewById(R.id.keyboardDialogCloseBtn).setOnClickListener(listener)
+
+ dialog.dialog.setOnShowListener(DialogInterface.OnShowListener {
+ KeyboardUtils.fixAndroidBug5497(dialog.dialog.window!!)
+ KeyboardUtils.showSoftInput()
+ })
+ }
+
+ override fun setWindowStyle(window: Window) {
+ window.setBackgroundDrawable(ColorDrawable(0))
+ val attributes = window.attributes
+ attributes.gravity = Gravity.BOTTOM
+ attributes.width = ScreenUtils.getAppScreenWidth()
+ attributes.height = ScreenUtils.getAppScreenHeight() * 2 / 5
+ attributes.windowAnimations = R.style.BottomDialogAnimation
+ window.attributes = attributes
+ }
+
+ override fun onCancel(dialog: BaseDialogFragment) {}
+
+ override fun onDismiss(dialog: BaseDialogFragment) {}
+ }).show()
+ }
+
+ fun showFragmentDialog(info: CharSequence) {
+ val topActivity = ActivityUtils.getTopActivity() ?: return
+ BaseDialogFragment().init(topActivity as FragmentActivity, object : DialogLayoutCallback {
+ override fun bindTheme(): Int {
+ return R.style.CommonContentDialogStyle
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.fragment_dialog
+ }
+
+ override fun initView(dialog: BaseDialogFragment, contentView: View) {
+ val aboutTv = contentView.findViewById(R.id.fragmentDialogAboutTv)
+ aboutTv.movementMethod = ScrollingMovementMethod.getInstance()
+ aboutTv.text = info
+ }
+
+ override fun setWindowStyle(window: Window) {}
+
+ override fun onCancel(dialog: BaseDialogFragment) {}
+
+ override fun onDismiss(dialog: BaseDialogFragment) {}
+ }).show()
+ }
+
+ fun showScreenshotDialog(screenshot: Bitmap) {
+ val topActivity = ActivityUtils.getTopActivity() ?: return
+ BaseDialogFragment().init(topActivity as FragmentActivity, object : DialogLayoutCallback {
+ override fun bindTheme(): Int {
+ return R.style.CommonContentDialogStyle
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.screen_dialog
+ }
+
+ override fun initView(dialog: BaseDialogFragment, contentView: View) {
+ contentView.findViewById(R.id.screenDialogScreenshotIv)
+ .setImageBitmap(screenshot)
+ }
+
+ override fun setWindowStyle(window: Window) {}
+
+ override fun onCancel(dialog: BaseDialogFragment) {}
+
+ override fun onDismiss(dialog: BaseDialogFragment) {}
+ }).show()
+ }
+
+ fun showToastDialog() {
+ val topActivity = ActivityUtils.getTopActivity() ?: return
+ BaseDialogFragment().init(topActivity as FragmentActivity, object : DialogLayoutCallback {
+ override fun bindTheme(): Int {
+ return R.style.CommonContentDialogStyle
+ }
+
+ override fun bindLayout(): Int {
+ return R.layout.toast_dialog
+ }
+
+ override fun initView(dialog: BaseDialogFragment, contentView: View) {
+ contentView.findViewById(R.id.toastDialogShowShortToastBtn)
+ .setOnClickListener { ToastUtils.showShort("Short") }
+ }
+
+ override fun setWindowStyle(window: Window) {}
+
+ override fun onCancel(dialog: BaseDialogFragment) {}
+
+ override fun onDismiss(dialog: BaseDialogFragment) {}
+ }).show()
+ }
+}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/fade_in_1000.xml b/feature/utilcode/pkg/src/main/res/anim/fade_in_1000.xml
new file mode 100644
index 0000000000..644fafcbad
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/fade_in_1000.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/fade_out_1000.xml b/feature/utilcode/pkg/src/main/res/anim/fade_out_1000.xml
new file mode 100644
index 0000000000..30b74cb723
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/fade_out_1000.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/slide_bottom_in_200.xml b/feature/utilcode/pkg/src/main/res/anim/slide_bottom_in_200.xml
new file mode 100755
index 0000000000..a3012c2433
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/slide_bottom_in_200.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/slide_bottom_out_200.xml b/feature/utilcode/pkg/src/main/res/anim/slide_bottom_out_200.xml
new file mode 100755
index 0000000000..758f8def70
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/slide_bottom_out_200.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/slide_left_out_1000.xml b/feature/utilcode/pkg/src/main/res/anim/slide_left_out_1000.xml
new file mode 100755
index 0000000000..6c000c2b30
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/slide_left_out_1000.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/anim/slide_right_in_1000.xml b/feature/utilcode/pkg/src/main/res/anim/slide_right_in_1000.xml
new file mode 100755
index 0000000000..f70f611fd5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/anim/slide_right_in_1000.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_enter.xml b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_enter.xml
new file mode 100644
index 0000000000..337e78d490
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_enter.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_exit.xml b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_exit.xml
new file mode 100644
index 0000000000..3c36fd51f7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_left_exit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_enter.xml b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_enter.xml
new file mode 100644
index 0000000000..eaa8aa9c26
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_enter.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_exit.xml b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_exit.xml
new file mode 100644
index 0000000000..1bed31ecb6
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/animator/fragment_slide_right_exit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/activity_activity_icon.png b/feature/utilcode/pkg/src/main/res/drawable/activity_activity_icon.png
new file mode 100644
index 0000000000..d57cc202c9
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/drawable/activity_activity_icon.png differ
diff --git a/feature/utilcode/pkg/src/main/res/drawable/activity_activity_logo.png b/feature/utilcode/pkg/src/main/res/drawable/activity_activity_logo.png
new file mode 100644
index 0000000000..e38d972b63
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/drawable/activity_activity_logo.png differ
diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml
new file mode 100644
index 0000000000..50a4898a07
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_custom.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_alpha.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_alpha.xml
new file mode 100644
index 0000000000..cd1aae4cd2
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_alpha.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_color.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_color.xml
new file mode 100644
index 0000000000..673c00eb93
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_color.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_custom.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_custom.xml
new file mode 100644
index 0000000000..c30e563602
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_custom.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_image.xml b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_image.xml
new file mode 100644
index 0000000000..a14f3af0a4
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/bar_status_nav_image.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/fragment_nav.xml b/feature/utilcode/pkg/src/main/res/drawable/fragment_nav.xml
new file mode 100644
index 0000000000..353532f4c7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/fragment_nav.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/image_lena.jpg b/feature/utilcode/pkg/src/main/res/drawable/image_lena.jpg
new file mode 100644
index 0000000000..ad90c8f96d
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/drawable/image_lena.jpg differ
diff --git a/feature/utilcode/pkg/src/main/res/drawable/keyboard_dialog_bg.xml b/feature/utilcode/pkg/src/main/res/drawable/keyboard_dialog_bg.xml
new file mode 100644
index 0000000000..f236825e67
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/keyboard_dialog_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/shadow_circle.xml b/feature/utilcode/pkg/src/main/res/drawable/shadow_circle.xml
new file mode 100644
index 0000000000..7abb0e7159
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/shadow_circle.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/shadow_round_rect.xml b/feature/utilcode/pkg/src/main/res/drawable/shadow_round_rect.xml
new file mode 100644
index 0000000000..576688b254
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/shadow_round_rect.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/snackbar_custom_bg.xml b/feature/utilcode/pkg/src/main/res/drawable/snackbar_custom_bg.xml
new file mode 100644
index 0000000000..729e6a4065
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/snackbar_custom_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/span_block_high.xml b/feature/utilcode/pkg/src/main/res/drawable/span_block_high.xml
new file mode 100644
index 0000000000..22775a2e99
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/span_block_high.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/span_block_low.xml b/feature/utilcode/pkg/src/main/res/drawable/span_block_low.xml
new file mode 100644
index 0000000000..991a401c7f
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/span_block_low.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/drawable/span_cheetah.png b/feature/utilcode/pkg/src/main/res/drawable/span_cheetah.png
new file mode 100755
index 0000000000..dcdf7de131
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/drawable/span_cheetah.png differ
diff --git a/feature/utilcode/pkg/src/main/res/drawable/toast_round_rect.xml b/feature/utilcode/pkg/src/main/res/drawable/toast_round_rect.xml
new file mode 100644
index 0000000000..d2176a3488
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/drawable/toast_round_rect.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml b/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
new file mode 100644
index 0000000000..278fe8c2c6
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/activity_adaptscreen.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/activity_item_shared_element_activity.xml b/feature/utilcode/pkg/src/main/res/layout/activity_item_shared_element_activity.xml
new file mode 100644
index 0000000000..1ae0c3f964
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/activity_item_shared_element_activity.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/activity_sub_activity.xml b/feature/utilcode/pkg/src/main/res/layout/activity_sub_activity.xml
new file mode 100644
index 0000000000..96ad7a773d
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/activity_sub_activity.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml
new file mode 100644
index 0000000000..2f8476a4a0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_close_activity.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml
new file mode 100644
index 0000000000..75fa87e8e5
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_height_activity.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml
new file mode 100644
index 0000000000..b6bfdb2c80
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/adaptscreen_width_activity.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_activity.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_activity.xml
new file mode 100644
index 0000000000..0e44e92e02
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_activity.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_fragment.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_fragment.xml
new file mode 100644
index 0000000000..8ee1ca308c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_alpha_fragment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_color_fragment.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_color_fragment.xml
new file mode 100644
index 0000000000..9a9ec8f3d8
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_color_fragment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_custom_fragment.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_custom_fragment.xml
new file mode 100644
index 0000000000..33a8f1e431
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_custom_fragment.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_drawer_activity.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_drawer_activity.xml
new file mode 100644
index 0000000000..9f0324e6a0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_drawer_activity.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml
new file mode 100644
index 0000000000..16518fc22f
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_fragment_activity.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_activity.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_activity.xml
new file mode 100644
index 0000000000..deb777407e
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_activity.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_fragment.xml b/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_fragment.xml
new file mode 100644
index 0000000000..f7cc6202c7
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/bar_status_image_view_fragment.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_activity.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_activity.xml
new file mode 100644
index 0000000000..ab89e8e725
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_activity.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_child.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_child.xml
new file mode 100644
index 0000000000..46d08d7b82
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_child.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_container.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_container.xml
new file mode 100644
index 0000000000..46d08d7b82
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_container.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_dialog.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_dialog.xml
new file mode 100644
index 0000000000..7e8aa92c9a
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_dialog.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_item_shared_element.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_item_shared_element.xml
new file mode 100644
index 0000000000..bd06cf49d4
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_item_shared_element.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/fragment_root.xml b/feature/utilcode/pkg/src/main/res/layout/fragment_root.xml
new file mode 100644
index 0000000000..1eabb1b936
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/fragment_root.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/keyboard_activity.xml b/feature/utilcode/pkg/src/main/res/layout/keyboard_activity.xml
new file mode 100644
index 0000000000..947b981509
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/keyboard_activity.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/keyboard_dialog.xml b/feature/utilcode/pkg/src/main/res/layout/keyboard_dialog.xml
new file mode 100644
index 0000000000..35493183f8
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/keyboard_dialog.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml b/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml
new file mode 100644
index 0000000000..d594eb654d
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/mvp_activity.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/screen_dialog.xml b/feature/utilcode/pkg/src/main/res/layout/screen_dialog.xml
new file mode 100644
index 0000000000..e5644ddac0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/screen_dialog.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/layout/shadow_activity.xml b/feature/utilcode/pkg/src/main/res/layout/shadow_activity.xml
new file mode 100644
index 0000000000..c8fca04657
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/shadow_activity.xml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/snackbar_custom.xml b/feature/utilcode/pkg/src/main/res/layout/snackbar_custom.xml
new file mode 100644
index 0000000000..10dbc26c7f
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/snackbar_custom.xml
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/span_activity.xml b/feature/utilcode/pkg/src/main/res/layout/span_activity.xml
new file mode 100644
index 0000000000..a94de917fe
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/span_activity.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/toast_custom.xml b/feature/utilcode/pkg/src/main/res/layout/toast_custom.xml
new file mode 100644
index 0000000000..6bc4d999af
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/toast_custom.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/layout/toast_dialog.xml b/feature/utilcode/pkg/src/main/res/layout/toast_dialog.xml
new file mode 100644
index 0000000000..e926cd1201
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/layout/toast_dialog.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/menu/fragment_nav.xml b/feature/utilcode/pkg/src/main/res/menu/fragment_nav.xml
new file mode 100644
index 0000000000..617a39bf0f
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/menu/fragment_nav.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/menu/status_bar_nav.xml b/feature/utilcode/pkg/src/main/res/menu/status_bar_nav.xml
new file mode 100644
index 0000000000..0dd52fbcf9
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/menu/status_bar_nav.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/utilcode/pkg/src/main/res/raw/test.txt b/feature/utilcode/pkg/src/main/res/raw/test.txt
new file mode 100644
index 0000000000..f7bc1649eb
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/raw/test.txt
@@ -0,0 +1,2 @@
+1st line
+2nd line
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/transition/explode_1000.xml b/feature/utilcode/pkg/src/main/res/transition/explode_1000.xml
new file mode 100644
index 0000000000..a87f4cb83c
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/transition/explode_1000.xml
@@ -0,0 +1,3 @@
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/transition/fade_1000.xml b/feature/utilcode/pkg/src/main/res/transition/fade_1000.xml
new file mode 100644
index 0000000000..81b43c210e
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/transition/fade_1000.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/feature/utilcode/pkg/src/main/res/transition/slide_1000.xml b/feature/utilcode/pkg/src/main/res/transition/slide_1000.xml
new file mode 100644
index 0000000000..ece4260af9
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/transition/slide_1000.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml b/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml
new file mode 100644
index 0000000000..20efc6c063
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/values-en-rUS/strings.xml
@@ -0,0 +1,12 @@
+
+
+
+ Language Demo
+
+ Apply Simple Chinese
+ Apply American
+ Apply English
+ Apply Arabic
+ Apply System
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml b/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000..e06759a6d0
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,12 @@
+
+
+
+ 语言例子
+
+ 设置简体中文
+ 设置美语
+ 设置英语
+ 设置阿拉伯语
+ 设置系统语言
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/values/ids.xml b/feature/utilcode/pkg/src/main/res/values/ids.xml
new file mode 100644
index 0000000000..00728ce459
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/values/ids.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/res/values/strings.xml b/feature/utilcode/pkg/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..551f9adbaf
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/values/strings.xml
@@ -0,0 +1,371 @@
+
+
+ ActivityUtils Demo
+ AdaptScreenUtils Demo
+ ApiUtils Demo
+ AppUtils Demo
+ BarUtils Demo
+ BrightnessUtils Demo
+ BusUtils Demo
+ CleanUtils Demo
+ ClickUtils Demo
+ ClipboardUtils Demo
+ CrashUtils Demo
+ DeviceUtils Demo
+ FileUtils Demo
+ FlashlightUtils Demo
+ FragmentUtils Demo
+ ImageUtils Demo
+ IntentUtils Demo
+ KeyboardUtils Demo
+ Language Demo
+ LogUtils Demo
+ MessengerUtils Demo
+ MetaDataUtils Demo
+ Mvp Demo
+ NetworkUtils Demo
+ PathUtils Demo
+ Notification Demo
+ PermissionUtils Demo
+ PhoneUtils Demo
+ ProcessUtils Demo
+ ReflectUtils Demo
+ ResourceUtils Demo
+ ScreenUtils Demo
+ RomUtils Demo
+ SDCardUtils Demo
+ Shadow Demo
+ SnackbarUtils Demo
+ SPStaticUtils Demo
+ SpanUtils Demo
+ ToastUtils Demo
+ UiMessage Demo
+ TransActivity Demo
+ VibrateUtils Demo
+ VolumeUtils Demo
+
+
+ Shared Element
+ Clz
+ Clz Opt
+ Clz Anim
+ Act Clz
+ Act Clz Opt
+ Act Clz Shared Element
+ Act Clz Anim
+ Pkg Cls
+ Pkg Cls Opt
+ Pkg Cls Anim
+ Act Pkg Cls
+ Act Pkg Cls Opt
+ Act Pkg Cls Shared Element
+ Act Pkg Cls Anim
+ Intent
+ Intent Opt
+ Intent Shared Element
+ Intent Anim
+ Intents
+ Intents Opt
+ Intents Anim
+ Act Intents
+ Act Intents Opt
+ Act Intents Anim
+ Start Activities
+ Start Home Activity
+ Start Launcher Activity
+ Finish CoreUtilActivity
+ Finish To CoreUtilActivity
+ Finish All Activities Except Newest
+ Finish All Activities
+
+
+ Invoke With Params
+ Invoke With Return Value
+ Post Bus
+
+
+ Install Test App
+ Test app have installed
+ Install successfully
+ Install unsuccessfully
+ Uninstall Test App
+ Please install test app first
+ Uninstall successfully
+ Uninstall unsuccessfully
+ Launch App
+ Relaunch App
+ Launch App Details Settings
+ Exit App
+
+
+ Adapt Width
+ Adapt Height
+ Close Adapt pt equals dp
+
+
+ About Status Bar
+ About Nav Bar
+ About Notification Bar
+
+ About Status
+ Status Visibility
+ Light Mode
+ Set Color
+ Set Alpha
+ Set Image View
+ Set Custom
+ Set Fragment
+ Set Drawer
+ Random Color
+ Set Transparent
+ Color
+ Alpha
+ Front
+ Image
+ Custom
+
+ About Notification
+ Show Notification And Hide After 2s
+
+ About Nav
+ Nav Visibility
+ Light Mode
+ Set Nav Color Random
+
+
+ Auto Brightness
+
+
+ Clean Internal Cache
+ Clean Internal Files
+ Clean Internal Databases
+ Clean Internal SP
+ Clean External Cache
+ cleanAppUserData
+
+
+ Click View Scale Default
+ Click View Scale 50%
+ Click View Alpha Default
+ Click Bg Alpha Default
+ Click Bg Dark Default
+ Click Global Debouncing
+ Click Single Debouncing
+ Click Multi
+ The view does not respond to clicks within 5 seconds.
+ The views which set global debouncing does not respond to clicks within 5 seconds.
+
+
+
+ Register
+ Unregister
+ Post
+ Post Basic Type
+ Post Sticky
+ Post To IO Thread
+ Remove Sticky
+ Start BusUtils Vs EventBus
+ Compare Register 10000 Times
+ Compare Post To 1 Subscriber 1000000 Times
+ Compare Post To 100 Subscribers 100000 Times
+ Compare Unregister 10000 Times
+
+
+ Flashlight Status
+
+
+ Fragment0
+ Fragment1
+ Fragment2
+ Show Stack
+ Add Child
+ Add Child Stack
+ Add Hide
+ Add Hide Stack
+ Add Demo1 Show
+ Pop
+ Remove
+ Pop To Root
+ Hide Demo0 Show Demo1
+ Hide Demo1 Show Demo0
+ Replace
+ Transition
+
+
+ Src
+ Add Color
+ Scale
+ Clip
+ Skew
+ Rotate
+ To Round
+ To Round Border
+ To Round Corner
+ To Round Corner Border
+ Add Corner Border
+ Add Circle Border
+ Add Reflection
+ Add Text Watermark
+ Add Image Watermark
+ Gray
+ Fast Blur
+ Render Script Blur
+ Stack Blur
+ Compress By Scale
+ Compress By Quality Half
+ Compress By Quality Max Size
+ Compress By Sample Size
+
+
+
+ Open Wireless Settings
+ Mobile Data Enabled
+ Wifi Enabled
+
+
+ Hide Soft Input
+ Show Soft Input
+ Toggle Soft Input
+ Show Dialog
+ Close Dialog
+
+
+ Relaunch App
+ Apply Simple Chinese
+ Apply American
+ Apply English
+ Apply Arabic
+ Apply System
+
+
+ Log Switch
+ Console Switch
+ Console Listener Switch
+ Head Switch
+ File Switch
+ File Listener Switch
+ Border Switch
+ Single Tag Switch
+ Log With No Tag
+ Log With Tag
+ Log In New Thread
+ Log Null
+ Log Many Params
+ Log Long String
+ Log To File
+ Log Json
+ Log Xml
+ Log Array
+ Log Throwable
+ Log Bundle
+ Log Intent
+ Log Array List
+ Log Map
+
+
+ Post To Main Server
+ Post To Self Client
+ Start Remote
+ Register Remote client
+ Unregister Remote Client
+
+
+ Notify
+ Cancel
+ Cancel All
+ Show
+
+
+ Open App Settings
+ Calendar Status
+ Record Audio Status
+ Calendar And Record Audio Status
+ Write Settings Status
+ Draw Overlays Status
+
+
+
+ Dial
+ Call
+ Send SMS
+
+
+ Kill All Background Processes
+
+
+ Copy File From Assets to Cache
+ Copy File From Raw to Cache
+
+
+ Screenshot
+
+
+ Short Snackbar
+ Short Snackbar Top
+ Short Snackbar With Action
+ Short Snackbar With Action Top
+ Long Snackbar
+ Long Snackbar With Action
+ Indefinite Snackbar
+ Indefinite Snackbar With Action
+ Add View
+ Add View With Action
+ Success
+ Warning
+ Error
+ Dismiss Snackbar
+ Click
+ Custom View
+ Click To Dismiss
+
+
+ Put String
+ Put Int
+ Put Long
+ Put Float
+ Put Boolean
+ Put String Set
+ Clear
+
+
+ Show Short
+ Show Long
+ Show Null
+ Show Empty
+ Show Green Font
+ Show Bg Color
+ Show Bg Resource
+ Show Span
+ Show Left Icon
+ Show Dark Mode
+ Show Long String
+ A toast is a view containing a quick little message for the user. The ToastUtils class helps you create and show those.
+ Show Custom View
+ Custom View
+ Show Middle
+ Show Top
+ Cancel
+ Show Toast Dialog
+ Show Toast When Start Activity
+ Short
+ Long
+ Green Font
+ Bg Color
+ Custom Bg
+ Spannable String
+ Middle
+ Top
+
+
+ Add Listener Id
+ Remove All Id
+ Add Listener
+ Remove Listener
+ Send
+
+
+ Vibrate 1000ms
+ Vibrate Custom
+ Vibrate Background
+ Cancel
+
diff --git a/feature/utilcode/pkg/src/main/res/values/styles.xml b/feature/utilcode/pkg/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..a92300c878
--- /dev/null
+++ b/feature/utilcode/pkg/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000000..b9d5f2bcbf
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,26 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+#org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
+
+android.enableJetifier=true
+android.useAndroidX=true
+
+org.gradle.jvmargs=-Xmx8192m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -XX:-UseGCOverheadLimit -Dfile.encoding=UTF-8
+org.gradle.daemon=true
+#org.gradle.configureondemand=true
+org.gradle.parallel=true
+org.gradle.caching=true
+
+#-Dorg.gradle.debug=true --no-daemon
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..5c2d1cf016
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..1e0ae1a108
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 06 10:07:23 CST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..b0d6d0ab5d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..15e1ee37a7
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/base/.gitignore b/lib/base/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/lib/base/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/lib/base/build.gradle b/lib/base/build.gradle
new file mode 100644
index 0000000000..b7eb9d588c
--- /dev/null
+++ b/lib/base/build.gradle
@@ -0,0 +1,14 @@
+dependencies {
+ api Config.modules.lib_subutil.dep
+ api Config.modules.lib_utilcode.dep
+
+ api Config.libs.androidx_appcompat.path
+ api Config.libs.androidx_material.path
+ api Config.libs.androidx_multidex.path
+ api Config.libs.androidx_constraint.path
+ api Config.libs.kotlin.path
+ api Config.libs.free_proguard.path
+ api Config.libs.swipe_panel.path
+ api Config.libs.eventbus_lib.path
+ compileOnly Config.modules.lib_utildebug_no_op.dep
+}
\ No newline at end of file
diff --git a/lib/base/proguard-rules.pro b/lib/base/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/lib/base/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/lib/base/src/main/AndroidManifest.xml b/lib/base/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..3744b24f38
--- /dev/null
+++ b/lib/base/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/base/src/main/java/com/blankj/base/BaseActivity.java b/lib/base/src/main/java/com/blankj/base/BaseActivity.java
new file mode 100644
index 0000000000..c0348203f8
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/BaseActivity.java
@@ -0,0 +1,56 @@
+package com.blankj.base;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.annotation.LayoutRes;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.blankj.utilcode.util.ClickUtils;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/10/24
+ * desc : base about activity
+ *
+ */
+public abstract class BaseActivity extends AppCompatActivity
+ implements IBaseView {
+
+ private View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onDebouncingClick(v);
+ }
+ };
+
+ public View mContentView;
+ public Activity mActivity;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mActivity = this;
+ super.onCreate(savedInstanceState);
+ initData(getIntent().getExtras());
+ setContentView();
+ initView(savedInstanceState, mContentView);
+ doBusiness();
+ }
+
+ @Override
+ public void setContentView() {
+ if (bindLayout() <= 0) return;
+ mContentView = LayoutInflater.from(this).inflate(bindLayout(), null);
+ setContentView(mContentView);
+ }
+
+ public void applyDebouncingClickListener(View... views) {
+ ClickUtils.applyGlobalDebouncing(views, mClickListener);
+ ClickUtils.applyPressedViewScale(views);
+ }
+}
+
diff --git a/lib/base/src/main/java/com/blankj/base/BaseApplication.java b/lib/base/src/main/java/com/blankj/base/BaseApplication.java
new file mode 100644
index 0000000000..f1fd6186c0
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/BaseApplication.java
@@ -0,0 +1,106 @@
+package com.blankj.base;
+
+import android.app.Application;
+import android.content.Context;
+
+import androidx.multidex.MultiDex;
+
+import com.blankj.utilcode.util.AppUtils;
+import com.blankj.utilcode.util.CrashUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ProcessUtils;
+import com.blankj.utildebug.DebugUtils;
+import com.blankj.utildebug.debug.IDebug;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/11/16
+ * desc : base about application
+ *
+ */
+public class BaseApplication extends Application {
+
+ private static BaseApplication sInstance;
+
+ public static BaseApplication getInstance() {
+ return sInstance;
+ }
+
+ private Boolean isDebug;
+ private Boolean isMainProcess;
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ MultiDex.install(this);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ sInstance = this;
+ initLog();
+ initCrash();
+ initDebugMenu();
+ }
+
+ // init it in ur application
+ public void initLog() {
+ LogUtils.Config config = LogUtils.getConfig()
+ .setLogSwitch(isDebug())// 设置 log 总开关,包括输出到控制台和文件,默认开
+ .setConsoleSwitch(isDebug())// 设置是否输出到控制台开关,默认开
+ .setGlobalTag(null)// 设置 log 全局标签,默认为空
+ // 当全局标签不为空时,我们输出的 log 全部为该 tag,
+ // 为空时,如果传入的 tag 为空那就显示类名,否则显示 tag
+ .setLogHeadSwitch(true)// 设置 log 头信息开关,默认为开
+ .setLog2FileSwitch(false)// 打印 log 时是否存到文件的开关,默认关
+ .setDir("")// 当自定义路径为空时,写入应用的/cache/log/目录中
+ .setFilePrefix("")// 当文件前缀为空时,默认为"util",即写入文件为"util-yyyy-MM-dd$fileExtension"
+ .setFileExtension(".log")// 设置日志文件后缀
+ .setBorderSwitch(true)// 输出日志是否带边框开关,默认开
+ .setSingleTagSwitch(true)// 一条日志仅输出一条,默认开,为美化 AS 3.1 的 Logcat
+ .setConsoleFilter(LogUtils.V)// log 的控制台过滤器,和 logcat 过滤器同理,默认 Verbose
+ .setFileFilter(LogUtils.V)// log 文件过滤器,和 logcat 过滤器同理,默认 Verbose
+ .setStackDeep(1)// log 栈深度,默认为 1
+ .setStackOffset(0)// 设置栈偏移,比如二次封装的话就需要设置,默认为 0
+ .setSaveDays(3)// 设置日志可保留天数,默认为 -1 表示无限时长
+ // 新增 ArrayList 格式化器,默认已支持 Array, Throwable, Bundle, Intent 的格式化输出
+ .addFormatter(new LogUtils.IFormatter() {
+ @Override
+ public String format(ArrayList arrayList) {
+ return "LogUtils Formatter ArrayList { " + arrayList.toString() + " }";
+ }
+ })
+ .addFileExtraHead("ExtraKey", "ExtraValue");
+ LogUtils.i(config.toString());
+ }
+
+ private void initCrash() {
+ CrashUtils.init(new CrashUtils.OnCrashListener() {
+ @Override
+ public void onCrash(CrashUtils.CrashInfo crashInfo) {
+ crashInfo.addExtraHead("extraKey", "extraValue");
+ LogUtils.e(crashInfo.toString());
+ AppUtils.relaunchApp();
+ }
+ });
+ }
+
+ private void initDebugMenu() {
+ DebugUtils.addDebugs(new ArrayList());
+ }
+
+ private boolean isDebug() {
+ if (isDebug == null) isDebug = AppUtils.isAppDebug();
+ return isDebug;
+ }
+
+ public boolean isMainProcess() {
+ if (isMainProcess == null) isMainProcess = ProcessUtils.isMainProcess();
+ return isMainProcess;
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/BaseFragment.java b/lib/base/src/main/java/com/blankj/base/BaseFragment.java
new file mode 100644
index 0000000000..ab2b8877fe
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/BaseFragment.java
@@ -0,0 +1,176 @@
+package com.blankj.base;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.blankj.utilcode.util.AppUtils;
+import com.blankj.utilcode.util.ClickUtils;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/03/28
+ * desc : base about v4-fragment
+ *
+ */
+public abstract class BaseFragment extends Fragment
+ implements IBaseView {
+
+ private static Boolean isDebug;
+
+ private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";
+
+ private View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onDebouncingClick(v);
+ }
+ };
+
+ protected AppCompatActivity mActivity;
+ protected LayoutInflater mInflater;
+ protected View mContentView;
+
+ protected boolean mIsVisibleToUser;
+ protected boolean mIsBusinessDone;
+ protected boolean mIsInPager;
+
+ /**
+ * @return true true {@link #doBusiness()} will lazy in view pager, false otherwise
+ */
+ public boolean isLazy() {
+ return false;
+ }
+
+ @Override
+ public void setUserVisibleHint(boolean isVisibleToUser) {
+ log("setUserVisibleHint: " + isVisibleToUser);
+ super.setUserVisibleHint(isVisibleToUser);
+ mIsInPager = true;
+ if (isVisibleToUser) mIsVisibleToUser = true;
+ if (isLazy()) {
+ if (!mIsBusinessDone && isVisibleToUser && mContentView != null) {
+ mIsBusinessDone = true;
+ doBusiness();
+ }
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ log("onAttach");
+ super.onAttach(context);
+ mActivity = (AppCompatActivity) context;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ log("onCreate");
+ super.onCreate(savedInstanceState);
+ FragmentManager fm = getFragmentManager();
+ if (fm == null) return;
+ if (savedInstanceState != null) {
+ boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);
+ FragmentTransaction ft = fm.beginTransaction();
+ if (isSupportHidden) {
+ ft.hide(this);
+ } else {
+ ft.show(this);
+ }
+ ft.commitNowAllowingStateLoss();
+ }
+ Bundle bundle = getArguments();
+ initData(bundle);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ log("onCreateView");
+ super.onCreateView(inflater, container, savedInstanceState);
+ mInflater = inflater;
+ setContentView();
+ return mContentView;
+ }
+
+ @Override
+ public void setContentView() {
+ if (bindLayout() <= 0) return;
+ mContentView = mInflater.inflate(bindLayout(), null);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ log("onViewCreated");
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ log("onActivityCreated");
+ super.onActivityCreated(savedInstanceState);
+ initView(savedInstanceState, mContentView);
+ if (!mIsInPager || !isLazy() || mIsVisibleToUser) {
+ mIsBusinessDone = true;
+ doBusiness();
+ }
+ }
+
+ @Override
+ public void onHiddenChanged(boolean hidden) {
+ log("onHiddenChanged: " + hidden);
+ super.onHiddenChanged(hidden);
+ }
+
+ @Override
+ public void onDestroyView() {
+ log("onDestroyView");
+ super.onDestroyView();
+ mIsVisibleToUser = false;
+ mIsBusinessDone = false;
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ log("onSaveInstanceState");
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
+ }
+
+ @Override
+ public void onDestroy() {
+ log("onDestroy");
+ super.onDestroy();
+ }
+
+ public void applyDebouncingClickListener(View... views) {
+ ClickUtils.applyGlobalDebouncing(views, mClickListener);
+ }
+
+ public T findViewById(@IdRes int id) {
+ if (mContentView == null) throw new NullPointerException("ContentView is null.");
+ return mContentView.findViewById(id);
+ }
+
+ protected void log(String msg) {
+ if (isDebug == null) {
+ isDebug = AppUtils.isAppDebug();
+ }
+ if (isDebug) {
+ Log.d("BaseFragment", getClass().getSimpleName() + ": " + msg);
+ }
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/IBaseView.java b/lib/base/src/main/java/com/blankj/base/IBaseView.java
new file mode 100644
index 0000000000..821cbf4399
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/IBaseView.java
@@ -0,0 +1,32 @@
+package com.blankj.base;
+
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/11/16
+ * desc :
+ *
+ */
+public interface IBaseView {
+
+ void initData(@Nullable Bundle bundle);
+
+ int bindLayout();
+
+ void setContentView();
+
+ void initView(@Nullable Bundle savedInstanceState, @Nullable View contentView);
+
+ void doBusiness();
+
+ void onDebouncingClick(@NonNull View view);
+}
diff --git a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java
new file mode 100644
index 0000000000..1599d8becc
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialog.java
@@ -0,0 +1,78 @@
+package com.blankj.base.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+
+import com.blankj.utilcode.util.ActivityUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+
+import androidx.annotation.NonNull;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/11
+ * desc :
+ *
+ */
+public abstract class BaseDialog extends Dialog {
+
+ protected Activity mActivity;
+
+ public abstract int bindLayout();
+
+ public abstract void initView(BaseDialog dialog, View contentView);
+
+ public abstract void setWindowStyle(Window window);
+
+ public BaseDialog(@NonNull Context context) {
+ this(context, 0);
+ }
+
+ public BaseDialog(@NonNull Context context, int themeResId) {
+ super(context, themeResId);
+ Activity activity = ActivityUtils.getActivityByContext(context);
+ if (activity == null) {
+ throw new IllegalArgumentException("context is not instance of Activity.");
+ }
+ mActivity = activity;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ View contentView = View.inflate(mActivity, bindLayout(), null);
+ setContentView(contentView);
+ initView(this, contentView);
+ setWindowStyle(getWindow());
+ }
+
+ @Override
+ public void show() {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityUtils.isActivityAlive(getContext())) {
+ BaseDialog.super.show();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void dismiss() {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityUtils.isActivityAlive(getContext())) {
+ BaseDialog.super.dismiss();
+ }
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java
new file mode 100644
index 0000000000..e115e78878
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/dialog/BaseDialogFragment.java
@@ -0,0 +1,159 @@
+package com.blankj.base.dialog;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+
+import com.blankj.utilcode.util.ActivityUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/11
+ * desc :
+ *
+ */
+public class BaseDialogFragment extends DialogFragment {
+
+ protected DialogLayoutCallback mDialogLayoutCallback;
+ protected DialogCallback mDialogCallback;
+
+ protected FragmentActivity mActivity;
+ protected View mContentView;
+
+ public BaseDialogFragment init(Context context, DialogLayoutCallback listener) {
+ mActivity = getFragmentActivity(context);
+ mDialogLayoutCallback = listener;
+ return this;
+ }
+
+ public BaseDialogFragment init(Context context, DialogCallback dialogCallback) {
+ mActivity = getFragmentActivity(context);
+ mDialogCallback = dialogCallback;
+ return this;
+ }
+
+ private FragmentActivity getFragmentActivity(Context context) {
+ Activity activity = ActivityUtils.getActivityByContext(context);
+ if (activity == null) return null;
+ if (activity instanceof FragmentActivity) {
+ return (FragmentActivity) activity;
+ }
+ LogUtils.w(context + "not instanceof FragmentActivity");
+ return null;
+ }
+
+ @Override
+ public int getTheme() {
+ if (mDialogLayoutCallback != null) {
+ int theme = mDialogLayoutCallback.bindTheme();
+ if (theme != View.NO_ID) {
+ return theme;
+ }
+ }
+ return super.getTheme();
+ }
+
+ @NonNull
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Dialog dialog;
+ if (mDialogCallback != null) {
+ dialog = mDialogCallback.bindDialog(mActivity);
+ } else {
+ dialog = super.onCreateDialog(savedInstanceState);
+ }
+ Window window = dialog.getWindow();
+ if (mDialogCallback != null) {
+ mDialogCallback.setWindowStyle(window);
+ } else if (mDialogLayoutCallback != null) {
+ mDialogLayoutCallback.setWindowStyle(window);
+ }
+ return dialog;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ if (mDialogLayoutCallback != null) {
+ return inflater.inflate(mDialogLayoutCallback.bindLayout(), container, false);
+ }
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ if (mDialogLayoutCallback != null) {
+ mDialogLayoutCallback.initView(this, view);
+ return;
+ }
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ if (mDialogLayoutCallback != null) {
+ mDialogLayoutCallback.onCancel(this);
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (mDialogLayoutCallback != null) {
+ mDialogLayoutCallback.onDismiss(this);
+ }
+ }
+
+ public void show() {
+ show(getClass().getSimpleName());
+ }
+
+ public void show(final String tag) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @SuppressLint("CommitTransaction")
+ @Override
+ public void run() {
+ if (ActivityUtils.isActivityAlive(mActivity)) {
+ FragmentManager fm = mActivity.getSupportFragmentManager();
+ Fragment prev = fm.findFragmentByTag(tag);
+ if (prev != null) {
+ fm.beginTransaction().remove(prev);
+ }
+ BaseDialogFragment.super.show(fm, tag);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void dismiss() {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityUtils.isActivityAlive(mActivity)) {
+ BaseDialogFragment.super.dismissAllowingStateLoss();
+ }
+ }
+ });
+ }
+}
+
+
diff --git a/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java b/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java
new file mode 100644
index 0000000000..defd34483f
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/dialog/DialogCallback.java
@@ -0,0 +1,22 @@
+package com.blankj.base.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.view.Window;
+
+import androidx.annotation.NonNull;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/12
+ * desc :
+ *
+ */
+public interface DialogCallback {
+ @NonNull
+ Dialog bindDialog(Activity activity);
+
+ void setWindowStyle(Window window);
+}
diff --git a/lib/base/src/main/java/com/blankj/base/dialog/DialogLayoutCallback.java b/lib/base/src/main/java/com/blankj/base/dialog/DialogLayoutCallback.java
new file mode 100644
index 0000000000..ea5c9a77cf
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/dialog/DialogLayoutCallback.java
@@ -0,0 +1,26 @@
+package com.blankj.base.dialog;
+
+import android.view.View;
+import android.view.Window;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/12
+ * desc :
+ *
+ */
+public interface DialogLayoutCallback {
+ int bindTheme();
+
+ int bindLayout();
+
+ void initView(BaseDialogFragment dialog, View contentView);
+
+ void setWindowStyle(Window window);
+
+ void onCancel(BaseDialogFragment dialog);
+
+ void onDismiss(BaseDialogFragment dialog);
+}
diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java b/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java
new file mode 100644
index 0000000000..b48ed32f23
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/mvp/BaseModel.java
@@ -0,0 +1,25 @@
+package com.blankj.base.mvp;
+
+import android.util.Log;
+
+import androidx.annotation.CallSuper;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/08/02
+ * desc :
+ *
+ */
+public abstract class BaseModel {
+
+ private static final String TAG = BaseView.TAG;
+
+ public abstract void onCreate();
+
+ @CallSuper
+ public void onDestroy() {
+ Log.i(TAG, "destroy model: " + getClass().getSimpleName());
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java b/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java
new file mode 100644
index 0000000000..32e672417b
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/mvp/BasePresenter.java
@@ -0,0 +1,73 @@
+package com.blankj.base.mvp;
+
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import androidx.annotation.CallSuper;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/08/02
+ * desc :
+ *
+ */
+public abstract class BasePresenter {
+
+ private static final String TAG = BaseView.TAG;
+
+ private V mView;
+ private Map, BaseModel> mModelMap = new HashMap<>();
+ private boolean isAlive = true;
+
+ public abstract void onBindView();
+
+ void bindView(V view) {
+ this.mView = view;
+ onBindView();
+ }
+
+ public V getView() {
+ return mView;
+ }
+
+ public M getModel(Class modelClass) {
+ BaseModel baseModel = mModelMap.get(modelClass);
+ if (baseModel != null) {
+ //noinspection unchecked
+ return (M) baseModel;
+ }
+ try {
+ M model = modelClass.newInstance();
+ mModelMap.put(modelClass, model);
+ model.onCreate();
+ return model;
+ } catch (IllegalAccessException e) {
+ Log.e("BasePresenter", "getModel", e);
+ } catch (InstantiationException e) {
+ Log.e("BasePresenter", "getModel", e);
+ }
+ return null;
+ }
+
+ @CallSuper
+ public void onDestroy() {
+ Log.i(TAG, "destroy presenter: " + getClass().getSimpleName());
+ isAlive = false;
+ for (BaseModel model : mModelMap.values()) {
+ if (model != null) {
+ model.onDestroy();
+ }
+ }
+ mModelMap.clear();
+ }
+
+ public boolean isAlive() {
+ return isAlive;
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java b/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java
new file mode 100644
index 0000000000..a68909d01f
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/mvp/BaseView.java
@@ -0,0 +1,114 @@
+package com.blankj.base.mvp;
+
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import androidx.annotation.CallSuper;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/08/02
+ * desc :
+ *
+ */
+public class BaseView implements LifecycleObserver {
+
+ public static final String TAG = "UtilsMVP";
+
+ private FragmentActivity mActivity;
+ private Fragment mFragment;
+ private Lifecycle mLifecycle;
+ private Map, BasePresenter> mPresenterMap = new HashMap<>();
+
+ public BaseView(Fragment fragment) {
+ mFragment = fragment;
+ mActivity = fragment.getActivity();
+ mLifecycle = mFragment.getLifecycle();
+ addLifecycle(this);
+ }
+
+ public BaseView(FragmentActivity activity) {
+ mActivity = activity;
+ mLifecycle = mActivity.getLifecycle();
+ addLifecycle(this);
+ }
+
+ public BaseView(Lifecycle lifecycle) {
+ mLifecycle = lifecycle;
+ addLifecycle(this);
+ }
+
+ public T getActivity() {
+ if (mActivity == null) {
+ return null;
+ }
+ //noinspection unchecked
+ return (T) mActivity;
+ }
+
+ public T getFragment() {
+ if (mFragment == null) {
+ return null;
+ }
+ //noinspection unchecked
+ return (T) mFragment;
+ }
+
+ public V addPresenter(BasePresenter presenter) {
+ if (presenter == null) return (V) this;
+ mPresenterMap.put(presenter.getClass(), presenter);
+ //noinspection unchecked
+ presenter.bindView((V) this);
+ return (V) this;
+ }
+
+ public > P getPresenter(Class
presenterClass) {
+ if (presenterClass == null) {
+ throw new IllegalArgumentException("presenterClass is null!");
+ }
+ BasePresenter basePresenter = mPresenterMap.get(presenterClass);
+ if (basePresenter == null) {
+ throw new IllegalArgumentException("presenter of <" + presenterClass.getSimpleName() + "> is not added!");
+ }
+ //noinspection unchecked
+ return (P) basePresenter;
+ }
+
+ @CallSuper
+ @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ public void onDestroy() {
+ Log.i(TAG, "destroy view: " + getClass().getSimpleName());
+ removeLifecycle(this);
+ for (BasePresenter presenter : mPresenterMap.values()) {
+ if (presenter != null) {
+ presenter.onDestroy();
+ }
+ }
+ mPresenterMap.clear();
+ }
+
+ private void addLifecycle(LifecycleObserver observer) {
+ if (mLifecycle == null) {
+ Log.w(TAG, "addLifecycle: mLifecycle is null");
+ return;
+ }
+ mLifecycle.addObserver(observer);
+ }
+
+ private void removeLifecycle(LifecycleObserver observer) {
+ if (mLifecycle == null) {
+ Log.w(TAG, "removeLifecycle: mLifecycle is null");
+ return;
+ }
+ mLifecycle.removeObserver(observer);
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java b/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java
new file mode 100644
index 0000000000..b0d6de04fa
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/rv/BaseItem.java
@@ -0,0 +1,169 @@
+package com.blankj.base.rv;
+
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/03/16
+ * desc :
+ *
+ */
+public abstract class BaseItem {
+
+ private static final SparseIntArray LAYOUT_SPARSE_ARRAY = new SparseIntArray();
+ private static final SparseArray VIEW_SPARSE_ARRAY = new SparseArray<>();
+ public boolean isBindViewHolder = false;
+
+ static ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ int layoutByType = LAYOUT_SPARSE_ARRAY.get(viewType, -1);
+ if (layoutByType != -1) {
+ return new ItemViewHolder(LayoutInflater.from(parent.getContext()).inflate(layoutByType, parent, false));
+ }
+ View viewByType = VIEW_SPARSE_ARRAY.get(viewType);
+ if (viewByType != null) {
+ return new ItemViewHolder(viewByType);
+ }
+ throw new RuntimeException("onCreateViewHolder: get holder from view type failed.");
+ }
+
+ public abstract void bind(@NonNull final ItemViewHolder holder, final int position);
+
+ public void partialUpdate(List payloads) {
+ }
+
+ void bindViewHolder(@NonNull final ItemViewHolder holder, final int position) {
+ isBindViewHolder = true;
+ if (mOnItemClickListener != null) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnItemClickListener != null) {
+ //noinspection unchecked
+ mOnItemClickListener.onItemClick(holder, (T) BaseItem.this, getIndex());
+ }
+ }
+ });
+ } else {
+ holder.itemView.setOnClickListener(null);
+ }
+ if (mOnItemLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mOnItemLongClickListener != null) {
+ //noinspection unchecked
+ return mOnItemLongClickListener.onItemLongClick(holder, (T) BaseItem.this, getIndex());
+ }
+ return false;
+ }
+ });
+ } else {
+ holder.itemView.setOnLongClickListener(null);
+ }
+ bind(holder, position);
+ }
+
+ public void onViewRecycled(@NonNull final ItemViewHolder holder, final int position) {
+ isBindViewHolder = false;
+ }
+
+ public long getItemId() {
+ return RecyclerView.NO_ID;
+ }
+
+ private int viewType;
+ BaseItemAdapter mAdapter;
+ private OnItemClickListener mOnItemClickListener;
+ private OnItemLongClickListener mOnItemLongClickListener;
+
+ public BaseItem(@LayoutRes int layoutId) {
+ viewType = getViewTypeByLayoutId(layoutId);
+ LAYOUT_SPARSE_ARRAY.put(viewType, layoutId);
+ }
+
+ public BaseItem(@NonNull View view) {
+ viewType = getViewTypeByView(view);
+ VIEW_SPARSE_ARRAY.put(viewType, view);
+ }
+
+ public int getViewType() {
+ return viewType;
+ }
+
+ public BaseItemAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ public boolean isViewType(@LayoutRes int layoutId) {
+ return viewType == getViewTypeByLayoutId(layoutId);
+ }
+
+ public boolean isViewType(@NonNull View view) {
+ return viewType == getViewTypeByView(view);
+ }
+
+ private int getViewTypeByLayoutId(@LayoutRes int layoutId) {
+ return layoutId + getClass().hashCode();
+ }
+
+ private int getViewTypeByView(@NonNull View view) {
+ return view.hashCode() + getClass().hashCode();
+ }
+
+ public void update() {
+ if (getAdapter() == null) return;
+ //noinspection unchecked
+ getAdapter().updateItem((T) this);
+ }
+
+ public List getItems() {
+ return getAdapter().getItems();
+ }
+
+ public int getCount() {
+ return getAdapter().getItemCount();
+ }
+
+ public int getIndex() {
+ //noinspection SuspiciousMethodCalls
+ return getAdapter().getItems().indexOf(this);
+ }
+
+ public OnItemClickListener getOnItemClickListener() {
+ return mOnItemClickListener;
+ }
+
+ public T setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ mOnItemClickListener = onItemClickListener;
+ return (T) this;
+ }
+
+ public OnItemLongClickListener getOnItemLongClickListener() {
+ return mOnItemLongClickListener;
+ }
+
+ public T setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
+ mOnItemLongClickListener = onItemLongClickListener;
+ return (T) this;
+ }
+
+ public interface OnItemClickListener {
+ void onItemClick(ItemViewHolder holder, T item, int position);
+ }
+
+ public interface OnItemLongClickListener {
+ boolean onItemLongClick(ItemViewHolder holder, T item, int position);
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/rv/BaseItemAdapter.java b/lib/base/src/main/java/com/blankj/base/rv/BaseItemAdapter.java
new file mode 100644
index 0000000000..67d5902752
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/rv/BaseItemAdapter.java
@@ -0,0 +1,308 @@
+package com.blankj.base.rv;
+
+import android.view.ViewGroup;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/08/22
+ * desc :
+ *
+ */
+public class BaseItemAdapter- extends RecyclerView.Adapter
{
+
+ public List- mItems;
+ private RecyclerView mRecyclerView;
+
+ public BaseItemAdapter() {
+ this(false);
+ }
+
+ public BaseItemAdapter(boolean hasStableIds) {
+ setHasStableIds(hasStableIds);
+ }
+
+ @Override
+ public final int getItemViewType(int position) {
+ Item item = mItems.get(position);
+ item.mAdapter = this;
+ return item.getViewType();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mItems.get(position).getItemId();
+ }
+
+ @NonNull
+ @Override
+ public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return Item.onCreateViewHolder(parent, viewType);
+ }
+
+ @Override
+ public final void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
+ mItems.get(position).bindViewHolder(holder, position);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ItemViewHolder holder, int position, @NonNull List
payloads) {
+ if (payloads.isEmpty()) {
+ super.onBindViewHolder(holder, position, payloads);
+ return;
+ }
+ mItems.get(position).partialUpdate(payloads);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public void onViewRecycled(@NonNull ItemViewHolder holder) {
+ super.onViewRecycled(holder);
+ int position = holder.getAdapterPosition();
+ if (position < 0 || position >= mItems.size()) {
+ return;
+ }
+ mItems.get(position).onViewRecycled(holder, position);
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ mRecyclerView = recyclerView;
+ }
+
+ public RecyclerView getRecyclerView() {
+ return mRecyclerView;
+ }
+
+ public void setItems(@NonNull final List- items) {
+ mItems = items;
+ }
+
+ public List
- getItems() {
+ return Collections.unmodifiableList(mItems);
+ }
+
+ public Item getItem(@IntRange(from = 0) final int position) {
+ return mItems.get(position);
+ }
+
+ public boolean isEmpty() {
+ return mItems.isEmpty();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // id
+ ///////////////////////////////////////////////////////////////////////////
+
+ public Item getItemById(final long id) {
+ int itemIndex = getItemIndexById(id);
+ if (itemIndex != -1) {
+ return mItems.get(itemIndex);
+ } else {
+ return null;
+ }
+ }
+
+ public int getItemIndexById(final long id) {
+ for (int i = 0; i < mItems.size(); i++) {
+ if (getItemId(i) == id) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public boolean hasItemWithId(final long id) {
+ return getItemIndexById(id) != -1;
+ }
+
+ public int replaceItemById(final long id, @NonNull final Item item) {
+ return replaceItemById(id, item, false);
+ }
+
+ public int replaceItemById(final long id, @NonNull final Item item, boolean notifyChanged) {
+ int itemIndex = getItemIndexById(id);
+ if (itemIndex != -1) {
+ replaceItem(itemIndex, item, notifyChanged);
+ }
+ return itemIndex;
+ }
+
+ public int removeItemById(final long id) {
+ return removeItemById(id, false);
+ }
+
+ public int removeItemById(final long id, boolean notifyRemoved) {
+ for (int i = 0; i < mItems.size(); i++) {
+ if (getItemId(i) == id) {
+ removeItem(i, notifyRemoved);
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // operate
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void updateItem(@NonNull final Item item) {
+ updateItems(item, 1, null);
+ }
+
+ public void updateItem(@IntRange(from = 0) final int index) {
+ updateItems(index, 1, null);
+ }
+
+ public void updateItem(@NonNull final Item item, Object payload) {
+ updateItems(item, 1, payload);
+ }
+
+ public void updateItem(@IntRange(from = 0) final int index, Object payload) {
+ updateItems(index, 1, payload);
+ }
+
+ public void updateItems(@NonNull final Item item, int itemCount) {
+ int itemIndex = mItems.indexOf(item);
+ if (itemIndex != -1) {
+ updateItems(itemIndex, itemCount);
+ }
+ }
+
+ public void updateItems(@IntRange(from = 0) final int index, int itemCount) {
+ updateItems(index, itemCount, null);
+ }
+
+ public void updateItems(@NonNull final Item item, int itemCount, Object payload) {
+ int itemIndex = mItems.indexOf(item);
+ if (itemIndex != -1) {
+ updateItems(itemIndex, itemCount, payload);
+ }
+ }
+
+ public void updateItems(@IntRange(from = 0) final int index, int itemCount, Object payload) {
+ notifyItemRangeChanged(index, itemCount, payload);
+ }
+
+ public void addItem(@NonNull final Item item) {
+ addItem(item, false);
+ }
+
+ public void addItem(@NonNull final Item item, boolean notifyInserted) {
+ mItems.add(item);
+ if (notifyInserted) notifyItemInserted(mItems.size() - 1);
+ }
+
+ public void addItem(@IntRange(from = 0) final int index, @NonNull final Item item) {
+ addItem(index, item, false);
+ }
+
+ public void addItem(@IntRange(from = 0) final int index, @NonNull final Item item, boolean notifyInserted) {
+ mItems.add(index, item);
+ if (notifyInserted) notifyItemInserted(index);
+ }
+
+ public void addItems(@NonNull final List
- items) {
+ addItems(items, false);
+ }
+
+ public void addItems(@NonNull final List
- items, boolean notifyInserted) {
+ mItems.addAll(items);
+ if (notifyInserted) notifyItemRangeInserted(mItems.size() - items.size() - 1, items.size());
+ }
+
+ public void addItems(@IntRange(from = 0) final int index, @NonNull final List
- items) {
+ addItems(index, items, false);
+ }
+
+ public void addItems(@IntRange(from = 0) final int index, @NonNull final List
- items, boolean notifyInserted) {
+ mItems.addAll(index, items);
+ if (notifyInserted) notifyItemRangeInserted(index, items.size());
+ }
+
+ public void swapItem(@IntRange(from = 0) final int firstIndex, @IntRange(from = 0) final int secondIndex) {
+ swapItem(firstIndex, secondIndex, false);
+ }
+
+ public void swapItem(@IntRange(from = 0) final int firstIndex,
+ @IntRange(from = 0) final int secondIndex, boolean notifyMoved) {
+ Collections.swap(mItems, firstIndex, secondIndex);
+ if (notifyMoved) notifyItemMoved(firstIndex, secondIndex);
+ }
+
+ public Item replaceItem(@IntRange(from = 0) final int index, @NonNull final Item item) {
+ return replaceItem(index, item, false);
+ }
+
+ public Item replaceItem(@IntRange(from = 0) final int index, @NonNull final Item item, boolean notifyChanged) {
+ Item prevItem = mItems.set(index, item);
+ if (notifyChanged) notifyItemChanged(index);
+ return prevItem;
+ }
+
+ public boolean replaceItems(@NonNull final List
- items) {
+ return replaceItems(items, false);
+ }
+
+ public boolean replaceItems(@NonNull final List
- items, boolean notifyChanged) {
+ mItems.clear();
+ boolean added = mItems.addAll(items);
+ if (notifyChanged) notifyDataSetChanged();
+ return added;
+ }
+
+ public Item removeItem(@IntRange(from = 0) final int index) {
+ return removeItem(index, false);
+ }
+
+ public Item removeItem(@IntRange(from = 0) final int index, boolean notifyRemoved) {
+ Item removedItem = mItems.remove(index);
+ if (notifyRemoved) notifyItemRemoved(index);
+ return removedItem;
+ }
+
+ public int removeItem(@NonNull final Item item) {
+ return removeItem(item, false);
+ }
+
+ public int removeItem(@NonNull final Item item, boolean notifyRemoved) {
+ int itemIndex = mItems.indexOf(item);
+ if (itemIndex != -1) {
+ mItems.remove(itemIndex);
+ if (notifyRemoved) notifyItemRemoved(itemIndex);
+ }
+ return itemIndex;
+ }
+
+ public void clear() {
+ clear(false);
+ }
+
+ public void clear(boolean notifyDataSetChanged) {
+ mItems.clear();
+ if (notifyDataSetChanged) notifyDataSetChanged();
+ }
+
+ public void sortItems(@NonNull final Comparator
- comparator) {
+ sortItems(comparator, false);
+ }
+
+ public void sortItems(@NonNull final Comparator
- comparator, boolean notifyDataSetChanged) {
+ Collections.sort(mItems, comparator);
+ if (notifyDataSetChanged) notifyDataSetChanged();
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/rv/ItemViewHolder.java b/lib/base/src/main/java/com/blankj/base/rv/ItemViewHolder.java
new file mode 100644
index 0000000000..e2bf00dfd6
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/rv/ItemViewHolder.java
@@ -0,0 +1,43 @@
+package com.blankj.base.rv;
+
+import androidx.annotation.IdRes;
+import androidx.recyclerview.widget.RecyclerView;
+import android.util.SparseArray;
+import android.view.View;
+
+import java.util.List;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/08/22
+ * desc :
+ *
+ */
+public class ItemViewHolder extends RecyclerView.ViewHolder {
+
+ private SparseArray viewArray = new SparseArray<>();
+
+ public ItemViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T findViewById(@IdRes final int viewId) {
+ View view = viewArray.get(viewId);
+ if (view == null) {
+ view = itemView.findViewById(viewId);
+ viewArray.put(viewId, view);
+ }
+ return (T) view;
+ }
+
+ public void setOnClickListener(@IdRes final int viewId, View.OnClickListener listener) {
+ findViewById(viewId).setOnClickListener(listener);
+ }
+
+ public void setOnLongClickListener(@IdRes final int viewId, View.OnLongClickListener listener) {
+ findViewById(viewId).setOnLongClickListener(listener);
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/rv/RecycleViewDivider.java b/lib/base/src/main/java/com/blankj/base/rv/RecycleViewDivider.java
new file mode 100644
index 0000000000..6c2e4383af
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/rv/RecycleViewDivider.java
@@ -0,0 +1,138 @@
+package com.blankj.base.rv;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/08/17
+ * desc :
+ *
+ */
+public class RecycleViewDivider extends RecyclerView.ItemDecoration {
+
+ public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+ public static final int VERTICAL = LinearLayout.VERTICAL;
+
+ protected Drawable mDivider;
+
+ protected int mOrientation;
+ protected boolean mShowFooterDivider;
+
+ protected final Rect mBounds = new Rect();
+
+ public RecycleViewDivider(Context context, int orientation, @DrawableRes int resId) {
+ this(context, orientation, resId, false);
+ }
+
+ public RecycleViewDivider(Context context, int orientation, @NonNull Drawable divider) {
+ this(context, orientation, divider, false);
+ }
+
+ public RecycleViewDivider(Context context, int orientation, @DrawableRes int resId, boolean showFooterDivider) {
+ this(context, orientation, ContextCompat.getDrawable(context, resId), showFooterDivider);
+ }
+
+ public RecycleViewDivider(Context context, int orientation, @NonNull Drawable divider, boolean showFooterDivider) {
+ setOrientation(orientation);
+ mDivider = divider;
+ mShowFooterDivider = showFooterDivider;
+ }
+
+ private void setOrientation(int orientation) {
+ if (orientation != HORIZONTAL && orientation != VERTICAL) {
+ throw new IllegalArgumentException(
+ "Invalid orientation. It should be either HORIZONTAL or VERTICAL");
+ }
+ mOrientation = orientation;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (parent.getLayoutManager() == null) {
+ return;
+ }
+ if (mOrientation == VERTICAL) {
+ drawVertical(c, parent);
+ } else {
+ drawHorizontal(c, parent);
+ }
+ }
+
+ @SuppressLint("NewApi")
+ protected void drawVertical(Canvas canvas, RecyclerView parent) {
+ canvas.save();
+ final int left;
+ final int right;
+ if (parent.getClipToPadding()) {
+ left = parent.getPaddingLeft();
+ right = parent.getWidth() - parent.getPaddingRight();
+ canvas.clipRect(left, parent.getPaddingTop(), right,
+ parent.getHeight() - parent.getPaddingBottom());
+ } else {
+ left = 0;
+ right = parent.getWidth();
+ }
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (i == childCount - 1 && !mShowFooterDivider) continue;
+ final View child = parent.getChildAt(i);
+ parent.getDecoratedBoundsWithMargins(child, mBounds);
+ final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child));
+ final int top = bottom - mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+ canvas.restore();
+ }
+
+ @SuppressLint("NewApi")
+ protected void drawHorizontal(Canvas canvas, RecyclerView parent) {
+ canvas.save();
+ final int top;
+ final int bottom;
+ if (parent.getClipToPadding()) {
+ top = parent.getPaddingTop();
+ bottom = parent.getHeight() - parent.getPaddingBottom();
+ canvas.clipRect(parent.getPaddingLeft(), top,
+ parent.getWidth() - parent.getPaddingRight(), bottom);
+ } else {
+ top = 0;
+ bottom = parent.getHeight();
+ }
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (i == childCount - 1 && !mShowFooterDivider) continue;
+ final View child = parent.getChildAt(i);
+ parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
+ final int right = mBounds.right + Math.round(ViewCompat.getTranslationX(child));
+ final int left = right - mDivider.getIntrinsicWidth();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+ canvas.restore();
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ if (mOrientation == VERTICAL) {
+ outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
+ } else {
+ outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
+ }
+ }
+}
diff --git a/lib/base/src/main/java/com/blankj/base/view/EmptyGoneTextView.java b/lib/base/src/main/java/com/blankj/base/view/EmptyGoneTextView.java
new file mode 100644
index 0000000000..abb765a0a4
--- /dev/null
+++ b/lib/base/src/main/java/com/blankj/base/view/EmptyGoneTextView.java
@@ -0,0 +1,41 @@
+package com.blankj.base.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.blankj.utilcode.util.StringUtils;
+
+import androidx.annotation.Nullable;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/09/03
+ * desc :
+ *
+ */
+@SuppressLint("AppCompatCustomView")
+public class EmptyGoneTextView extends TextView {
+
+ public EmptyGoneTextView(Context context) {
+ this(context, null);
+ }
+
+ public EmptyGoneTextView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ setVisibility(GONE);
+ }
+
+ @Override
+ protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
+ super.onTextChanged(text, start, lengthBefore, lengthAfter);
+ if (StringUtils.isEmpty(text)) {
+ setVisibility(GONE);
+ } else {
+ setVisibility(VISIBLE);
+ }
+ }
+}
diff --git a/lib/base/src/main/res/layout/activity_back.xml b/lib/base/src/main/res/layout/activity_back.xml
new file mode 100644
index 0000000000..c01cbee99d
--- /dev/null
+++ b/lib/base/src/main/res/layout/activity_back.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/base/src/main/res/layout/fragment_lazy.xml b/lib/base/src/main/res/layout/fragment_lazy.xml
new file mode 100644
index 0000000000..4971dc6fe6
--- /dev/null
+++ b/lib/base/src/main/res/layout/fragment_lazy.xml
@@ -0,0 +1,5 @@
+
+
diff --git a/lib/common/.gitignore b/lib/common/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/lib/common/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/lib/common/build.gradle b/lib/common/build.gradle
new file mode 100644
index 0000000000..4993b43792
--- /dev/null
+++ b/lib/common/build.gradle
@@ -0,0 +1,4 @@
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ api Config.modules.lib_base.dep
+}
\ No newline at end of file
diff --git a/lib/common/proguard-rules.pro b/lib/common/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/lib/common/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/lib/common/src/main/AndroidManifest.xml b/lib/common/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..32ea8ea189
--- /dev/null
+++ b/lib/common/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/lib/common/src/main/assets/test_install b/lib/common/src/main/assets/test_install
new file mode 100644
index 0000000000..50afc3206a
Binary files /dev/null and b/lib/common/src/main/assets/test_install differ
diff --git a/lib/common/src/main/java/com/blankj/common/CommonApplication.java b/lib/common/src/main/java/com/blankj/common/CommonApplication.java
new file mode 100644
index 0000000000..309a73257a
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/CommonApplication.java
@@ -0,0 +1,19 @@
+package com.blankj.common;
+
+import com.blankj.base.BaseApplication;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/06/05
+ * desc : app about common
+ *
+ */
+public class CommonApplication extends BaseApplication {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java b/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java
new file mode 100644
index 0000000000..1d7d739597
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/activity/CommonActivity.java
@@ -0,0 +1,267 @@
+package com.blankj.common.activity;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.blankj.base.BaseActivity;
+import com.blankj.base.rv.BaseItemAdapter;
+import com.blankj.base.rv.RecycleViewDivider;
+import com.blankj.common.R;
+import com.blankj.common.dialog.CommonDialogLoading;
+import com.blankj.common.item.CommonItem;
+import com.blankj.swipepanel.SwipePanel;
+import com.blankj.utilcode.util.LanguageUtils;
+import com.blankj.utilcode.util.SizeUtils;
+
+import java.util.List;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2019/06/05
+ * desc :
+ *
+ */
+public abstract class CommonActivity extends BaseActivity {
+
+ private CommonActivityItemsView mItemsView;
+ private CommonActivityTitleView mTitleView;
+ private CommonActivityDrawerView mDrawerView;
+
+ private CommonDialogLoading mDialogLoading;
+
+ public View commonContentView;
+
+// @Override
+// protected void attachBaseContext(Context newBase) {
+// super.attachBaseContext(LanguageUtils.attachBaseContext(newBase));
+// }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // title view
+ ///////////////////////////////////////////////////////////////////////////
+ public boolean isSwipeBack() {
+ return true;
+ }
+
+ @StringRes
+ public int bindTitleRes() {
+ return View.NO_ID;
+ }
+
+ public CharSequence bindTitle() {
+ return "";
+ }
+
+ public boolean isSupportScroll() {
+ return true;
+ }
+
+ public CommonActivityTitleView bindTitleView() {
+ return null;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // items view
+ ///////////////////////////////////////////////////////////////////////////
+ public CommonActivityItemsView bindItemsView() {
+ return null;
+ }
+
+ public List bindItems() {
+ return null;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // drawer view
+ ///////////////////////////////////////////////////////////////////////////
+ public CommonActivityDrawerView bindDrawerView() {
+ return null;
+ }
+
+ public boolean bindDrawer() {
+ return false;
+ }
+
+ @CallSuper
+ @Override
+ public void initData(@Nullable Bundle bundle) {
+ mTitleView = bindTitleView();
+ if (mTitleView == null) {
+ int titleRes = bindTitleRes();
+ if (titleRes != View.NO_ID) {
+ mTitleView = new CommonActivityTitleView(this, titleRes, isSupportScroll());
+ } else {
+ CharSequence title = bindTitle();
+ if (!TextUtils.isEmpty(title)) {
+ mTitleView = new CommonActivityTitleView(this, title, isSupportScroll());
+ }
+ }
+ }
+
+ mItemsView = bindItemsView();
+ if (mItemsView == null) {
+ List items = bindItems();
+ if (items != null) {
+ mItemsView = new CommonActivityItemsView(this, items);
+ }
+ }
+
+ mDrawerView = bindDrawerView();
+ if (mDrawerView == null) {
+ if (bindDrawer()) {
+ mDrawerView = new CommonActivityDrawerView(this);
+ }
+ }
+
+ if (mTitleView != null && mItemsView != null) {
+ mTitleView.setIsSupportScroll(false);
+ }
+
+ findViewById(android.R.id.content).setBackgroundColor(getResources().getColor(R.color.lightGrayDark));
+ initSwipeBack();
+ }
+
+ @Override
+ public int bindLayout() {
+ return View.NO_ID;
+ }
+
+ @Override
+ public void setContentView() {
+ if (mTitleView != null) {
+ mContentView = LayoutInflater.from(this).inflate(mTitleView.bindLayout(), null);
+ setContentView(mContentView);
+ commonContentView = mTitleView.getContentView();
+ } else if (mDrawerView != null) {
+ mContentView = LayoutInflater.from(this).inflate(mDrawerView.bindLayout(), null);
+ setContentView(mContentView);
+ commonContentView = mDrawerView.getContentView();
+ } else {
+ if (mItemsView != null) {
+ mContentView = LayoutInflater.from(this).inflate(mItemsView.bindLayout(), null);
+ setContentView(mContentView);
+ } else {
+ super.setContentView();
+ }
+ commonContentView = mContentView;
+ return;
+ }
+
+ if (mItemsView != null) {
+ LayoutInflater.from(this).inflate(mItemsView.bindLayout(), (ViewGroup) commonContentView);
+ } else {
+ if (bindLayout() > 0) {
+ LayoutInflater.from(this).inflate(bindLayout(), (ViewGroup) commonContentView);
+ }
+ }
+ }
+
+ private void initSwipeBack() {
+ if (isSwipeBack()) {
+ final SwipePanel swipeLayout = new SwipePanel(this);
+ swipeLayout.setLeftDrawable(R.drawable.common_back);
+ swipeLayout.setLeftEdgeSize(SizeUtils.dp2px(16));
+ swipeLayout.setLeftSwipeColor(getResources().getColor(R.color.colorPrimary));
+ swipeLayout.wrapView(findViewById(android.R.id.content));
+ swipeLayout.setOnFullSwipeListener(new SwipePanel.OnFullSwipeListener() {
+ @Override
+ public void onFullSwipe(int direction) {
+ swipeLayout.close(direction);
+ finish();
+ }
+ });
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void initView(@Nullable Bundle savedInstanceState, @Nullable View contentView) {
+ if (mItemsView != null) {
+ mItemsView.initView();
+ }
+ }
+
+ @Override
+ public void doBusiness() {
+ }
+
+ @Override
+ public void onDebouncingClick(@NonNull View view) {
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mTitleView != null) {
+ return mTitleView.onOptionsItemSelected(item);
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void showLoading() {
+ showLoading(null);
+ }
+
+ public void showLoading(Runnable listener) {
+ if (mDialogLoading != null) {
+ return;
+ }
+ mDialogLoading = new CommonDialogLoading().init(this, listener);
+ mDialogLoading.show();
+ }
+
+ public void dismissLoading() {
+ if (mDialogLoading != null) {
+ mDialogLoading.dismiss();
+ mDialogLoading = null;
+ }
+ }
+
+ public CommonActivityItemsView getItemsView() {
+ return mItemsView;
+ }
+
+ public CommonActivityTitleView getTitleView() {
+ return mTitleView;
+ }
+
+ public CommonActivityDrawerView getDrawerView() {
+ return mDrawerView;
+ }
+
+ private BaseItemAdapter mCommonItemAdapter;
+
+ public void setCommonItems(RecyclerView rv, List items) {
+ mCommonItemAdapter = new BaseItemAdapter<>();
+ mCommonItemAdapter.setItems(items);
+ rv.setAdapter(mCommonItemAdapter);
+ rv.setLayoutManager(new LinearLayoutManager(this));
+ rv.addItemDecoration(new RecycleViewDivider(this, RecycleViewDivider.VERTICAL, R.drawable.common_item_divider));
+ }
+
+ public void updateCommonItems(List data) {
+ mCommonItemAdapter.setItems(data);
+ mCommonItemAdapter.notifyDataSetChanged();
+ }
+
+ public void updateCommonItem(int position) {
+ mCommonItemAdapter.notifyItemChanged(position);
+ }
+
+ public BaseItemAdapter getCommonItemAdapter() {
+ return mCommonItemAdapter;
+ }
+}
\ No newline at end of file
diff --git a/lib/common/src/main/java/com/blankj/common/activity/CommonActivityDrawerView.java b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityDrawerView.java
new file mode 100644
index 0000000000..684d580a74
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityDrawerView.java
@@ -0,0 +1,65 @@
+package com.blankj.common.activity;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.blankj.common.R;
+import com.blankj.utilcode.util.ActivityUtils;
+import com.blankj.utilcode.util.StringUtils;
+import com.google.android.material.navigation.NavigationView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.drawerlayout.widget.DrawerLayout;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/01
+ * desc :
+ *
+ */
+public class CommonActivityDrawerView {
+
+ public AppCompatActivity mBaseActivity;
+ public DrawerLayout mBaseDrawerRootLayout;
+ public FrameLayout mBaseDrawerContainerView;
+
+ private NavigationView.OnNavigationItemSelectedListener mListener = new NavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+ int id = item.getItemId();
+ if (id == R.id.baseDrawerActionGitHub) {
+ return goWeb(R.string.github);
+ } else if (id == R.id.baseDrawerActionBlog) {
+ return goWeb(R.string.blog);
+ }
+ return false;
+ }
+ };
+
+ public CommonActivityDrawerView(@NonNull AppCompatActivity activity) {
+ mBaseActivity = activity;
+ }
+
+ public int bindLayout() {
+ return R.layout.common_activity_drawer;
+ }
+
+ public View getContentView() {
+ mBaseDrawerRootLayout = mBaseActivity.findViewById(R.id.baseDrawerRootLayout);
+ mBaseDrawerContainerView = mBaseActivity.findViewById(R.id.baseDrawerContainerView);
+ NavigationView nav = mBaseActivity.findViewById(R.id.baseDrawerNavView);
+ nav.setNavigationItemSelectedListener(mListener);
+ return mBaseDrawerContainerView;
+ }
+
+ private boolean goWeb(@StringRes int id) {
+ return ActivityUtils.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(StringUtils.getString(id))));
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/activity/CommonActivityItemsView.java b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityItemsView.java
new file mode 100644
index 0000000000..120eae1963
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityItemsView.java
@@ -0,0 +1,57 @@
+package com.blankj.common.activity;
+
+
+import com.blankj.base.rv.BaseItemAdapter;
+import com.blankj.base.rv.RecycleViewDivider;
+import com.blankj.common.R;
+import com.blankj.common.item.CommonItem;
+
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/01
+ * desc :
+ *
+ */
+public class CommonActivityItemsView {
+
+ public AppCompatActivity mBaseActivity;
+ private List mItems;
+ public BaseItemAdapter mCommonItemAdapter;
+ public RecyclerView mCommonItemRv;
+
+ public CommonActivityItemsView(@NonNull AppCompatActivity activity, @NonNull List items) {
+ mBaseActivity = activity;
+ mItems = items;
+ }
+
+ public int bindLayout() {
+ return R.layout.common_item;
+ }
+
+ public void initView() {
+ mCommonItemAdapter = new BaseItemAdapter<>();
+ mCommonItemAdapter.setItems(mItems);
+ mCommonItemRv = mBaseActivity.findViewById(R.id.commonItemRv);
+ mCommonItemRv.setAdapter(mCommonItemAdapter);
+ mCommonItemRv.setLayoutManager(new LinearLayoutManager(mBaseActivity));
+ mCommonItemRv.addItemDecoration(new RecycleViewDivider(mBaseActivity, RecycleViewDivider.VERTICAL, R.drawable.common_item_divider));
+ }
+
+ public void updateItems(List data) {
+ mCommonItemAdapter.setItems(data);
+ mCommonItemAdapter.notifyDataSetChanged();
+ }
+
+ public void updateItem(int position) {
+ mCommonItemAdapter.notifyItemChanged(position);
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/activity/CommonActivityTitleView.java b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityTitleView.java
new file mode 100644
index 0000000000..623feee1a3
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/activity/CommonActivityTitleView.java
@@ -0,0 +1,95 @@
+package com.blankj.common.activity;
+
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.FrameLayout;
+
+import com.blankj.common.R;
+import com.blankj.utilcode.util.BarUtils;
+import com.blankj.utilcode.util.ColorUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/01
+ * desc :
+ *
+ */
+public class CommonActivityTitleView {
+
+ public AppCompatActivity mBaseActivity;
+ public CharSequence mTitle;
+ public boolean mIsSupportScroll;
+ public CoordinatorLayout baseTitleRootLayout;
+ public Toolbar baseTitleToolbar;
+ public FrameLayout baseTitleContentView;
+ public ViewStub mViewStub;
+
+ public CommonActivityTitleView(@NonNull AppCompatActivity activity, @StringRes int resId) {
+ this(activity, activity.getString(resId), true);
+ }
+
+ public CommonActivityTitleView(@NonNull AppCompatActivity activity, @NonNull CharSequence title) {
+ this(activity, title, true);
+ }
+
+ public CommonActivityTitleView(@NonNull AppCompatActivity activity, @StringRes int resId, boolean isSupportScroll) {
+ this(activity, activity.getString(resId), isSupportScroll);
+ }
+
+ public CommonActivityTitleView(@NonNull AppCompatActivity activity, @NonNull CharSequence title, boolean isSupportScroll) {
+ mBaseActivity = activity;
+ mTitle = title;
+ mIsSupportScroll = isSupportScroll;
+ }
+
+ public void setIsSupportScroll(boolean isSupportScroll) {
+ mIsSupportScroll = isSupportScroll;
+ }
+
+ public int bindLayout() {
+ return R.layout.common_activity_title;
+ }
+
+ public View getContentView() {
+ baseTitleRootLayout = mBaseActivity.findViewById(R.id.baseTitleRootLayout);
+ baseTitleToolbar = mBaseActivity.findViewById(R.id.baseTitleToolbar);
+ if (mIsSupportScroll) {
+ mViewStub = mBaseActivity.findViewById(R.id.baseTitleStubScroll);
+ } else {
+ mViewStub = mBaseActivity.findViewById(R.id.baseTitleStubNoScroll);
+ }
+ mViewStub.setVisibility(View.VISIBLE);
+ baseTitleContentView = mBaseActivity.findViewById(R.id.commonTitleContentView);
+ setTitleBar();
+ BarUtils.setStatusBarColor(mBaseActivity, ColorUtils.getColor(R.color.colorPrimary));
+ BarUtils.addMarginTopEqualStatusBarHeight(baseTitleRootLayout);
+ return baseTitleContentView;
+ }
+
+ private void setTitleBar() {
+ mBaseActivity.setSupportActionBar(baseTitleToolbar);
+ ActionBar titleBar = mBaseActivity.getSupportActionBar();
+ if (titleBar != null) {
+ titleBar.setDisplayHomeAsUpEnabled(true);
+ titleBar.setTitle(mTitle);
+ }
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ mBaseActivity.finish();
+ return true;
+ }
+ return mBaseActivity.onOptionsItemSelected(item);
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogContent.java b/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogContent.java
new file mode 100644
index 0000000000..1cbe7a8ab2
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogContent.java
@@ -0,0 +1,113 @@
+package com.blankj.common.dialog;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.view.View;
+import android.view.Window;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.blankj.base.dialog.BaseDialogFragment;
+import com.blankj.base.dialog.DialogLayoutCallback;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.ClickUtils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/18
+ * desc :
+ *
+ */
+public class CommonDialogContent extends BaseDialogFragment {
+
+ private RelativeLayout cdcTitleRl;
+ private TextView cdcTitleTv;
+ private RelativeLayout cdcContentRl;
+ private TextView cdcContentTv;
+ private RelativeLayout cdcBottomRl;
+ private TextView cdcBottomPositiveTv;
+ private TextView cdcBottomNegativeTv;
+
+ public CommonDialogContent init(Context context, final CharSequence title, final CharSequence content,
+ final Pair positiveBtnAction,
+ final Pair negativeBtnAction) {
+ super.init(context, new DialogLayoutCallback() {
+ @Override
+ public int bindTheme() {
+ return R.style.CommonContentDialogStyle;
+ }
+
+ @Override
+ public int bindLayout() {
+ return R.layout.common_dialog_content;
+ }
+
+ @Override
+ public void initView(final BaseDialogFragment dialog, View contentView) {
+ cdcTitleRl = contentView.findViewById(R.id.cdcTitleRl);
+ cdcTitleTv = contentView.findViewById(R.id.cdcTitleTv);
+ cdcContentRl = contentView.findViewById(R.id.cdcContentRl);
+ cdcContentTv = contentView.findViewById(R.id.cdcContentTv);
+ cdcBottomRl = contentView.findViewById(R.id.cdcBottomRl);
+ cdcBottomPositiveTv = contentView.findViewById(R.id.cdcBottomPositiveTv);
+ cdcBottomNegativeTv = contentView.findViewById(R.id.cdcBottomNegativeTv);
+
+ if (TextUtils.isEmpty(title)) {
+ cdcTitleRl.setVisibility(View.GONE);
+ } else {
+ cdcTitleTv.setText(title);
+ }
+ if (TextUtils.isEmpty(content)) {
+ cdcContentRl.setVisibility(View.GONE);
+ } else {
+ cdcContentTv.setText(content);
+ }
+
+ if (positiveBtnAction == null && negativeBtnAction == null) {
+ cdcBottomRl.setVisibility(View.GONE);
+ } else {
+ if (positiveBtnAction != null) {
+ ClickUtils.applyPressedBgDark(cdcBottomPositiveTv);
+ cdcBottomPositiveTv.setText(positiveBtnAction.first);
+ cdcBottomPositiveTv.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ positiveBtnAction.second.onClick(v);
+ }
+ });
+ }
+ if (negativeBtnAction != null) {
+ ClickUtils.applyPressedBgDark(cdcBottomNegativeTv);
+ cdcBottomNegativeTv.setText(negativeBtnAction.first);
+ cdcBottomNegativeTv.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ negativeBtnAction.second.onClick(v);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void setWindowStyle(Window window) {
+ }
+
+ @Override
+ public void onCancel(BaseDialogFragment dialog) {
+
+ }
+
+ @Override
+ public void onDismiss(BaseDialogFragment dialog) {
+
+ }
+ });
+ return this;
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogLoading.java b/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogLoading.java
new file mode 100644
index 0000000000..b40a10f5cc
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/dialog/CommonDialogLoading.java
@@ -0,0 +1,65 @@
+package com.blankj.common.dialog;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.blankj.base.dialog.BaseDialogFragment;
+import com.blankj.base.dialog.DialogLayoutCallback;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.BarUtils;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/29
+ * desc :
+ *
+ */
+public class CommonDialogLoading extends BaseDialogFragment {
+
+ public CommonDialogLoading init(Context context, final Runnable onCancelListener) {
+ super.init(context, new DialogLayoutCallback() {
+ @Override
+ public int bindTheme() {
+ return R.style.CommonLoadingDialogStyle;
+ }
+
+ @Override
+ public int bindLayout() {
+ return R.layout.common_dialog_loading;
+ }
+
+ @Override
+ public void initView(BaseDialogFragment dialog, View contentView) {
+ if (onCancelListener == null) {
+ setCancelable(false);
+ } else {
+ setCancelable(true);
+ }
+ }
+
+ @Override
+ public void setWindowStyle(final Window window) {
+ window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
+ BarUtils.setStatusBarColor(window, Color.TRANSPARENT);
+ }
+
+ @Override
+ public void onCancel(BaseDialogFragment dialog) {
+ if (onCancelListener != null) {
+ onCancelListener.run();
+ }
+ }
+
+ @Override
+ public void onDismiss(BaseDialogFragment dialog) {
+
+ }
+ });
+ return this;
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/fragment/CommonFragment.java b/lib/common/src/main/java/com/blankj/common/fragment/CommonFragment.java
new file mode 100644
index 0000000000..46f4b24115
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/fragment/CommonFragment.java
@@ -0,0 +1,114 @@
+package com.blankj.common.fragment;
+
+import android.os.Bundle;
+import android.view.View;
+
+import com.blankj.base.BaseFragment;
+import com.blankj.base.rv.BaseItemAdapter;
+import com.blankj.base.rv.RecycleViewDivider;
+import com.blankj.common.R;
+import com.blankj.common.activity.CommonActivityItemsView;
+import com.blankj.common.item.CommonItem;
+
+import java.util.List;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/11/03
+ * desc :
+ *
+ */
+public class CommonFragment extends BaseFragment {
+
+ private CommonActivityItemsView mItemsView;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // items view
+ ///////////////////////////////////////////////////////////////////////////
+ public CommonActivityItemsView bindItemsView() {
+ return null;
+ }
+
+ public List bindItems() {
+ return null;
+ }
+
+ @CallSuper
+ @Override
+ public void initData(@Nullable Bundle bundle) {
+ mItemsView = bindItemsView();
+ if (mItemsView == null) {
+ List items = bindItems();
+ if (items != null) {
+ mItemsView = new CommonActivityItemsView(mActivity, items);
+ }
+ }
+ }
+
+ @Override
+ public int bindLayout() {
+ return View.NO_ID;
+ }
+
+ @Override
+ public void setContentView() {
+ if (mItemsView != null) {
+ mContentView = mInflater.inflate(mItemsView.bindLayout(), null);
+ } else {
+ super.setContentView();
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void initView(@Nullable Bundle savedInstanceState, @Nullable View contentView) {
+ if (mItemsView != null) {
+ mItemsView.initView();
+ }
+ }
+
+ @Override
+ public void doBusiness() {
+ log("doBusiness");
+ }
+
+ @Override
+ public void onDebouncingClick(@NonNull View view) {
+ }
+
+
+ public CommonActivityItemsView getItemsView() {
+ return mItemsView;
+ }
+
+ private BaseItemAdapter mCommonItemAdapter;
+
+ public void setCommonItems(RecyclerView rv, List items) {
+ mCommonItemAdapter = new BaseItemAdapter<>();
+ mCommonItemAdapter.setItems(items);
+ rv.setAdapter(mCommonItemAdapter);
+ rv.setLayoutManager(new LinearLayoutManager(mActivity));
+ rv.addItemDecoration(new RecycleViewDivider(mActivity, RecycleViewDivider.VERTICAL, R.drawable.common_item_divider));
+ }
+
+ public void updateCommonItems(List data) {
+ mCommonItemAdapter.setItems(data);
+ mCommonItemAdapter.notifyDataSetChanged();
+ }
+
+ public void updateCommonItem(int position) {
+ mCommonItemAdapter.notifyItemChanged(position);
+ }
+
+ public BaseItemAdapter getCommonItemAdapter() {
+ return mCommonItemAdapter;
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt b/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt
new file mode 100644
index 0000000000..1df23cb1a4
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/helper/PermissionHelper.kt
@@ -0,0 +1,96 @@
+package com.blankj.common.helper
+
+import android.content.Context
+import android.util.Pair
+import android.view.View
+import com.blankj.common.R
+import com.blankj.common.dialog.CommonDialogContent
+import com.blankj.utilcode.constant.PermissionConstants
+import com.blankj.utilcode.util.*
+
+/**
+ * ```
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2018/01/06
+ * desc : helper about permission
+ * ```
+ */
+object PermissionHelper {
+
+ fun request(context: Context, callback: PermissionUtils.SimpleCallback,
+ @PermissionConstants.PermissionGroup vararg permissions: String) {
+ PermissionUtils.permission(*permissions)
+ .rationale { activity, shouldRequest -> showRationaleDialog(activity, shouldRequest) }
+ .callback(object : PermissionUtils.SingleCallback {
+ override fun callback(isAllGranted: Boolean, granted: MutableList,
+ deniedForever: MutableList, denied: MutableList) {
+ LogUtils.d(isAllGranted, granted, deniedForever, denied)
+ if (isAllGranted) {
+ callback.onGranted()
+ return
+ }
+ if (deniedForever.isNotEmpty()) {
+ showOpenAppSettingDialog(context)
+ return
+ }
+ val activity = ActivityUtils.getActivityByContext(context)
+ if (activity != null) {
+ SnackbarUtils.with(activity.findViewById(android.R.id.content))
+ .setMessage("Permission denied: ${permissions2String(denied)}")
+ .showError(true)
+ }
+ callback.onDenied()
+ }
+
+ fun permissions2String(permissions: MutableList): String {
+ if (permissions.isEmpty()) return "[]"
+ val sb: StringBuilder = StringBuilder()
+ for (permission in permissions) {
+ sb.append(", " + permission.substring(permission.lastIndexOf('.') + 1))
+ }
+ return "[${sb.substring(2)}]"
+ }
+ })
+ .request()
+ }
+
+ fun showRationaleDialog(context: Context, shouldRequest: PermissionUtils.OnRationaleListener.ShouldRequest) {
+ CommonDialogContent().init(context,
+ StringUtils.getString(android.R.string.dialog_alert_title),
+ StringUtils.getString(R.string.permission_rationale_message),
+ Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener {
+ shouldRequest.again(true)
+ }),
+ Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener {
+ shouldRequest.again(false)
+ }))
+ .show()
+ }
+
+ fun showExplainDialog(context: Context, denied: List, shouldRequest: PermissionUtils.OnExplainListener.ShouldRequest) {
+ CommonDialogContent().init(context,
+ StringUtils.getString(android.R.string.dialog_alert_title),
+ "We needs the permissions of $denied to test the utils of permission.",
+ Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener {
+ shouldRequest.start(true)
+ }),
+ Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener {
+ ToastUtils.showShort("request failed.")
+ shouldRequest.start(false)
+ }))
+ .show()
+ }
+
+ fun showOpenAppSettingDialog(context: Context) {
+ CommonDialogContent().init(context,
+ StringUtils.getString(android.R.string.dialog_alert_title),
+ StringUtils.getString(R.string.permission_denied_forever_message),
+ Pair(StringUtils.getString(android.R.string.ok), View.OnClickListener {
+ PermissionUtils.launchAppDetailsSettings()
+ }),
+ Pair(StringUtils.getString(android.R.string.cancel), View.OnClickListener {
+ }))
+ .show()
+ }
+}
\ No newline at end of file
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItem.java b/lib/common/src/main/java/com/blankj/common/item/CommonItem.java
new file mode 100644
index 0000000000..c04ef136ab
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItem.java
@@ -0,0 +1,41 @@
+package com.blankj.common.item;
+
+import com.blankj.base.rv.BaseItem;
+import com.blankj.base.rv.ItemViewHolder;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.ColorUtils;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/25
+ * desc :
+ *
+ */
+public class CommonItem extends BaseItem {
+
+ private int backgroundColor = ColorUtils.getColor(R.color.lightGray);
+
+ public CommonItem(int layoutId) {
+ super(layoutId);
+ }
+
+ @CallSuper
+ @Override
+ public void bind(@NonNull final ItemViewHolder holder, int position) {
+ holder.itemView.setBackgroundColor(backgroundColor);
+ }
+
+ public CommonItem setBackgroundColor(int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemClick.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemClick.java
new file mode 100644
index 0000000000..3db0b7caed
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemClick.java
@@ -0,0 +1,137 @@
+package com.blankj.common.item;
+
+import android.view.View;
+import android.widget.TextView;
+
+import com.blankj.base.rv.ItemViewHolder;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.ClickUtils;
+import com.blankj.utilcode.util.StringUtils;
+import com.blankj.utilcode.util.Utils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/31
+ * desc :
+ *
+ */
+public class CommonItemClick extends CommonItem {
+
+ private CharSequence mTitle;
+ private CharSequence mContent;
+ private boolean mIsJump;
+
+ public CommonItemClick(@StringRes int title) {
+ this(StringUtils.getString(title), "", false, null);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title) {
+ this(title, "", false, null);
+ }
+
+ public CommonItemClick(@StringRes int title, boolean isJump) {
+ this(StringUtils.getString(title), "", isJump);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, boolean isJump) {
+ this(title, "", isJump, null);
+ }
+
+ public CommonItemClick(@StringRes int title, CharSequence content) {
+ this(StringUtils.getString(title), content, false, null);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, CharSequence content) {
+ this(title, content, false, null);
+ }
+
+ public CommonItemClick(@StringRes int title, CharSequence content, boolean isJump) {
+ this(StringUtils.getString(title), content, isJump);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, CharSequence content, boolean isJump) {
+ this(title, content, isJump, null);
+ }
+
+ public CommonItemClick(@StringRes int title, final Runnable simpleClickListener) {
+ this(StringUtils.getString(title), "", false, simpleClickListener);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, final Runnable simpleClickListener) {
+ this(title, "", false, simpleClickListener);
+ }
+
+ public CommonItemClick(@StringRes int title, boolean isJump, final Runnable simpleClickListener) {
+ this(StringUtils.getString(title), "", isJump, simpleClickListener);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, boolean isJump, final Runnable simpleClickListener) {
+ this(title, "", isJump, simpleClickListener);
+ }
+
+ public CommonItemClick(@StringRes int title, CharSequence content, final Runnable simpleClickListener) {
+ this(StringUtils.getString(title), content, false, simpleClickListener);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, CharSequence content, final Runnable simpleClickListener) {
+ this(title, content, false, simpleClickListener);
+ }
+
+ public CommonItemClick(@StringRes int title, CharSequence content, boolean isJump, final Runnable simpleClickListener) {
+ this(StringUtils.getString(title), content, isJump, simpleClickListener);
+ }
+
+ public CommonItemClick(@NonNull CharSequence title, CharSequence content, boolean isJump, final Runnable simpleClickListener) {
+ super(R.layout.common_item_title_click);
+ mTitle = title;
+ mContent = content;
+ mIsJump = isJump;
+ if (simpleClickListener == null) return;
+ setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(ItemViewHolder holder, CommonItemClick item, int position) {
+ if (simpleClickListener != null) {
+ simpleClickListener.run();
+ }
+ }
+ });
+ }
+
+ public CommonItemClick setOnClickUpdateContentListener(@NonNull final Utils.Supplier supplier) {
+ setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(ItemViewHolder holder, CommonItemClick item, int position) {
+ item.mContent = supplier.get();
+ update();
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public void bind(@NonNull ItemViewHolder holder, int position) {
+ super.bind(holder, position);
+ final TextView titleTv = holder.findViewById(R.id.commonItemTitleTv);
+ final TextView contentTv = holder.findViewById(R.id.commonItemContentTv);
+
+ titleTv.setText(mTitle);
+ contentTv.setText(mContent);
+
+ ClickUtils.applyPressedBgDark(holder.itemView);
+ holder.findViewById(R.id.commonItemGoIv).setVisibility(mIsJump ? View.VISIBLE : View.GONE);
+ }
+
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ update();
+ }
+
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemImage.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemImage.java
new file mode 100644
index 0000000000..207746bf85
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemImage.java
@@ -0,0 +1,46 @@
+package com.blankj.common.item;
+
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.blankj.base.rv.ItemViewHolder;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.StringUtils;
+import com.blankj.utilcode.util.Utils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/31
+ * desc :
+ *
+ */
+public class CommonItemImage extends CommonItem {
+
+ private CharSequence mTitle;
+ private Utils.Consumer mSetImageConsumer;
+
+ public CommonItemImage(@StringRes int title, @NonNull Utils.Consumer setImageConsumer) {
+ this(StringUtils.getString(title), setImageConsumer);
+ }
+
+ public CommonItemImage(@NonNull CharSequence title, @NonNull Utils.Consumer setImageConsumer) {
+ super(R.layout.common_item_title_image);
+ mTitle = title;
+ mSetImageConsumer = setImageConsumer;
+ }
+
+ @Override
+ public void bind(@NonNull ItemViewHolder holder, int position) {
+ super.bind(holder, position);
+ final TextView titleTv = holder.findViewById(R.id.commonItemTitleTv);
+
+ titleTv.setText(mTitle);
+ ImageView commonItemIv = holder.findViewById(R.id.commonItemIv);
+ mSetImageConsumer.accept(commonItemIv);
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
new file mode 100644
index 0000000000..14ff005851
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
@@ -0,0 +1,106 @@
+package com.blankj.common.item;
+
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.blankj.base.rv.ItemViewHolder;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.StringUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/31
+ * desc :
+ *
+ */
+public class CommonItemSeekBar extends CommonItem {
+
+ private CharSequence mTitle;
+ private CharSequence mContent;
+ private int mMaxProgress;
+ private int mCurProgress;
+ private ProgressListener mProgressListener;
+
+ public CommonItemSeekBar(@StringRes int title, int maxProgress, @NonNull ProgressListener listener) {
+ this(StringUtils.getString(title), maxProgress, listener);
+ }
+
+ public CommonItemSeekBar(@NonNull CharSequence title, int maxProgress, @NonNull ProgressListener listener) {
+ super(R.layout.common_item_title_seekbar);
+ mTitle = title;
+ mMaxProgress = maxProgress;
+ mCurProgress = listener.getCurValue();
+ mProgressListener = listener;
+ mContent = String.valueOf(mCurProgress);
+ }
+
+
+ @Override
+ public void bind(@NonNull ItemViewHolder holder, int position) {
+ super.bind(holder, position);
+ final TextView titleTv = holder.findViewById(R.id.commonItemTitleTv);
+ final TextView contentTv = holder.findViewById(R.id.commonItemContentTv);
+
+ titleTv.setText(mTitle);
+ contentTv.setText(mContent);
+
+ final SeekBar seekBar = holder.findViewById(R.id.commonItemSb);
+ seekBar.setMax(mMaxProgress);
+ seekBar.setProgress(mCurProgress);
+ holder.itemView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return seekBar.dispatchTouchEvent(event);
+ }
+ });
+ seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mProgressListener.onProgressChanged(seekBar, progress, fromUser);
+ int curValue = mProgressListener.getCurValue();
+ mCurProgress = curValue;
+ contentTv.setText(String.valueOf(curValue));
+ seekBar.setProgress(curValue);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mProgressListener.onStartTrackingTouch(seekBar);
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mProgressListener.onStopTrackingTouch(seekBar);
+ }
+ });
+ }
+
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ update();
+ }
+
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ public static abstract class ProgressListener implements SeekBar.OnSeekBarChangeListener {
+
+ public abstract int getCurValue();
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ }
+}
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemSwitch.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemSwitch.java
new file mode 100644
index 0000000000..cbb9b0792a
--- /dev/null
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemSwitch.java
@@ -0,0 +1,87 @@
+package com.blankj.common.item;
+
+import android.annotation.SuppressLint;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.blankj.base.rv.ItemViewHolder;
+import com.blankj.common.R;
+import com.blankj.utilcode.util.ClickUtils;
+import com.blankj.utilcode.util.StringUtils;
+import com.blankj.utilcode.util.Utils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+/**
+ *
+ * author: blankj
+ * blog : http://blankj.com
+ * time : 2019/10/31
+ * desc :
+ *
+ */
+public class CommonItemSwitch extends CommonItem {
+
+ private CharSequence mTitle;
+ private CharSequence mContent;
+ private boolean mState;
+ private Utils.Supplier mGetStateSupplier;
+ private Utils.Consumer mSetStateConsumer;
+
+
+ public CommonItemSwitch(@StringRes int title, @NonNull Utils.Supplier getStateSupplier, @NonNull Utils.Consumer setStateConsumer) {
+ this(StringUtils.getString(title), getStateSupplier, setStateConsumer);
+ }
+
+ public CommonItemSwitch(@NonNull CharSequence title, @NonNull Utils.Supplier