diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..081b737fd
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 数据源本地存储已忽略文件
+/dataSources/
+/dataSources.local.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
diff --git a/.idea/Dokit.iml b/.idea/Dokit.iml
new file mode 100644
index 000000000..d6ebd4805
--- /dev/null
+++ b/.idea/Dokit.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 000000000..919ce1f1f
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 000000000..a55e7a179
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 000000000..69d1d89f9
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 000000000..6560a9898
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..c56cef51c
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..e94585c4d
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..00d3bd654
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/app/build.gradle b/Android/app/build.gradle
index 3efa18f64..c2fef772a 100644
--- a/Android/app/build.gradle
+++ b/Android/app/build.gradle
@@ -200,11 +200,11 @@ dependencies {
implementation rootProject.ext.dependencies["easypermissions"]
releaseImplementation rootProject.ext.dependencies["okgo"]
//高德地图定位
- implementation rootProject.ext.dependencies["amap_location"]
+// implementation rootProject.ext.dependencies["amap_location"]
//高德地图
// implementation rootProject.ext.dependencies["amap_map3d"]
//高德搜索
- implementation rootProject.ext.dependencies["amap_search"]
+// implementation rootProject.ext.dependencies["amap_search"]
implementation rootProject.ext.dependencies["amap_navi"]
//腾讯地图定位
// implementation rootProject.ext.dependencies["tencent_location"]
diff --git a/Android/dokit/src/main/AndroidManifest.xml b/Android/dokit/src/main/AndroidManifest.xml
index df38c255c..02e27445b 100644
--- a/Android/dokit/src/main/AndroidManifest.xml
+++ b/Android/dokit/src/main/AndroidManifest.xml
@@ -53,7 +53,9 @@
android:name=".kit.connect.DoKitScanActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|stateUnchanged" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Android/dokit/src/main/assets/dokit_system_kits.json b/Android/dokit/src/main/assets/dokit_system_kits.json
index f0ba72a1a..c883a8504 100644
--- a/Android/dokit/src/main/assets/dokit_system_kits.json
+++ b/Android/dokit/src/main/assets/dokit_system_kits.json
@@ -96,7 +96,12 @@
"allClassName": "com.didichuxing.doraemonkit.kit.h5_help.H5Kit",
"checked": true,
"innerKitId": "dokit_sdk_comm_ck_h5kit"
- }
+ },
+ {
+ "allClassName": "com.didichuxing.doraemonkit.kit.permissionlist.PermissionListKit",
+ "checked": true,
+ "innerKitId": "dokit_sdk_platform_ck_permission"
+ }
]
},
{
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/BaseViewHolder.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/BaseViewHolder.java
new file mode 100644
index 000000000..01a49a37e
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/BaseViewHolder.java
@@ -0,0 +1,141 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.util.SparseArray;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.databinding.DataBindingUtil;
+import androidx.databinding.ViewDataBinding;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * 通用的RecyclerView.ViewHolder。提供了根据viewId获取View的方法。
+ * 提供了对View、TextView、ImageView的常用设置方法。
+ */
+public class BaseViewHolder extends RecyclerView.ViewHolder {
+
+ private SparseArray mViews;
+ public boolean isExpanded;
+
+ public BaseViewHolder(View itemView) {
+ super(itemView);
+ mViews = new SparseArray<>();
+ isExpanded=false;
+ }
+
+ /**
+ * 设置、查看子项是否扩展
+ * @return
+ */
+ public boolean isExpanded() {
+ return isExpanded;
+ }
+
+ public void setExpanded(boolean expanded) {
+ isExpanded = expanded;
+ }
+
+
+ /**
+ * 获取item对应的ViewDataBinding对象
+ *
+ * @param
+ * @return
+ */
+ public T getBinding() {
+ return DataBindingUtil.getBinding(this.itemView);
+ }
+
+ /**
+ * 根据View Id 获取对应的View
+ *
+ * @param viewId
+ * @param
+ * @return
+ */
+ public T get(int viewId) {
+ View view = mViews.get(viewId);
+ if (view == null) {
+ view = this.itemView.findViewById(viewId);
+ mViews.put(viewId, view);
+ }
+ return (T) view;
+ }
+
+ //******** 提供对View、TextView、ImageView的常用设置方法 ******//
+ public String getText(int viewId) {
+ TextView tv = get(viewId);
+ return tv.getText().toString();
+ }
+
+ public BaseViewHolder setText(int viewId, CharSequence text) {
+ TextView tv = get(viewId);
+ tv.setText(text);
+ return this;
+ }
+
+ public BaseViewHolder setText(int viewId, int textRes) {
+ TextView tv = get(viewId);
+ tv.setText(textRes);
+ return this;
+ }
+
+ public BaseViewHolder setTextColor(int viewId, int textColor) {
+ TextView view = get(viewId);
+ view.setTextColor(textColor);
+ return this;
+ }
+
+ public BaseViewHolder setTextSize(int viewId, float size) {
+ TextView view = get(viewId);
+ view.setTextSize(size);
+ return this;
+ }
+
+ public BaseViewHolder setImageResource(int viewId, int resId) {
+ ImageView view = get(viewId);
+ view.setImageResource(resId);
+ return this;
+ }
+
+ public BaseViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
+ ImageView view = get(viewId);
+ view.setImageBitmap(bitmap);
+ return this;
+ }
+
+
+ public BaseViewHolder setImageDrawable(int viewId, Drawable drawable) {
+ ImageView view = get(viewId);
+ view.setImageDrawable(drawable);
+ return this;
+ }
+
+
+ public BaseViewHolder setBackgroundColor(int viewId, int color) {
+ View view = get(viewId);
+ view.setBackgroundColor(color);
+ return this;
+ }
+
+ public BaseViewHolder setBackgroundRes(int viewId, int backgroundRes) {
+ View view = get(viewId);
+ view.setBackgroundResource(backgroundRes);
+ return this;
+ }
+
+ public BaseViewHolder setVisible(int viewId, boolean visible) {
+ View view = get(viewId);
+ view.setVisibility(visible ? View.VISIBLE : View.GONE);
+ return this;
+ }
+
+ public BaseViewHolder setVisible(int viewId, int visible) {
+ View view = get(viewId);
+ view.setVisibility(visible);
+ return this;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableActivity.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableActivity.java
new file mode 100644
index 000000000..8dea08833
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableActivity.java
@@ -0,0 +1,185 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.graphics.Color;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.didichuxing.doraemonkit.R;
+import com.didichuxing.doraemonkit.widget.titlebar.HomeTitleBar;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+/**
+ * Created by lmh 2022/6/14
+ */
+public class ExpandableActivity extends AppCompatActivity {
+ private HashMap permissonmap; //获取预处理的所有权限map
+ private ArrayList PermissionInfoList; //获取预处理的所有权限list
+ public ArrayList normalList;
+ public ArrayList signatureList;
+ public ArrayList dangerousList;
+ public ArrayList notclassfied;
+
+ private RecyclerView rvList;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getSupportActionBar().hide(); //隐藏标题栏
+ //获取分组的信息
+ normalList=new ArrayList<>();
+ signatureList=new ArrayList<>();
+ dangerousList=new ArrayList<>();
+ notclassfied=new ArrayList<>();
+ XMLparser Infoparser=new XMLparser(); //分组预处理,取得是安卓9的系统源码xml文件
+ InputStream path = null;
+ try {
+ path = getResources().getAssets().open("AndroidManifest_meta.xml");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ PermissionInfoList =Infoparser.parser(path);
+ permissonmap=Infoparser.getMap();
+ try {
+ getUsesPermission(this.getPackageName()); //对包权限进行分类
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ //设置adapter
+ setContentView(R.layout.dk_permission_list_activity_group_list);
+ HomeTitleBar titleBar = findViewById(R.id.title_bar);
+ titleBar.setListener(() -> finish());
+ rvList = (RecyclerView) findViewById(R.id.rv_list);
+ rvList.setLayoutManager(new LinearLayoutManager(this));
+ ArrayList>grouplist=new ArrayList<>();
+ grouplist.add(normalList);
+ grouplist.add(signatureList);
+ grouplist.add(dangerousList);
+ grouplist.add(notclassfied);
+ ExpandableAdapter adapter = new ExpandableAdapter(this, GroupModel.getExpandableGroups(PermissionInfoList,
+ grouplist));
+ adapter.setOnHeaderClickListener(new GroupedRecyclerViewAdapter.OnHeaderClickListener() {
+ @Override
+ public void onHeaderClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
+ int groupPosition) {
+ ExpandableAdapter expandableAdapter = (ExpandableAdapter) adapter;
+ if (expandableAdapter.isExpand(groupPosition)) {
+ expandableAdapter.collapseGroup(groupPosition);
+ } else {
+ expandableAdapter.expandGroup(groupPosition);
+ }
+ }
+ });
+ adapter.setOnChildClickListener(new GroupedRecyclerViewAdapter.OnChildClickListener() {
+ @Override
+ public void onChildClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
+ int groupPosition, int childPosition) {
+// Toast.makeText(ExpandableActivity.this, "子项:groupPosition = " + groupPosition+ ", childPosition = " + childPosition,Toast.LENGTH_LONG).show();
+ if (!holder.isExpanded()) { //如果当前是缩小的
+ holder.setBackgroundColor(R.id.all, Color.BLACK);
+ holder.setExpanded(true);
+ holder.setTextColor(R.id.tv_child,Color.WHITE);
+ if(holder.getText(R.id.p_group)!="notfound"){
+ holder.setVisible(R.id.p_group,true);
+ holder.setTextColor(R.id.p_group,Color.WHITE);
+ }
+ holder.setVisible(R.id.p_label,true);
+ holder.setTextColor(R.id.p_label,Color.WHITE);
+ holder.setVisible(R.id.p_description,true);
+ holder.setTextColor(R.id.p_description,Color.WHITE);
+ } else {
+ holder.setTextColor(R.id.tv_child,Color.BLACK);
+ holder.setBackgroundColor(R.id.all,Color.WHITE);
+ holder.setExpanded(false);
+ holder.setVisible(R.id.p_group,false);
+ holder.setVisible(R.id.p_label,false);
+ holder.setVisible(R.id.p_description,false);
+ }
+
+ }
+ });
+ rvList.setAdapter(adapter);
+
+ }
+
+ public static void openActivity(Context context) {
+ Intent intent = new Intent(context, ExpandableActivity.class);
+ context.startActivity(intent);
+ }
+ private void getUsesPermission(String packageName) throws PackageManager.NameNotFoundException {
+ PackageManager packageManager=this.getPackageManager();
+ PackageInfo packageInfo=packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+ String [] usesPermissionsArray=packageInfo.requestedPermissions;
+ System.out.println(usesPermissionsArray.length);
+
+ for (int i = 0; i < usesPermissionsArray.length; i++) {
+ try {
+ //得到每个权限的名字,如:android.permission.INTERNET
+ String usesPermissionName=usesPermissionsArray[i];
+ MyPermissionInfo p= permissonmap.get(usesPermissionName);
+
+ //通过usesPermissionName获取该权限的详细信息
+ PermissionInfo permissionInfo=packageManager.getPermissionInfo(usesPermissionName, 0);
+ //获取该权限的标签信息,比如:完全的网络访问权限
+ String permissionLabel=permissionInfo.loadLabel(packageManager).toString();
+ //获取该权限的详细描述信息,比如:允许该应用创建网络套接字和使用自定义网络协议
+ //浏览器和其他某些应用提供了向互联网发送数据的途径,因此应用无需该权限即可向互联网发送数据.
+ String permissionDescription=permissionInfo.loadDescription(packageManager).toString();
+ p.setDescription(permissionDescription);
+ p.setLabel(permissionLabel);
+
+ if(checkname(p.getProtectionLevel(),"normal")){
+ normalList.add(p);
+ }
+ else if(checkname(p.getProtectionLevel(),"signature ")){
+ signatureList.add(p);
+ }
+ else {
+ dangerousList.add(p);
+ }
+ } catch (Exception e) {
+ // TODO: handle exception
+ String invalidname=usesPermissionsArray[i];
+ System.out.println(invalidname+"is not found in package");
+ if(permissonmap.containsKey(invalidname)){
+ MyPermissionInfo p=permissonmap.get(invalidname);
+ if(checkname(p.getProtectionLevel(),"normal")){
+ normalList.add(p);
+ }
+ else if(checkname(p.getProtectionLevel(),"signature")){
+ signatureList.add(p);
+ }
+ else {
+ dangerousList.add(p);
+ }
+ }
+ else{
+ MyPermissionInfo p=new MyPermissionInfo(invalidname,"","","");
+ notclassfied.add(p);
+ }
+ }
+ }
+ }
+ public boolean checkname(String name,String element){
+ if(name.indexOf(element)>-1){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableAdapter.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableAdapter.java
new file mode 100644
index 000000000..0438c87d9
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/ExpandableAdapter.java
@@ -0,0 +1,163 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+import android.content.Context;
+import android.widget.ImageView;
+
+import com.didichuxing.doraemonkit.R;
+
+
+import com.didichuxing.doraemonkit.kit.permissionlist.entity.ChildEntity;
+import com.didichuxing.doraemonkit.kit.permissionlist.entity.ExpandableGroupEntity;
+
+
+import java.util.ArrayList;
+
+/**
+ * 可展开收起的Adapter。他跟普通的{GroupedListAdapter}基本是一样的。
+ * 它只是利用了{@link GroupedRecyclerViewAdapter}的
+ * 删除一组里的所有子项{@link GroupedRecyclerViewAdapter#notifyChildrenRemoved(int)}} 和
+ * 插入一组里的所有子项{@link GroupedRecyclerViewAdapter#notifyChildrenInserted(int)}
+ * 两个方法达到列表的展开和收起的效果。
+ * 这种列表类似于{@link ExpandableListView}的效果。
+ * 这里我把列表的组尾去掉是为了效果上更像ExpandableListView。
+ */
+public class ExpandableAdapter extends GroupedRecyclerViewAdapter {
+
+ private ArrayList mGroups;
+
+ public ExpandableAdapter(Context context, ArrayList groups) {
+ super(context);
+ mGroups = groups;
+ }
+
+ @Override
+ public int getGroupCount() {
+ return mGroups == null ? 0 : mGroups.size();
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ //如果当前组收起,就直接返回0,否则才返回子项数。这是实现列表展开和收起的关键。
+ if (!isExpand(groupPosition)) {
+ return 0;
+ }
+ ArrayList children = mGroups.get(groupPosition).getChildren();
+ return children == null ? 0 : children.size();
+ }
+
+ @Override
+ public boolean hasHeader(int groupPosition) {
+ return true;
+ }
+
+ @Override
+ public boolean hasFooter(int groupPosition) {
+ return false;
+ }
+
+ @Override
+ public int getHeaderLayout(int viewType) {
+ return R.layout.dk_permission_list_adapter_expandable_header;
+ }
+
+ @Override
+ public int getFooterLayout(int viewType) {
+ return 0;
+ }
+
+ @Override
+ public int getChildLayout(int viewType) {
+ return R.layout.dk_permission_list_adapter_child;
+ }
+
+ @Override
+ public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
+ ExpandableGroupEntity entity = mGroups.get(groupPosition);
+ holder.setText(R.id.tv_expandable_header, entity.getHeader());
+ ImageView ivState = holder.get(R.id.iv_state);
+ if(entity.isExpand()){
+ ivState.setRotation(90);
+ } else {
+ ivState.setRotation(0);
+ }
+ }
+
+ @Override
+ public void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition) {
+ }
+
+ @Override
+ public void onBindChildViewHolder(BaseViewHolder holder, int groupPosition, int childPosition) {
+ ChildEntity entity = mGroups.get(groupPosition).getChildren().get(childPosition);
+ holder.setText(R.id.tv_child, entity.getChild().getName());
+ if(entity.getChild().getPermissionGroup()==""){
+ holder.setText(R.id.p_group,"notfound");
+ }
+ else{
+ holder.setText(R.id.p_group, "Group: "+entity.getChild().getPermissionGroup());
+ }
+ holder.setText(R.id.p_label, "Label: "+entity.getChild().getLabel());
+ holder.setText(R.id.p_description, "Description: "+entity.getChild().getDescription());
+ }
+
+ /**
+ * 判断当前组是否展开
+ *
+ * @param groupPosition
+ * @return
+ */
+ public boolean isExpand(int groupPosition) {
+ ExpandableGroupEntity entity = mGroups.get(groupPosition);
+ return entity.isExpand();
+ }
+
+ /**
+ * 展开一个组
+ *
+ * @param groupPosition
+ */
+ public void expandGroup(int groupPosition) {
+ expandGroup(groupPosition, false);
+ }
+
+ /**
+ * 展开一个组
+ *
+ * @param groupPosition
+ * @param animate
+ */
+ public void expandGroup(int groupPosition, boolean animate) {
+ ExpandableGroupEntity entity = mGroups.get(groupPosition);
+ entity.setExpand(true);
+ if (animate) {
+ notifyChildrenInserted(groupPosition);
+ } else {
+ notifyDataChanged();
+ }
+ }
+
+ /**
+ * 收起一个组
+ *
+ * @param groupPosition
+ */
+ public void collapseGroup(int groupPosition) {
+ collapseGroup(groupPosition, false);
+ }
+
+ /**
+ * 收起一个组
+ *
+ * @param groupPosition
+ * @param animate
+ */
+ public void collapseGroup(int groupPosition, boolean animate) {
+ ExpandableGroupEntity entity = mGroups.get(groupPosition);
+ entity.setExpand(false);
+ if (animate) {
+ notifyChildrenRemoved(groupPosition);
+ } else {
+ notifyDataChanged();
+ }
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupModel.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupModel.java
new file mode 100644
index 000000000..c7592fcc0
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupModel.java
@@ -0,0 +1,43 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+import com.didichuxing.doraemonkit.kit.permissionlist.entity.ChildEntity;
+import com.didichuxing.doraemonkit.kit.permissionlist.entity.ExpandableGroupEntity;
+
+import java.util.ArrayList;
+
+/**
+ * Depiction:
+ * Author: teach
+ * Date: 2017/3/20 15:51
+ */
+public class GroupModel {
+
+ /**
+ * 获取可展开收起的组列表数据(默认展开)
+ *
+ * @param PermissionInfoList 所有权限列表
+ * @param grouplist 分类权限列表
+ * @return
+ */
+ public static ArrayList getExpandableGroups(ArrayList PermissionInfoList,
+ ArrayList> grouplist) {
+ String[] titlename=new String[]{"普通权限_normal","签名权限_signature","危险权限_dangerous","未分类权限"};
+ int sum=0;//总权限数目
+ for(ArrayList arr:grouplist){
+ sum+=arr.size();
+ }
+ ArrayList groups = new ArrayList<>();
+ for (int i = 0; i < grouplist.size(); i++) {
+ ArrayList children = new ArrayList<>();
+ ArrayList permissionlist=grouplist.get(i);
+ for (int j = 0; j < permissionlist.size(); j++) {
+ children.add(new ChildEntity(permissionlist.get(j)));
+ }
+ groups.add(new ExpandableGroupEntity(titlename[i]+" ("+permissionlist.size()+
+ "/"+sum+")",
+ "", true, children));
+ }
+ return groups;
+ }
+
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupStructure.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupStructure.java
new file mode 100644
index 000000000..6e7344577
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupStructure.java
@@ -0,0 +1,44 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+
+/**
+ * 这个类是用来记录分组列表中组的结构的。
+ * 通过GroupStructure记录每个组是否有头部,是否有尾部和子项的数量。从而能方便的计算
+ * 列表的长度和每个组的组头、组尾和子项在列表中的位置。
+ */
+public class GroupStructure {
+
+ private boolean hasHeader;
+ private boolean hasFooter;
+ private int childrenCount;
+
+ public GroupStructure(boolean hasHeader, boolean hasFooter, int childrenCount) {
+ this.hasHeader = hasHeader;
+ this.hasFooter = hasFooter;
+ this.childrenCount = childrenCount;
+ }
+
+ public boolean hasHeader() {
+ return hasHeader;
+ }
+
+ public void setHasHeader(boolean hasHeader) {
+ this.hasHeader = hasHeader;
+ }
+
+ public boolean hasFooter() {
+ return hasFooter;
+ }
+
+ public void setHasFooter(boolean hasFooter) {
+ this.hasFooter = hasFooter;
+ }
+
+ public int getChildrenCount() {
+ return childrenCount;
+ }
+
+ public void setChildrenCount(int childrenCount) {
+ this.childrenCount = childrenCount;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupedRecyclerViewAdapter.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupedRecyclerViewAdapter.java
new file mode 100644
index 000000000..89d854ae3
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/GroupedRecyclerViewAdapter.java
@@ -0,0 +1,1249 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.FrameLayout;
+
+import androidx.databinding.DataBindingUtil;
+import androidx.databinding.ViewDataBinding;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+import com.didichuxing.doraemonkit.R;
+
+import java.util.ArrayList;
+
+
+/**
+ * 通用的分组列表Adapter。通过它可以很方便的实现列表的分组效果。
+ * 这个类提供了一系列的对列表的更新、删除和插入等操作的方法。
+ * 使用者要使用这些方法的列表进行操作,而不要直接使用RecyclerView.Adapter的方法。
+ * 因为当分组列表发生变化时,需要及时更新分组列表的组结构{@link GroupedRecyclerViewAdapter#mStructures}
+ */
+public abstract class GroupedRecyclerViewAdapter
+ extends RecyclerView.Adapter {
+
+ public static final int TYPE_HEADER = R.integer.type_header;
+ public static final int TYPE_FOOTER = R.integer.type_footer;
+ public static final int TYPE_CHILD = R.integer.type_child;
+ public static final int TYPE_EMPTY = R.integer.type_empty;
+
+ private OnHeaderClickListener mOnHeaderClickListener;
+ private OnFooterClickListener mOnFooterClickListener;
+ private OnChildClickListener mOnChildClickListener;
+ private OnHeaderLongClickListener mOnHeaderLongClickListener;
+ private OnFooterLongClickListener mOnFooterLongClickListener;
+ private OnChildLongClickListener mOnChildLongClickListener;
+
+ protected Context mContext;
+ //保存分组列表的组结构
+ protected ArrayList mStructures = new ArrayList<>();
+ //数据是否发生变化。如果数据发生变化,要及时更新组结构。
+ private boolean isDataChanged;
+ private int mTempPosition;
+
+ private boolean mUseBinding;
+
+ // 是否显示空布局
+ private boolean showEmptyView = false;
+
+ public GroupedRecyclerViewAdapter(Context context) {
+ this(context, false);
+ }
+
+ public GroupedRecyclerViewAdapter(Context context, boolean useBinding) {
+ mContext = context;
+ mUseBinding = useBinding;
+ registerAdapterDataObserver(new GroupDataObserver());
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ structureChanged();
+ }
+
+ @Override
+ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
+ super.onViewAttachedToWindow(holder);
+
+ //处理StaggeredGridLayout,保证组头和组尾占满一行。
+ if (isStaggeredGridLayout(holder)) {
+ handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
+ }
+ }
+
+ private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
+ ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
+ if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
+ return true;
+ }
+ return false;
+ }
+
+ private void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
+ if (isEmptyPosition(position) || judgeType(position) == TYPE_HEADER || judgeType(position) == TYPE_FOOTER) {
+ StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams)
+ holder.itemView.getLayoutParams();
+ p.setFullSpan(true);
+ }
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == TYPE_EMPTY) {
+ return new BaseViewHolder(getEmptyView(parent));
+ } else {
+ if (mUseBinding) {
+ ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mContext),
+ getLayoutId(mTempPosition, viewType), parent, false);
+ return new BaseViewHolder(binding.getRoot());
+ } else {
+ View view = LayoutInflater.from(mContext).inflate(
+ getLayoutId(mTempPosition, viewType), parent, false);
+ return new BaseViewHolder(view);
+ }
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
+ int type = judgeType(position);
+ final int groupPosition = getGroupPositionForPosition(position);
+ if (type == TYPE_HEADER) {
+ if (mOnHeaderClickListener != null) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnHeaderClickListener != null) {
+ ViewParent parent = holder.itemView.getParent();
+ int gPosition = parent instanceof FrameLayout ? groupPosition : getGroupPositionForPosition(holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size()) {
+ mOnHeaderClickListener.onHeaderClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition);
+ }
+ }
+ }
+ });
+ }
+
+ if (mOnHeaderLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mOnHeaderLongClickListener != null) {
+ ViewParent parent = holder.itemView.getParent();
+ int gPosition = parent instanceof FrameLayout ? groupPosition : getGroupPositionForPosition(holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size()) {
+ return mOnHeaderLongClickListener.onHeaderLongClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition);
+ }
+ }
+ return false;
+ }
+ });
+ }
+ onBindHeaderViewHolder((BaseViewHolder) holder, groupPosition);
+ } else if (type == TYPE_FOOTER) {
+ if (mOnFooterClickListener != null) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnFooterClickListener != null) {
+ int gPosition = getGroupPositionForPosition(holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size()) {
+ mOnFooterClickListener.onFooterClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition);
+ }
+ }
+ }
+ });
+ }
+
+ if (mOnFooterLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mOnFooterLongClickListener != null) {
+ int gPosition = getGroupPositionForPosition(holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size()) {
+ return mOnFooterLongClickListener.onFooterLongClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition);
+ }
+ }
+ return false;
+ }
+ });
+ }
+ onBindFooterViewHolder((BaseViewHolder) holder, groupPosition);
+ } else if (type == TYPE_CHILD) {
+ int childPosition = getChildPositionForPosition(groupPosition, position);
+ if (mOnChildClickListener != null) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnChildClickListener != null) {
+ int gPosition = getGroupPositionForPosition(holder.getLayoutPosition());
+ int cPosition = getChildPositionForPosition(gPosition, holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size() && cPosition >= 0
+ && cPosition < mStructures.get(gPosition).getChildrenCount()) {
+ mOnChildClickListener.onChildClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition, cPosition);
+ }
+ }
+ }
+ });
+ }
+
+ if (mOnChildLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mOnChildLongClickListener != null) {
+ int gPosition = getGroupPositionForPosition(holder.getLayoutPosition());
+ int cPosition = getChildPositionForPosition(gPosition, holder.getLayoutPosition());
+ if (gPosition >= 0 && gPosition < mStructures.size() && cPosition >= 0
+ && cPosition < mStructures.get(gPosition).getChildrenCount()) {
+ return mOnChildLongClickListener.onChildLongClick(GroupedRecyclerViewAdapter.this,
+ (BaseViewHolder) holder, gPosition, cPosition);
+ }
+ }
+ return false;
+ }
+ });
+ }
+ onBindChildViewHolder((BaseViewHolder) holder, groupPosition, childPosition);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ if (isDataChanged) {
+ structureChanged();
+ }
+
+ int count = count();
+ if (count > 0) {
+ return count;
+ } else if (showEmptyView) {
+ // 显示空布局
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ public boolean isEmptyPosition(int position) {
+ return position == 0 && showEmptyView && count() == 0;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (isEmptyPosition(position)) {
+ // 空布局
+ return TYPE_EMPTY;
+ }
+ mTempPosition = position;
+ int groupPosition = getGroupPositionForPosition(position);
+ int type = judgeType(position);
+ if (type == TYPE_HEADER) {
+ return getHeaderViewType(groupPosition);
+ } else if (type == TYPE_FOOTER) {
+ return getFooterViewType(groupPosition);
+ } else if (type == TYPE_CHILD) {
+ int childPosition = getChildPositionForPosition(groupPosition, position);
+ return getChildViewType(groupPosition, childPosition);
+ }
+ return super.getItemViewType(position);
+ }
+
+ public int getHeaderViewType(int groupPosition) {
+ return TYPE_HEADER;
+ }
+
+ public int getFooterViewType(int groupPosition) {
+ return TYPE_FOOTER;
+ }
+
+ public int getChildViewType(int groupPosition, int childPosition) {
+ return TYPE_CHILD;
+ }
+
+ private int getLayoutId(int position, int viewType) {
+ int type = judgeType(position);
+ if (type == TYPE_HEADER) {
+ return getHeaderLayout(viewType);
+ } else if (type == TYPE_FOOTER) {
+ return getFooterLayout(viewType);
+ } else if (type == TYPE_CHILD) {
+ return getChildLayout(viewType);
+ }
+ return 0;
+ }
+
+ private int count() {
+ return countGroupRangeItem(0, mStructures.size());
+ }
+
+ /**
+ * 判断item的type 头部 尾部 和 子项
+ *
+ * @param position
+ * @return
+ */
+ public int judgeType(int position) {
+ int itemCount = 0;
+ int groupCount = mStructures.size();
+
+ for (int i = 0; i < groupCount; i++) {
+ GroupStructure structure = mStructures.get(i);
+ if (structure.hasHeader()) {
+ itemCount += 1;
+ if (position < itemCount) {
+ return TYPE_HEADER;
+ }
+ }
+
+ itemCount += structure.getChildrenCount();
+ if (position < itemCount) {
+ return TYPE_CHILD;
+ }
+
+ if (structure.hasFooter()) {
+ itemCount += 1;
+ if (position < itemCount) {
+ return TYPE_FOOTER;
+ }
+ }
+ }
+
+ return TYPE_EMPTY;
+ }
+
+ /**
+ * 重置组结构列表
+ */
+ private void structureChanged() {
+ mStructures.clear();
+ int groupCount = getGroupCount();
+ for (int i = 0; i < groupCount; i++) {
+ mStructures.add(new GroupStructure(hasHeader(i), hasFooter(i), getChildrenCount(i)));
+ }
+ isDataChanged = false;
+ }
+
+ /**
+ * 根据下标计算position所在的组(groupPosition)
+ *
+ * @param position 下标
+ * @return 组下标 groupPosition
+ */
+ public int getGroupPositionForPosition(int position) {
+ int count = 0;
+ int groupCount = mStructures.size();
+ for (int i = 0; i < groupCount; i++) {
+ count += countGroupItem(i);
+ if (position < count) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 根据下标计算position在组中位置(childPosition)
+ *
+ * @param groupPosition 所在的组
+ * @param position 下标
+ * @return 子项下标 childPosition
+ */
+ public int getChildPositionForPosition(int groupPosition, int position) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ int itemCount = countGroupRangeItem(0, groupPosition + 1);
+ GroupStructure structure = mStructures.get(groupPosition);
+ int p = structure.getChildrenCount() - (itemCount - position)
+ + (structure.hasFooter() ? 1 : 0);
+ if (p >= 0) {
+ return p;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 获取一个组的开始下标,这个下标可能是组头,可能是子项(如果没有组头)或者组尾(如果这个组只有组尾)
+ *
+ * @param groupPosition 组下标
+ * @return
+ */
+ public int getPositionForGroup(int groupPosition) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ return countGroupRangeItem(0, groupPosition);
+ } else {
+ return -1;
+ }
+
+ }
+
+ /**
+ * 获取一个组的组头下标 如果该组没有组头 返回-1
+ *
+ * @param groupPosition 组下标
+ * @return 下标
+ */
+ public int getPositionForGroupHeader(int groupPosition) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (!structure.hasHeader()) {
+ return -1;
+ }
+ return countGroupRangeItem(0, groupPosition);
+ }
+ return -1;
+ }
+
+ /**
+ * 获取一个组的组尾下标 如果该组没有组尾 返回-1
+ *
+ * @param groupPosition 组下标
+ * @return 下标
+ */
+ public int getPositionForGroupFooter(int groupPosition) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (!structure.hasFooter()) {
+ return -1;
+ }
+ return countGroupRangeItem(0, groupPosition + 1) - 1;
+ }
+ return -1;
+ }
+
+ /**
+ * 获取一个组指定的子项下标 如果没有 返回-1
+ *
+ * @param groupPosition 组下标
+ * @param childPosition 子项的组内下标
+ * @return 下标
+ */
+ public int getPositionForChild(int groupPosition, int childPosition) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (structure.getChildrenCount() > childPosition) {
+ int itemCount = countGroupRangeItem(0, groupPosition);
+ return itemCount + childPosition + (structure.hasHeader() ? 1 : 0);
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 计算一个组里有多少个Item(头加尾加子项)
+ *
+ * @param groupPosition
+ * @return
+ */
+ public int countGroupItem(int groupPosition) {
+ int itemCount = 0;
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (structure.hasHeader()) {
+ itemCount += 1;
+ }
+ itemCount += structure.getChildrenCount();
+ if (structure.hasFooter()) {
+ itemCount += 1;
+ }
+ }
+ return itemCount;
+ }
+
+ /**
+ * 计算多个组的项的总和
+ *
+ * @return
+ */
+ public int countGroupRangeItem(int start, int count) {
+ int itemCount = 0;
+ int size = mStructures.size();
+ for (int i = start; i < size && i < start + count; i++) {
+ itemCount += countGroupItem(i);
+ }
+ return itemCount;
+ }
+
+ /**
+ * 设置空布局显示。默认不显示
+ *
+ * @param isShow
+ */
+ public void showEmptyView(boolean isShow) {
+ if (isShow != showEmptyView) {
+ showEmptyView = isShow;
+ notifyDataChanged();
+ }
+ }
+
+ public boolean isShowEmptyView() {
+ return showEmptyView;
+ }
+
+ //****** 刷新操作 *****//
+
+ /**
+ * Use {@link #notifyDataChanged()} instead.
+ */
+ @Deprecated
+ public void changeDataSet() {
+ notifyDataChanged();
+ }
+
+ /**
+ * 通知数据列表刷新
+ */
+ public void notifyDataChanged() {
+ isDataChanged = true;
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Use {@link #notifyGroupChanged(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void changeGroup(int groupPosition) {
+ notifyGroupChanged(groupPosition);
+ }
+
+ /**
+ * 通知一组数据刷新,包括组头,组尾和子项
+ *
+ * @param groupPosition
+ */
+ public void notifyGroupChanged(int groupPosition) {
+ int index = getPositionForGroup(groupPosition);
+ int itemCount = countGroupItem(groupPosition);
+ if (index >= 0 && itemCount > 0) {
+ notifyItemRangeChanged(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyGroupRangeChanged(int, int)} instead.
+ *
+ * @param groupPosition
+ * @param count
+ */
+ @Deprecated
+ public void changeRangeGroup(int groupPosition, int count) {
+ notifyGroupRangeChanged(groupPosition, count);
+ }
+
+ /**
+ * 通知多组数据刷新,包括组头,组尾和子项
+ *
+ * @param groupPosition
+ */
+ public void notifyGroupRangeChanged(int groupPosition, int count) {
+ int index = getPositionForGroup(groupPosition);
+ int itemCount = 0;
+ if (groupPosition + count <= mStructures.size()) {
+ itemCount = countGroupRangeItem(groupPosition, groupPosition + count);
+ } else {
+ itemCount = countGroupRangeItem(groupPosition, mStructures.size());
+ }
+ if (index >= 0 && itemCount > 0) {
+ notifyItemRangeChanged(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyHeaderChanged(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void changeHeader(int groupPosition) {
+ notifyHeaderChanged(groupPosition);
+ }
+
+ /**
+ * 通知组头刷新
+ *
+ * @param groupPosition
+ */
+ public void notifyHeaderChanged(int groupPosition) {
+ int index = getPositionForGroupHeader(groupPosition);
+ if (index >= 0) {
+ notifyItemChanged(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyFooterChanged(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void changeFooter(int groupPosition) {
+ notifyFooterChanged(groupPosition);
+ }
+
+ /**
+ * 通知组尾刷新
+ *
+ * @param groupPosition
+ */
+ public void notifyFooterChanged(int groupPosition) {
+ int index = getPositionForGroupFooter(groupPosition);
+ if (index >= 0) {
+ notifyItemChanged(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildChanged(int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ @Deprecated
+ public void changeChild(int groupPosition, int childPosition) {
+ notifyChildChanged(groupPosition, childPosition);
+ }
+
+ /**
+ * 通知一组里的某个子项刷新
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ public void notifyChildChanged(int groupPosition, int childPosition) {
+ int index = getPositionForChild(groupPosition, childPosition);
+ if (index >= 0) {
+ notifyItemChanged(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildRangeChanged(int, int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ @Deprecated
+ public void changeRangeChild(int groupPosition, int childPosition, int count) {
+ notifyChildRangeChanged(groupPosition, childPosition, count);
+ }
+
+ /**
+ * 通知一组里的多个子项刷新
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ public void notifyChildRangeChanged(int groupPosition, int childPosition, int count) {
+ if (groupPosition < mStructures.size()) {
+ int index = getPositionForChild(groupPosition, childPosition);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (structure.getChildrenCount() >= childPosition + count) {
+ notifyItemRangeChanged(index, count);
+ } else {
+ notifyItemRangeChanged(index, structure.getChildrenCount() - childPosition);
+ }
+ }
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildrenChanged(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void changeChildren(int groupPosition) {
+ notifyChildrenChanged(groupPosition);
+ }
+
+ /**
+ * 通知一组里的所有子项刷新
+ *
+ * @param groupPosition
+ */
+ public void notifyChildrenChanged(int groupPosition) {
+ if (groupPosition >= 0 && groupPosition < mStructures.size()) {
+ int index = getPositionForChild(groupPosition, 0);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ notifyItemRangeChanged(index, structure.getChildrenCount());
+ }
+ }
+ }
+
+ //****** 删除操作 *****//
+
+ /**
+ * Use {@link #notifyDataRemoved()} instead.
+ */
+ @Deprecated
+ public void removeAll() {
+ notifyDataRemoved();
+ }
+
+ /**
+ * 通知所有数据删除
+ */
+ public void notifyDataRemoved() {
+ int count = countGroupRangeItem(0, mStructures.size());
+ mStructures.clear();
+ notifyItemRangeRemoved(0, count);
+ }
+
+ /**
+ * Use {@link #notifyGroupRemoved(int)} instead.
+ */
+ @Deprecated
+ public void removeGroup(int groupPosition) {
+ notifyGroupRemoved(groupPosition);
+ }
+
+ /**
+ * 通知一组数据删除,包括组头,组尾和子项
+ *
+ * @param groupPosition
+ */
+ public void notifyGroupRemoved(int groupPosition) {
+ int index = getPositionForGroup(groupPosition);
+ int itemCount = countGroupItem(groupPosition);
+ if (index >= 0 && itemCount > 0) {
+ mStructures.remove(groupPosition);
+ notifyItemRangeRemoved(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyGroupRangeRemoved(int, int)} instead.
+ */
+ @Deprecated
+ public void removeRangeGroup(int groupPosition, int count) {
+ notifyGroupRangeRemoved(groupPosition, count);
+ }
+
+ /**
+ * 通知多组数据删除,包括组头,组尾和子项
+ *
+ * @param groupPosition
+ */
+ public void notifyGroupRangeRemoved(int groupPosition, int count) {
+ int index = getPositionForGroup(groupPosition);
+ int itemCount = 0;
+ if (groupPosition + count <= mStructures.size()) {
+ itemCount = countGroupRangeItem(groupPosition, groupPosition + count);
+ } else {
+ itemCount = countGroupRangeItem(groupPosition, mStructures.size());
+ }
+ if (index >= 0 && itemCount > 0) {
+ mStructures.remove(groupPosition);
+ notifyItemRangeRemoved(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyHeaderRemoved(int)} instead.
+ */
+ @Deprecated
+ public void removeHeader(int groupPosition) {
+ notifyHeaderRemoved(groupPosition);
+ }
+
+ /**
+ * 通知组头删除
+ *
+ * @param groupPosition
+ */
+ public void notifyHeaderRemoved(int groupPosition) {
+ int index = getPositionForGroupHeader(groupPosition);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ structure.setHasHeader(false);
+ notifyItemRemoved(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyFooterRemoved(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void removeFooter(int groupPosition) {
+ notifyFooterRemoved(groupPosition);
+ }
+
+ /**
+ * 通知组尾删除
+ *
+ * @param groupPosition
+ */
+ public void notifyFooterRemoved(int groupPosition) {
+ int index = getPositionForGroupFooter(groupPosition);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ structure.setHasFooter(false);
+ notifyItemRemoved(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildRemoved(int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ @Deprecated
+ public void removeChild(int groupPosition, int childPosition) {
+ notifyChildRemoved(groupPosition, childPosition);
+ }
+
+ /**
+ * 通知一组里的某个子项删除
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ public void notifyChildRemoved(int groupPosition, int childPosition) {
+ int index = getPositionForChild(groupPosition, childPosition);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ structure.setChildrenCount(structure.getChildrenCount() - 1);
+ notifyItemRemoved(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildRangeRemoved(int, int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ @Deprecated
+ public void removeRangeChild(int groupPosition, int childPosition, int count) {
+ notifyChildRangeRemoved(groupPosition, childPosition, count);
+ }
+
+ /**
+ * 通知一组里的多个子项删除
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ public void notifyChildRangeRemoved(int groupPosition, int childPosition, int count) {
+ if (groupPosition < mStructures.size()) {
+ int index = getPositionForChild(groupPosition, childPosition);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ int childCount = structure.getChildrenCount();
+ int removeCount = count;
+ if (childCount < childPosition + count) {
+ removeCount = childCount - childPosition;
+ }
+ structure.setChildrenCount(childCount - removeCount);
+ notifyItemRangeRemoved(index, removeCount);
+ }
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildrenRemoved(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void removeChildren(int groupPosition) {
+ notifyChildrenRemoved(groupPosition);
+ }
+
+ /**
+ * 通知一组里的所有子项删除
+ *
+ * @param groupPosition
+ */
+ public void notifyChildrenRemoved(int groupPosition) {
+ if (groupPosition < mStructures.size()) {
+ int index = getPositionForChild(groupPosition, 0);
+ if (index >= 0) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ int itemCount = structure.getChildrenCount();
+ structure.setChildrenCount(0);
+ notifyItemRangeRemoved(index, itemCount);
+ }
+ }
+ }
+
+ //****** 插入操作 *****//
+
+ /**
+ * Use {@link #notifyGroupInserted(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void insertGroup(int groupPosition) {
+ notifyGroupInserted(groupPosition);
+ }
+
+ /**
+ * 通知一组数据插入
+ *
+ * @param groupPosition
+ */
+ public void notifyGroupInserted(int groupPosition) {
+ GroupStructure structure = new GroupStructure(hasHeader(groupPosition),
+ hasFooter(groupPosition), getChildrenCount(groupPosition));
+ if (groupPosition < mStructures.size()) {
+ mStructures.add(groupPosition, structure);
+ } else {
+ mStructures.add(structure);
+ groupPosition = mStructures.size() - 1;
+ }
+
+ int index = countGroupRangeItem(0, groupPosition);
+ int itemCount = countGroupItem(groupPosition);
+ if (itemCount > 0) {
+ notifyItemRangeInserted(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyGroupRangeInserted(int, int)} instead.
+ *
+ * @param groupPosition
+ * @param count
+ */
+ @Deprecated
+ public void insertRangeGroup(int groupPosition, int count) {
+ notifyGroupRangeInserted(groupPosition, count);
+ }
+
+ /**
+ * 通知多组数据插入
+ *
+ * @param groupPosition
+ * @param count
+ */
+ public void notifyGroupRangeInserted(int groupPosition, int count) {
+ ArrayList list = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ GroupStructure structure = new GroupStructure(hasHeader(i),
+ hasFooter(i), getChildrenCount(i));
+ list.add(structure);
+ }
+
+ if (groupPosition < mStructures.size()) {
+ mStructures.addAll(groupPosition, list);
+ } else {
+ mStructures.addAll(list);
+ groupPosition = mStructures.size() - list.size();
+ }
+
+ int index = countGroupRangeItem(0, groupPosition);
+ int itemCount = countGroupRangeItem(groupPosition, count);
+ if (itemCount > 0) {
+ notifyItemRangeInserted(index, itemCount);
+ }
+ }
+
+ /**
+ * Use {@link #notifyHeaderInserted(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void insertHeader(int groupPosition) {
+ notifyHeaderInserted(groupPosition);
+ }
+
+ /**
+ * 通知组头插入
+ *
+ * @param groupPosition
+ */
+ public void notifyHeaderInserted(int groupPosition) {
+ if (groupPosition < mStructures.size() && 0 > getPositionForGroupHeader(groupPosition)) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ structure.setHasHeader(true);
+ int index = countGroupRangeItem(0, groupPosition);
+ notifyItemInserted(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyFooterInserted(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void insertFooter(int groupPosition) {
+ notifyFooterInserted(groupPosition);
+ }
+
+ /**
+ * 通知组尾插入
+ *
+ * @param groupPosition
+ */
+ public void notifyFooterInserted(int groupPosition) {
+ if (groupPosition < mStructures.size() && 0 > getPositionForGroupFooter(groupPosition)) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ structure.setHasFooter(true);
+ int index = countGroupRangeItem(0, groupPosition + 1);
+ notifyItemInserted(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildInserted(int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ @Deprecated
+ public void insertChild(int groupPosition, int childPosition) {
+ notifyChildInserted(groupPosition, childPosition);
+ }
+
+ /**
+ * 通知一个子项到组里插入
+ *
+ * @param groupPosition
+ * @param childPosition
+ */
+ public void notifyChildInserted(int groupPosition, int childPosition) {
+ if (groupPosition < mStructures.size()) {
+ GroupStructure structure = mStructures.get(groupPosition);
+ int index = getPositionForChild(groupPosition, childPosition);
+ if (index < 0) {
+ index = countGroupRangeItem(0, groupPosition);
+ index += structure.hasHeader() ? 1 : 0;
+ index += structure.getChildrenCount();
+ }
+ structure.setChildrenCount(structure.getChildrenCount() + 1);
+ notifyItemInserted(index);
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildRangeInserted(int, int, int)} instead.
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ @Deprecated
+ public void insertRangeChild(int groupPosition, int childPosition, int count) {
+ notifyChildRangeInserted(groupPosition, childPosition, count);
+ }
+
+ /**
+ * 通知一组里的多个子项插入
+ *
+ * @param groupPosition
+ * @param childPosition
+ * @param count
+ */
+ public void notifyChildRangeInserted(int groupPosition, int childPosition, int count) {
+ if (groupPosition < mStructures.size()) {
+ int index = countGroupRangeItem(0, groupPosition);
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (structure.hasHeader()) {
+ index++;
+ }
+ if (childPosition < structure.getChildrenCount()) {
+ index += childPosition;
+ } else {
+ index += structure.getChildrenCount();
+ }
+ if (count > 0) {
+ structure.setChildrenCount(structure.getChildrenCount() + count);
+ notifyItemRangeInserted(index, count);
+ }
+ }
+ }
+
+ /**
+ * Use {@link #notifyChildrenInserted(int)} instead.
+ *
+ * @param groupPosition
+ */
+ @Deprecated
+ public void insertChildren(int groupPosition) {
+ notifyChildrenInserted(groupPosition);
+ }
+
+ /**
+ * 通知一组里的所有子项插入
+ *
+ * @param groupPosition
+ */
+ public void notifyChildrenInserted(int groupPosition) {
+ if (groupPosition < mStructures.size()) {
+ int index = countGroupRangeItem(0, groupPosition);
+ GroupStructure structure = mStructures.get(groupPosition);
+ if (structure.hasHeader()) {
+ index++;
+ }
+ int itemCount = getChildrenCount(groupPosition);
+ if (itemCount > 0) {
+ structure.setChildrenCount(itemCount);
+ notifyItemRangeInserted(index, itemCount);
+ }
+ }
+ }
+
+ //****** 设置点击事件 *****//
+
+ /**
+ * 设置组头点击事件
+ *
+ * @param listener
+ */
+ public void setOnHeaderClickListener(OnHeaderClickListener listener) {
+ mOnHeaderClickListener = listener;
+ }
+
+ /**
+ * 设置组尾点击事件
+ *
+ * @param listener
+ */
+ public void setOnFooterClickListener(OnFooterClickListener listener) {
+ mOnFooterClickListener = listener;
+ }
+
+ /**
+ * 设置子项长按事件
+ *
+ * @param listener
+ */
+ public void setOnChildLongClickListener(OnChildLongClickListener listener) {
+ mOnChildLongClickListener = listener;
+ }
+
+ /**
+ * 设置组头长按事件
+ *
+ * @param listener
+ */
+ public void setOnHeaderLongClickListener(OnHeaderLongClickListener listener) {
+ mOnHeaderLongClickListener = listener;
+ }
+
+ /**
+ * 设置组尾长按事件
+ *
+ * @param listener
+ */
+ public void setOnFooterLongClickListener(OnFooterLongClickListener listener) {
+ mOnFooterLongClickListener = listener;
+ }
+
+ /**
+ * 设置子项点击事件
+ *
+ * @param listener
+ */
+ public void setOnChildClickListener(OnChildClickListener listener) {
+ mOnChildClickListener = listener;
+ }
+
+ public abstract int getGroupCount();
+
+ public abstract int getChildrenCount(int groupPosition);
+
+ public abstract boolean hasHeader(int groupPosition);
+
+ public abstract boolean hasFooter(int groupPosition);
+
+ public abstract int getHeaderLayout(int viewType);
+
+ public abstract int getFooterLayout(int viewType);
+
+ public abstract int getChildLayout(int viewType);
+
+ public abstract void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition);
+
+ public abstract void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition);
+
+ public abstract void onBindChildViewHolder(BaseViewHolder holder,
+ int groupPosition, int childPosition);
+
+ /**
+ * 获取空布局
+ *
+ * @param parent
+ * @return
+ */
+ public View getEmptyView(ViewGroup parent) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.dk_permission_list_group_adapter_default_empty_view, parent, false);
+ return view;
+ }
+
+ class GroupDataObserver extends RecyclerView.AdapterDataObserver {
+
+ @Override
+ public void onChanged() {
+ isDataChanged = true;
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ isDataChanged = true;
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ onItemRangeChanged(positionStart, itemCount);
+ }
+
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ isDataChanged = true;
+ }
+
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ isDataChanged = true;
+ }
+ }
+
+ public interface OnHeaderClickListener {
+ void onHeaderClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition);
+ }
+
+ public interface OnFooterClickListener {
+ void onFooterClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition);
+ }
+
+ public interface OnChildClickListener {
+ void onChildClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
+ int groupPosition, int childPosition);
+ }
+
+ public interface OnHeaderLongClickListener {
+ boolean onHeaderLongClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition);
+ }
+
+ public interface OnFooterLongClickListener {
+ boolean onFooterLongClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition);
+ }
+
+ public interface OnChildLongClickListener {
+ boolean onChildLongClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
+ int groupPosition, int childPosition);
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/MyPermissionInfo.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/MyPermissionInfo.java
new file mode 100644
index 000000000..8c6f777b4
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/MyPermissionInfo.java
@@ -0,0 +1,57 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+public class MyPermissionInfo {
+ private String name;
+ private String permissionGroup;
+ private String description;
+ private String label;
+ private String protectionLevel;
+
+ public MyPermissionInfo(String name, String permissionGroup, String description, String protectionLevel) {
+ this.name = name;
+ this.permissionGroup = permissionGroup;
+ this.description = description;
+ this.protectionLevel = protectionLevel;
+ label="";
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setPermissionGroup(String permissionGroup) {
+ this.permissionGroup = permissionGroup;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setProtectionLevel(String protectionLevel) {
+ this.protectionLevel = protectionLevel;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getPermissionGroup() {
+ return permissionGroup;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getProtectionLevel() {
+ return protectionLevel;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/PermissionListKit.kt b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/PermissionListKit.kt
new file mode 100644
index 000000000..d4c6c534e
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/PermissionListKit.kt
@@ -0,0 +1,32 @@
+package com.didichuxing.doraemonkit.kit.permissionlist
+
+import android.app.Activity
+import android.content.Context
+import com.didichuxing.doraemonkit.R
+import com.didichuxing.doraemonkit.kit.AbstractKit
+import com.didichuxing.doraemonkit.kit.network.ui.NetWorkMonitorFragment
+import com.google.auto.service.AutoService
+
+/**
+ * Created by lmh 2022/6/14
+ */
+@AutoService(AbstractKit::class)
+class PermissionListKit : AbstractKit() {
+ override val name: Int
+ get() = R.string.dk_kit_permission_list
+ override val icon: Int
+ get() = R.mipmap.dk_permission_list
+
+ override fun onClickWithReturn(activity: Activity): Boolean {
+ ExpandableActivity.openActivity(activity)
+ return true
+ }
+
+ override fun onAppInit(context: Context?) {
+ }
+
+ override val isInnerKit: Boolean
+ get() = true
+
+ override fun innerKitId(): String = "dokit_sdk_platform_ck_permission"
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/XMLparser.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/XMLparser.java
new file mode 100644
index 000000000..477ddb9b9
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/XMLparser.java
@@ -0,0 +1,55 @@
+package com.didichuxing.doraemonkit.kit.permissionlist;
+
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+public class XMLparser {
+ private HashMap permissonmap;
+
+ public ArrayList parser(InputStream path){
+ // 1.权限名-对象的映射map
+ permissonmap=new HashMap<>();
+ //2.创建DocumentBuilderFactory对象
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ //3.创建DocumentBuilder对象
+ try {
+ ArrayList myPermissionInfoList =new ArrayList<>();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document d = builder.parse(path);
+ NodeList sList = d.getElementsByTagName("permission");
+ //System.out.println(sList.getLength());
+ for(int i=0;i getMap(){
+ return permissonmap;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ChildEntity.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ChildEntity.java
new file mode 100644
index 000000000..cf7fd900e
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ChildEntity.java
@@ -0,0 +1,22 @@
+package com.didichuxing.doraemonkit.kit.permissionlist.entity;
+import com.didichuxing.doraemonkit.kit.permissionlist.MyPermissionInfo;
+
+/**
+ * 子项数据的实体类
+ */
+public class ChildEntity {
+
+ private MyPermissionInfo child;
+
+ public ChildEntity(MyPermissionInfo child) {
+ this.child = child;
+ }
+
+ public MyPermissionInfo getChild() {
+ return child;
+ }
+
+ public void setChild(MyPermissionInfo child) {
+ this.child = child;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ExpandableGroupEntity.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ExpandableGroupEntity.java
new file mode 100644
index 000000000..401d409f9
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/ExpandableGroupEntity.java
@@ -0,0 +1,54 @@
+package com.didichuxing.doraemonkit.kit.permissionlist.entity;
+
+import java.util.ArrayList;
+
+/**
+ * 可展开收起的组数据的实体类 它比GroupEntity只是多了一个boolean类型的isExpand,用来表示展开和收起的状态。
+ */
+public class ExpandableGroupEntity {
+
+ private String header;
+ private String footer;
+ private ArrayList children;
+ private boolean isExpand;
+
+ public ExpandableGroupEntity(String header, String footer, boolean isExpand,
+ ArrayList children) {
+ this.header = header;
+ this.footer = footer;
+ this.isExpand = isExpand;
+ this.children = children;
+ }
+
+ public String getHeader() {
+ return header;
+ }
+
+ public void setHeader(String header) {
+ this.header = header;
+ }
+
+ public String getFooter() {
+ return footer;
+ }
+
+ public void setFooter(String footer) {
+ this.footer = footer;
+ }
+
+ public boolean isExpand() {
+ return isExpand;
+ }
+
+ public void setExpand(boolean expand) {
+ isExpand = expand;
+ }
+
+ public ArrayList getChildren() {
+ return children;
+ }
+
+ public void setChildren(ArrayList children) {
+ this.children = children;
+ }
+}
diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/GroupEntity.java b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/GroupEntity.java
new file mode 100644
index 000000000..433978a0f
--- /dev/null
+++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/permissionlist/entity/GroupEntity.java
@@ -0,0 +1,43 @@
+package com.didichuxing.doraemonkit.kit.permissionlist.entity;
+
+import java.util.ArrayList;
+
+/**
+ * 组数据的实体类
+ */
+public class GroupEntity {
+
+ private String header;
+ private String footer;
+ private ArrayList children;
+
+ public GroupEntity(String header, String footer, ArrayList children) {
+ this.header = header;
+ this.footer = footer;
+ this.children = children;
+ }
+
+ public String getHeader() {
+ return header;
+ }
+
+ public void setHeader(String header) {
+ this.header = header;
+ }
+
+ public String getFooter() {
+ return footer;
+ }
+
+ public void setFooter(String footer) {
+ this.footer = footer;
+ }
+
+ public ArrayList getChildren() {
+ return children;
+ }
+
+ public void setChildren(ArrayList children) {
+ this.children = children;
+ }
+}
diff --git a/Android/dokit/src/main/res/drawable-v21/holo_gray_dark_ripple_bg.xml b/Android/dokit/src/main/res/drawable-v21/holo_gray_dark_ripple_bg.xml
new file mode 100644
index 000000000..545f5f9f6
--- /dev/null
+++ b/Android/dokit/src/main/res/drawable-v21/holo_gray_dark_ripple_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/Android/dokit/src/main/res/drawable-v21/holo_red_dark_ripple_bg.xml b/Android/dokit/src/main/res/drawable-v21/holo_red_dark_ripple_bg.xml
new file mode 100644
index 000000000..27e4997b7
--- /dev/null
+++ b/Android/dokit/src/main/res/drawable-v21/holo_red_dark_ripple_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/Android/dokit/src/main/res/drawable-v21/white_ripple_bg.xml b/Android/dokit/src/main/res/drawable-v21/white_ripple_bg.xml
new file mode 100644
index 000000000..79ffedc3e
--- /dev/null
+++ b/Android/dokit/src/main/res/drawable-v21/white_ripple_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/Android/dokit/src/main/res/drawable-xhdpi/group_adapter_empty_view_image.png b/Android/dokit/src/main/res/drawable-xhdpi/group_adapter_empty_view_image.png
new file mode 100644
index 000000000..96a0f83ad
Binary files /dev/null and b/Android/dokit/src/main/res/drawable-xhdpi/group_adapter_empty_view_image.png differ
diff --git a/Android/dokit/src/main/res/drawable-xhdpi/icon_right.png b/Android/dokit/src/main/res/drawable-xhdpi/icon_right.png
new file mode 100644
index 000000000..c0a92baec
Binary files /dev/null and b/Android/dokit/src/main/res/drawable-xhdpi/icon_right.png differ
diff --git a/Android/dokit/src/main/res/layout/dk_item_log.xml b/Android/dokit/src/main/res/layout/dk_item_log.xml
index b42b4c447..355b63fab 100644
--- a/Android/dokit/src/main/res/layout/dk_item_log.xml
+++ b/Android/dokit/src/main/res/layout/dk_item_log.xml
@@ -11,13 +11,13 @@
android:id="@+id/pid_text"
android:layout_width="70dp"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:singleLine="true"
- android:textColor="@color/dk_color_FFFFFF"
+ android:layout_alignParentLeft="true"
android:paddingEnd="2dp"
android:paddingRight="2dp"
- android:textSize="12sp"/>
+ android:singleLine="true"
+ android:textColor="@color/dk_color_FFFFFF"
+ android:textSize="12sp" />
+ android:singleLine="true"
+ android:textColor="@color/dk_color_FFFFFF"
+ android:textSize="12sp" />
+ android:singleLine="true"
+ android:textColor="@color/dk_color_000000"
+ android:textSize="12sp" />
+ android:textSize="12sp" />
+ android:singleLine="true"
+ android:textSize="12sp" />
-
\ No newline at end of file
+
diff --git a/Android/dokit/src/main/res/layout/dk_permission_list_activity_group_list.xml b/Android/dokit/src/main/res/layout/dk_permission_list_activity_group_list.xml
new file mode 100644
index 000000000..4df80fc22
--- /dev/null
+++ b/Android/dokit/src/main/res/layout/dk_permission_list_activity_group_list.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/Android/dokit/src/main/res/layout/dk_permission_list_adapter_child.xml b/Android/dokit/src/main/res/layout/dk_permission_list_adapter_child.xml
new file mode 100644
index 000000000..5525f7eee
--- /dev/null
+++ b/Android/dokit/src/main/res/layout/dk_permission_list_adapter_child.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Android/dokit/src/main/res/layout/dk_permission_list_adapter_expandable_header.xml b/Android/dokit/src/main/res/layout/dk_permission_list_adapter_expandable_header.xml
new file mode 100644
index 000000000..faf2bdae2
--- /dev/null
+++ b/Android/dokit/src/main/res/layout/dk_permission_list_adapter_expandable_header.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/Android/dokit/src/main/res/layout/dk_permission_list_group_adapter_default_empty_view.xml b/Android/dokit/src/main/res/layout/dk_permission_list_group_adapter_default_empty_view.xml
new file mode 100644
index 000000000..29d7681ad
--- /dev/null
+++ b/Android/dokit/src/main/res/layout/dk_permission_list_group_adapter_default_empty_view.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/Android/dokit/src/main/res/mipmap-xxhdpi/dk_permission_list.png b/Android/dokit/src/main/res/mipmap-xxhdpi/dk_permission_list.png
new file mode 100644
index 000000000..eab44a8ff
Binary files /dev/null and b/Android/dokit/src/main/res/mipmap-xxhdpi/dk_permission_list.png differ
diff --git a/Android/dokit/src/main/res/values-en-rUS/strings.xml b/Android/dokit/src/main/res/values-en-rUS/strings.xml
index 439b954d6..52da9aa2b 100644
--- a/Android/dokit/src/main/res/values-en-rUS/strings.xml
+++ b/Android/dokit/src/main/res/values-en-rUS/strings.xml
@@ -19,6 +19,7 @@
running service
Language
+ Permission List
Tools
demo
Sandbox
diff --git a/Android/dokit/src/main/res/values-zh-rCN/strings.xml b/Android/dokit/src/main/res/values-zh-rCN/strings.xml
index 18630b27d..20e3a4204 100644
--- a/Android/dokit/src/main/res/values-zh-rCN/strings.xml
+++ b/Android/dokit/src/main/res/values-zh-rCN/strings.xml
@@ -26,6 +26,7 @@
位置模拟
位置微调
位置预设
+ 权限列表
实时导航
取色器
对齐标尺
diff --git a/Android/dokit/src/main/res/values-zh-rTW/strings.xml b/Android/dokit/src/main/res/values-zh-rTW/strings.xml
index 149b9e5ba..4f20b7c52 100644
--- a/Android/dokit/src/main/res/values-zh-rTW/strings.xml
+++ b/Android/dokit/src/main/res/values-zh-rTW/strings.xml
@@ -13,6 +13,7 @@
文件同步助手
Weex
+ 權限列表
App信息
三方库信息
開發者選項
diff --git a/Android/dokit/src/main/res/values/strings.xml b/Android/dokit/src/main/res/values/strings.xml
index 43b6e15de..9301ebd0f 100644
--- a/Android/dokit/src/main/res/values/strings.xml
+++ b/Android/dokit/src/main/res/values/strings.xml
@@ -1,6 +1,6 @@
- DoKit
+ DoKit
业务专区
常用工具
LBS
@@ -26,6 +26,7 @@
位置模拟
位置微调
+ 权限列表
实时导航
取色器
对齐标尺
@@ -405,4 +406,9 @@
DoKit Web
DoKit Studio
+
+
+
+
+
diff --git a/DoraemonKit b/DoraemonKit
new file mode 160000
index 000000000..c1531e7cd
--- /dev/null
+++ b/DoraemonKit
@@ -0,0 +1 @@
+Subproject commit c1531e7cdf41e67317095aa7d5f9d4af4afcc203