Browse Source

首页增加权限申请

zk 1 year ago
parent
commit
28aec0ad16

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -53,6 +53,9 @@
         <activity
             android:name=".module.login.LoginActivity"
             android:screenOrientation="portrait" />
+        <activity
+            android:name=".module.imgrecover.ImageRecoverActivity"
+            android:screenOrientation="portrait" />
 
     </application>
 

+ 20 - 0
app/src/main/java/com/datarecovery/master/dialog/CommonSureDialog.java

@@ -38,11 +38,31 @@ public class CommonSureDialog extends BaseDialog<DialogCommonSureBinding> {
         return this;
     }
 
+    public CommonSureDialog setTitleGravity(int gravity) {
+        binding.tvDialogTitle.setGravity(gravity);
+        return this;
+    }
+
     public CommonSureDialog setDialogContent(@StringRes int content) {
         binding.tvContent.setText(content);
         return this;
     }
 
+    public CommonSureDialog setContentGravity(int gravity) {
+        binding.tvContent.setGravity(gravity);
+        return this;
+    }
+
+    public CommonSureDialog setSureText(@StringRes int sureText) {
+        binding.tvSure.setText(sureText);
+        return this;
+    }
+
+    public CommonSureDialog setCancelText(@StringRes int cancelText) {
+        binding.tvCancel.setText(cancelText);
+        return this;
+    }
+
     public interface OnDialogClickListener {
         void onClickSure();
     }

+ 44 - 0
app/src/main/java/com/datarecovery/master/module/homepage/HomePageFragment.java

@@ -1,13 +1,18 @@
 package com.datarecovery.master.module.homepage;
 
 import android.os.Bundle;
+import android.view.Gravity;
 import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.atmob.app.lib.base.BaseFragment;
+import com.datarecovery.master.R;
 import com.datarecovery.master.databinding.FragmentHomePageBinding;
+import com.datarecovery.master.dialog.CommonSureDialog;
+import com.datarecovery.master.utils.PermissionUtil;
+import com.datarecovery.master.utils.xfile.XFilePermission;
 import com.datarecovery.master.widget.InformationSwitchBanner;
 import com.gyf.immersionbar.ImmersionBar;
 
@@ -22,6 +27,9 @@ public class HomePageFragment extends BaseFragment<FragmentHomePageBinding> {
 
     private OtherFunctionAdapter otherFunctionAdapter;
 
+    private CommonSureDialog requestManageDialog;
+    private CommonSureDialog requestAndroidDataDialog;
+
     @Override
     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
@@ -30,9 +38,45 @@ public class HomePageFragment extends BaseFragment<FragmentHomePageBinding> {
     }
 
     private void initObserver() {
+        homePageViewModel.getRequestManagePermission().observe(getViewLifecycleOwner(), o -> showManageDialog());
+        homePageViewModel.getRequestAndroidDataPermission().observe(getViewLifecycleOwner(), o -> showAndroidDataDialog());
+    }
 
+    private void showManageDialog() {
+        if (requestManageDialog == null) {
+            requestManageDialog = new CommonSureDialog(requireContext());
+            requestManageDialog.setDialogTitle(R.string.request_manage_permission_title)
+                    .setDialogContent(R.string.request_manage_permission_content)
+                    .setTitleGravity(Gravity.START)
+                    .setContentGravity(Gravity.START)
+                    .setSureText(R.string.teaching_limit)
+                    .setOnDialogClickListener(this::requestManageFilePermission);
+        }
+        requestManageDialog.show();
     }
 
+    private void showAndroidDataDialog() {
+        if (requestAndroidDataDialog == null) {
+            requestAndroidDataDialog = new CommonSureDialog(requireContext());
+            requestAndroidDataDialog.setDialogTitle(R.string.request_android_data_permission_title)
+                    .setDialogContent(R.string.request_android_data_permission_content)
+                    .setCancelText(R.string.wait_moment)
+                    .setSureText(R.string.teaching_limit)
+                    .setOnDialogClickListener(this::requestAndroidDataPermission);
+
+        }
+        requestAndroidDataDialog.show();
+    }
+
+    private void requestAndroidDataPermission() {
+        XFilePermission.requestAndroidDataPermission(getActivity(), null);
+    }
+
+    private void requestManageFilePermission() {
+        PermissionUtil.requestWriteStoragePermission(getActivity(), null);
+    }
+
+
     private void initView() {
         initTextViewBanner();
         initHotFunction();

+ 84 - 0
app/src/main/java/com/datarecovery/master/module/homepage/HomePageViewModel.java

@@ -1,17 +1,34 @@
 package com.datarecovery.master.module.homepage;
 
 import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.app.lib.livedata.SingleLiveEvent;
+import com.atmob.common.runtime.ActivityUtil;
+import com.atmob.common.runtime.ContextUtil;
 import com.datarecovery.master.R;
+import com.datarecovery.master.data.repositories.AccountRepository;
+import com.datarecovery.master.module.imgrecover.ImageRecoverActivity;
+import com.datarecovery.master.utils.PermissionUtil;
+import com.datarecovery.master.utils.xfile.XFilePermission;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.inject.Inject;
 
+import atmob.reactivex.rxjava3.annotations.NonNull;
+import atmob.reactivex.rxjava3.core.Single;
+import atmob.reactivex.rxjava3.core.SingleEmitter;
+import atmob.reactivex.rxjava3.core.SingleObserver;
+import atmob.reactivex.rxjava3.core.SingleOnSubscribe;
+import atmob.reactivex.rxjava3.disposables.Disposable;
+import atmob.rxjava.utils.RxJavaUtil;
 import dagger.hilt.android.lifecycle.HiltViewModel;
 
+import android.os.Build;
 import android.util.Pair;
 
+import androidx.lifecycle.LiveData;
+
 
 @HiltViewModel
 public class HomePageViewModel extends BaseViewModel {
@@ -20,6 +37,9 @@ public class HomePageViewModel extends BaseViewModel {
     private final List<Pair<CharSequence, CharSequence>> informationList = new ArrayList<>();
     private final List<FunctionBean> functionList = new ArrayList<>();
 
+    private final SingleLiveEvent<?> requestManagePermission = new SingleLiveEvent<>();
+    private final SingleLiveEvent<?> requestAndroidDataPermission = new SingleLiveEvent<>();
+
 
     @Inject
     public HomePageViewModel() {
@@ -48,6 +68,13 @@ public class HomePageViewModel extends BaseViewModel {
         functionList.add(new FunctionBean(FunctionBean.IMG_CLEARING, R.string.home_page_img_clearing, R.drawable.icon_home_page_img_clearing));
     }
 
+    public LiveData<?> getRequestManagePermission() {
+        return requestManagePermission;
+    }
+
+    public LiveData<?> getRequestAndroidDataPermission() {
+        return requestAndroidDataPermission;
+    }
 
     public void onWxMessageRecoveryClick() {
 
@@ -58,7 +85,64 @@ public class HomePageViewModel extends BaseViewModel {
     }
 
     public void onImgRecoveryClick() {
+        isCheckPermission(() -> ImageRecoverActivity.start(ActivityUtil.getTopActivity()));
+    }
 
+    /**
+     * 判断是否有所需的存储权限
+     *
+     * @param stepCallback 有权限的回调
+     */
+    public void isCheckPermission(NextStepCallback stepCallback) {
+        Single.just(Build.VERSION.SDK_INT).map(sdkInt -> {
+                    //判断是否有所有文件权限
+                    boolean result = PermissionUtil.hasFilePermission();
+                    if (!result) {
+                        throw new RequestManageExternalException();
+                    }
+                    return sdkInt;
+                }).map(sdkInt -> {
+                    if (sdkInt >= Build.VERSION_CODES.TIRAMISU) {
+                        return true;
+                    }
+                    boolean dataFolder = XFilePermission.hasAndroidDataPermission(ContextUtil.getContext());
+                    if (!dataFolder) {
+                        throw new RequestDataFolderException();
+                    }
+                    return true;
+                })
+                .compose(RxJavaUtil.SingleSchedule.io2Main())
+                .subscribe(new SingleObserver<Boolean>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull Boolean aBoolean) {
+                        if (stepCallback != null) stepCallback.onNextStep();
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        if (e instanceof RequestManageExternalException) {
+                            requestManagePermission.call();
+                        } else if (e instanceof RequestDataFolderException) {
+                            requestAndroidDataPermission.call();
+                        }
+                    }
+                });
     }
 
+    public interface NextStepCallback {
+        void onNextStep();
+    }
+
+    public static class RequestManageExternalException extends Exception {
+    }
+
+    public static class RequestDataFolderException extends Exception {
+    }
+
+
 }

+ 64 - 0
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageRecoverActivity.java

@@ -0,0 +1,64 @@
+package com.datarecovery.master.module.imgrecover;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.datarecovery.master.databinding.ActivityImageRecoverBinding;
+import com.gyf.immersionbar.ImmersionBar;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+
+@AndroidEntryPoint
+public class ImageRecoverActivity extends BaseActivity<ActivityImageRecoverBinding> {
+
+
+    ImageRecoverViewModel imageRecoverViewModel;
+
+
+    public static void start(Context context) {
+        Intent intent = new Intent(context, ImageRecoverActivity.class);
+        if (!(context instanceof Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        initView();
+        initObserver();
+    }
+
+    private void initView() {
+        addTopStatusBarHeight(binding.toolBar);
+    }
+
+    private void initObserver() {
+        imageRecoverViewModel.getFinishEvent().observe(this, o -> finish());
+    }
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        immersionBar.statusBarDarkFont(true);
+    }
+
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+
+    @Override
+    protected void initViewModel() {
+        super.initViewModel();
+        imageRecoverViewModel = getViewModelProvider().get(ImageRecoverViewModel.class);
+        binding.setImageRecoverViewModel(imageRecoverViewModel);
+    }
+}

+ 44 - 0
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageRecoverAdapter.java

@@ -0,0 +1,44 @@
+package com.datarecovery.master.module.imgrecover;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.datarecovery.master.databinding.ItemDataImgBinding;
+
+public class ImageRecoverAdapter extends RecyclerView.Adapter<ImageRecoverAdapter.ViewHolder> {
+
+
+    public ImageRecoverAdapter() {
+    }
+
+    @NonNull
+    @Override
+    public ImageRecoverAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        return null;
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull ImageRecoverAdapter.ViewHolder holder, int position) {
+
+    }
+
+    @Override
+    public int getItemCount() {
+        return 0;
+    }
+
+    public class ViewHolder extends RecyclerView.ViewHolder {
+
+        private ItemDataImgBinding binding;
+
+        public ViewHolder(@NonNull ItemDataImgBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+        }
+
+
+    }
+}

+ 45 - 0
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageRecoverViewModel.java

@@ -0,0 +1,45 @@
+package com.datarecovery.master.module.imgrecover;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.app.lib.livedata.SingleLiveEvent;
+import com.atmob.common.runtime.ContextUtil;
+import com.datarecovery.master.R;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.lifecycle.HiltViewModel;
+
+
+@HiltViewModel
+public class ImageRecoverViewModel extends BaseViewModel {
+
+
+    private final SingleLiveEvent<?> finishEvent = new SingleLiveEvent<>();
+    private final MutableLiveData<String> barTitle = new MutableLiveData<>();
+    private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>();
+
+
+    @Inject
+    public ImageRecoverViewModel() {
+        barTitle.setValue(ContextUtil.getContext().getString(R.string.iamge_recover_all));
+    }
+
+    public LiveData<?> getFinishEvent() {
+        return finishEvent;
+    }
+
+    public LiveData<Boolean> getCheckAll() {
+        return checkAll;
+    }
+
+    public LiveData<String> getBarTitle() {
+        return barTitle;
+    }
+
+    public void onCheckAllClick(boolean isCheck) {
+        checkAll.setValue(!isCheck);
+    }
+}

+ 77 - 0
app/src/main/java/com/datarecovery/master/utils/PermissionUtil.java

@@ -0,0 +1,77 @@
+package com.datarecovery.master.utils;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.Settings;
+
+import androidx.activity.ComponentActivity;
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.core.content.ContextCompat;
+
+import com.atmob.common.runtime.ContextUtil;
+
+public class PermissionUtil {
+
+
+    public static boolean hasFilePermission() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            return Environment.isExternalStorageManager();
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return PermissionUtil.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+        } else {
+            return true;
+        }
+    }
+
+    public static boolean hasPermission(String... permissions) {
+        if (permissions == null) {
+            return true;
+        }
+        Context context = ContextUtil.getContext();
+        for (String permission : permissions) {
+            boolean hasPermission = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
+            if (!hasPermission) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void requestWriteStoragePermission(ComponentActivity activity, PermissionCallback callback) {
+        if (activity == null) {
+            throw new RuntimeException("activity is null");
+        }
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+            new ActivityForResultUtil<String, Boolean>().startActivityForResult(activity, new ActivityResultContracts.RequestPermission(), Manifest.permission.WRITE_EXTERNAL_STORAGE, result -> {
+                if (result) {
+                    if (callback != null) callback.onPermissionGranted();
+                } else {
+                    if (callback != null) callback.onPermissionDenied();
+                }
+            });
+        } else {
+            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
+            intent.setData(Uri.parse("package:" + activity.getPackageName()));
+            new ActivityForResultUtil<Intent, ActivityResult>().startActivityForResult(activity, new ActivityResultContracts.StartActivityForResult(), intent, result -> {
+                if (Environment.isExternalStorageManager()) {
+                    if (callback != null) callback.onPermissionGranted();
+                } else {
+                    if (callback != null) callback.onPermissionDenied();
+                }
+            });
+        }
+    }
+
+    public interface PermissionCallback {
+        void onPermissionGranted();
+
+        void onPermissionDenied();
+    }
+
+}

+ 50 - 4
app/src/main/java/com/datarecovery/master/utils/xfile/XFilePermission.java

@@ -10,11 +10,23 @@ import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Environment;
 import android.os.storage.StorageVolume;
 import android.provider.DocumentsContract;
 
+import androidx.activity.ComponentActivity;
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+import com.datarecovery.master.utils.ActivityForResultUtil;
+import com.datarecovery.master.utils.BoxingUtil;
+import com.datarecovery.master.utils.PermissionUtil;
+
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 这个权限申请写的不好,看怎么根据业务需求优化
@@ -32,7 +44,7 @@ public class XFilePermission {
     public static boolean hasAndroidDataPermission(Context context) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
             for (String permission : EXTERNAL_STORAGE_PERMISSIONS_BELOW_Q) {
-                if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+                if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                     return false;
                 }
             }
@@ -76,9 +88,26 @@ public class XFilePermission {
         return false;
     }
 
-    public static void requestAndroidDataPermission(Activity activity) {
+    public static void requestAndroidDataPermission(ComponentActivity activity, PermissionCallback callback) {
+        if (activity == null) {
+            throw new RuntimeException("activity is null");
+        }
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-            activity.requestPermissions(EXTERNAL_STORAGE_PERMISSIONS_BELOW_Q, REQUEST_CODE_EXTERNAL_STORAGE_PERMISSIONS_BELOW_Q);
+            new ActivityForResultUtil<String[], Map<String, Boolean>>().startActivityForResult(activity, new ActivityResultContracts.RequestMultiplePermissions(), EXTERNAL_STORAGE_PERMISSIONS_BELOW_Q, result -> {
+                boolean permission = false;
+                for (Map.Entry<String, Boolean> entry : result.entrySet()) {
+                    Boolean value = entry.getValue();
+                    if (BoxingUtil.boxing(value)) {
+                        permission = true;
+                        break;
+                    }
+                }
+                if (permission) {
+                    if (callback != null) callback.onPermissionGranted();
+                } else {
+                    if (callback != null) callback.onPermissionDenied();
+                }
+            });
         } else {
             Intent grantIntentSDMOg = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
             grantIntentSDMOg.putExtra("android.content.extra.SHOW_ADVANCED", true);
@@ -88,7 +117,17 @@ public class XFilePermission {
                 XSAFFile xFile = new XSAFFile(activity, treeUri, Arrays.asList("Android", "data"));
                 if (!hasPermission(activity, xFile)) {
                     grantIntentSDMOg.putExtra(DocumentsContract.EXTRA_INITIAL_URI, xFile.getDocumentUri());
-                    activity.startActivityForResult(grantIntentSDMOg, REQUEST_CODE_SAF_PERMISSIONS);
+                    new ActivityForResultUtil<Intent, ActivityResult>().startActivityForResult(activity, new ActivityResultContracts.StartActivityForResult(), grantIntentSDMOg, result -> {
+                        Intent data = result.getData();
+                        Uri uri = null;
+                        if (result.getResultCode() == Activity.RESULT_OK && data != null && (uri = data.getData()) != null) {
+                            activity.getContentResolver().takePersistableUriPermission(uri,
+                                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                            if (callback != null) callback.onPermissionGranted();
+                        } else {
+                            if (callback != null) callback.onPermissionDenied();
+                        }
+                    });
                 }
             }
         }
@@ -121,4 +160,11 @@ public class XFilePermission {
         }
         return false;
     }
+
+
+    public interface PermissionCallback {
+        void onPermissionGranted();
+
+        void onPermissionDenied();
+    }
 }

BIN
app/src/main/res/drawable-xxhdpi/icon_image_recover_checked.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_image_recover_uncheck.webp


+ 58 - 0
app/src/main/res/layout/activity_image_recover.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="imageRecoverViewModel"
+            type="com.datarecovery.master.module.imgrecover.ImageRecoverViewModel" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <Toolbar
+            android:id="@+id/tool_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:navigationIcon="@drawable/icon_back"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <TextView
+                style="@style/Tool_Bar_Title_Txt"
+                android:text="@{imageRecoverViewModel.barTitle}"
+                tools:text="全部图片" />
+
+
+            <ImageView
+                imageDraw="@{imageRecoverViewModel.checkAll ? @drawable/icon_image_recover_checked : @drawable/icon_image_recover_uncheck}"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="right"
+                android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
+                android:onClick="@{()->imageRecoverViewModel.onCheckAllClick(imageRecoverViewModel.checkAll)}"
+                tools:src="@drawable/icon_image_recover_uncheck" />
+        </Toolbar>
+
+        <TableLayout
+            android:id="@+id/tab_layout"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:40"
+            app:layout_constraintTop_toBottomOf="@+id/tool_bar" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/ry_image_recover"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tab_layout"
+            tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+            tools:spanCount="3" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 5 - 3
app/src/main/res/layout/dialog_common_sure.xml

@@ -40,13 +40,15 @@
 
         <TextView
             android:id="@+id/tv_dialog_title"
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:textColor="@color/common_txt_color"
             android:textSize="15sp"
             android:textStyle="bold"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintWidth_percent="0.6444444444444444"
+            android:gravity="center"
+            app:layout_constraintEnd_toEndOf="@+id/v_bg"
+            app:layout_constraintStart_toStartOf="@+id/v_bg"
             app:layout_constraintTop_toBottomOf="@+id/space1"
             tools:text="@string/dialog_kind_tips" />
 

+ 22 - 0
app/src/main/res/layout/item_data_img.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <data>
+
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            tools:src="@color/colorPrimary"
+            app:layout_constraintTop_toTopOf="parent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="1:1" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 7 - 0
app/src/main/res/values/strings.xml

@@ -74,4 +74,11 @@
     <string name="login_verification_code_request_failed_toast">验证码发送失败,请重试</string>
     <string name="login_agree_user_terms_text">《隐私权政策》</string>
     <string name="login_agree_privacy_policy_text">《服务条款》</string>
+    <string name="iamge_recover_all">全部图片</string>
+    <string name="request_manage_permission_title">需要授权以下权限才能正常使用文件管理权限:</string>
+    <string name="request_manage_permission_content">1. 用于读取您手机上的图片或文件进行展示,以方便您查找数据或照片处理;\n2.用于缓存、保存或导出图片或文件。</string>
+    <string name="request_android_data_permission_title">申请授权访问权限</string>
+    <string name="request_android_data_permission_content">为了保证扫描效果,需要您授权文件目录的访问权限,否则会影响扫描结果。授权页面无需多余操作,您只需点击【使用此文件夹】即可。</string>
+    <string name="teaching_limit">授权权限</string>
+    <string name="wait_moment">等会在说</string>
 </resources>