隐私协议&授权访问的实现

交互逻辑

用户首次下载打开apk,先弹出用户隐私协议的确认框,如果不同意则进入再次确认的弹窗,如果仍旧不同意则直接退出应用;
从再次确认的弹窗点去同意,又再次回到用户隐私协议的确认框;
如果用户同意隐私协议,则弹出开启权限的弹窗,选择是否开启权限;
进入用户登录界面,在此用户可以查看详细的隐私协议,并提示用户如果登录注册,则表示同意隐私协议的内容。

隐私协议的实现

隐私协议主要分为隐私协议确认弹窗、再次确认弹窗、使用协议&隐私政策弹窗、使用协议弹窗、隐私政策弹窗界面实现,以及业务交互逻辑。

初始化隐私协议

apk第一次运行/apk下载更新后,在MainActivity中弹出隐私政策确认界面,示例代码如下:

public class MainActivity extends BaseActivity {

    private LicenseConfigUtil licenseUtil;
    private PrivacyDialog privacyDialog;
    private boolean isFirstEnterApp;
    private boolean isHaveUpdate;
    private String IS_FIRST_ENTER_APP = "is_first_enter_app";
    private String IS_HAVE_UPDATE = "is_have_update";
    private String TAG = MainActivity.class.getSimpleName();

    @Override
    protected int getLayout() {
        return R.layout.activity_main;
    }

    @Override
    protected void initEvent() {
        ...
        // 授权访问的工具类
        licenseUtil = LicenseConfigUtil.getInstance(MainActivity.this);
        checkPrivacyAndPermission();

    }

    private void checkPrivacyAndPermission() {
        isFirstEnterApp = SPUtils.getInstance().getBoolean(IS_FIRST_ENTER_APP, true);
        isHaveUpdate = SPUtils.getInstance().getBoolean(IS_HAVE_UPDATE, false);
        if (isFirstEnterApp || isHaveUpdate) {
            privacyDialog = new PrivacyDialog(this, licenseUtil);
            privacyDialog.initDialog(this);
        } else if (!isFirstEnterApp) {
            licenseUtil.checkPermission();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("MainActivity", " -=-=- onResume: isToSetting:" + ConfirmAuthorityDialog.isToSetting);
        if (ConfirmAuthorityDialog.isToSetting) {
            new Thread(() -> {
                try {
                    Log.d("MainActivity", " -=-=- onResume: sleep 1 :");
                    Thread.sleep(100);
                    Log.d("MainActivity", " -=-=- onResume: sleep 2 :");
                    licenseUtil.openWIFI();
                    ConfirmAuthorityDialog.isToSetting = false;
                } catch (Exception e) {
                    Log.e("MainActivity", " -=-=- onResume: sleep error", e);
                }
            }).start();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放弹窗资源,防止内存泄漏
        if (privacyDialog != null) {
            privacyDialog.cancel();
            privacyDialog = null;
        }
    }

在登录界面,添加隐私政策的链接可以跳转至隐私政策&用户协议界面、隐私政策界面、用户协议界面,表示“用户如果登录使用就代表同意隐私政策”,示例代码如下:

public class LoginFragment extends BaseFragment {

    ...
    @BindView(R.id.tv_user_agreement_and_privacy_policy)
    TextView tvUserAgreementAndPrivacyPolicy;

	@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ((MainActivity) getActivity()).setKeyDownCallBack(null);

        String userName = SPUtils.getInstance().getString(SpConfig.UserName);
        String password = SPUtils.getInstance().getString(SpConfig.Password);

        etUserName.setText(userName);
        etPassword.setText(password);

        tvUserAgreementAndPrivacyPolicy.setOnClickListener(v -> {
            new UserAgreementAndPrivacyPolicyDialog(getContext(), LicenseConfigUtil.getInstance(getActivity()));
        });

        btnLogin.setOnClickListener(v -> {
            DialogLoading.showDialog(getContext());
            login(); /** 跳过授权码查询 */
        });
        ...

    }

隐私协议确认弹窗

隐私协议确认弹窗用多个textView拼接的话,会比较繁琐。这里用到了android自带的方法SpannableStringBuilder 来实现业务需求。

以下是确认隐私弹窗界面的逻辑代码:

public class PrivacyDialog extends BaseDialog implements View.OnClickListener {

    @BindView(R.id.btn_exit)
    TextView tvBtnExit;
    @BindView(R.id.btn_agree)
    TextView tvBtnAgree;
    @BindView(R.id.privacy_tips)
    TextView tvPrivacyTips;

    private Context context;
    private String IS_FIRST_ENTER_APP = "is_first_enter_app";
    private String IS_FROM_PRIVACY_DIALOG = "is_from_privacy_dialog";
    private String TAG = PrivacyDialog.class.getSimpleName();
    private LicenseConfigUtil licenseUtil;
    private Activity a;

    public PrivacyDialog(Context context, LicenseConfigUtil licenseUtil, Activity a) {
        super(context, R.style.PrivacyDialogTheme);
        this.context = context;
        this.licenseUtil = licenseUtil;
        this.a = a;
        bindView();
    }

    @Override
    protected int setContentView() {
        return R.layout.dialog_privacy;
    }

    @Override
    protected void bindView() {
        super.bindView();
    }

    public void initDialog(Context context) {
        initSpan(context);

		// 在用户点击返回键 or 触碰到弹窗之外时不会意外退出
        setCancelable(false);
        setCanceledOnTouchOutside(false);

		// 设置弹窗占据屏幕的比例大小
        Window window = getWindow();
        window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        Display display = window.getWindowManager().getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (display.getHeight() * 0.5);
        window.setAttributes(params);

        tvBtnAgree.setOnClickListener(this);
        tvBtnExit.setOnClickListener(this);
        show();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_agree) {
            dismiss();
			// 权限检查
            licenseUtil.checkPermission();
            // 控制隐私协议的确认弹窗只在用户第一次打开时弹出
            SPUtils.getInstance().put(IS_FIRST_ENTER_APP, false);
        }
        if (v.getId() == R.id.btn_exit) {
            exitDialog();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            exitDialog();
        }
        return super.onKeyDown(keyCode, event);
    }

    private void exitDialog(){
        dismiss();
        SPUtils.getInstance().put(IS_FIRST_ENTER_APP, true);
        new ConfirmPrivacyDialog(context, licenseUtil, a);
    }

    private void initSpan(Context context){
        String privacyTipsStr = context.getResources().getString(R.string.privacyTips);
        String userItemStr = context.getResources().getString(R.string.userAgreementBar);
        String privacyPolicyStr = context.getResources().getString(R.string.privacyPolicyBar);
        int userItemIndex = privacyTipsStr.indexOf(userItemStr);
        int privacyPolicyIndex = privacyTipsStr.indexOf(privacyPolicyStr);

        SpannableString privacyTipsSpannableStr = new SpannableString(privacyTipsStr);
        // 设置特定字段的颜色
        ForegroundColorSpan userItemColor = new ForegroundColorSpan(context.getResources().getColor(R.color.c_03bcff));
        privacyTipsSpannableStr.setSpan(userItemColor, userItemIndex,
                userItemIndex + userItemStr.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        ForegroundColorSpan privacyPolicyColor = new ForegroundColorSpan(context.getResources().getColor(R.color.c_03bcff));
        privacyTipsSpannableStr.setSpan(privacyPolicyColor, privacyPolicyIndex,
                privacyPolicyIndex + privacyPolicyStr.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);

		// 为特定字段注册点击事件
        ClickableSpan userItemClick = new ClickableSpan() {
            @Override
            public void onClick(@NonNull View widget) {
                dismiss();
                SPUtils.getInstance().put(IS_FROM_PRIVACY_DIALOG, true);
                new UserAgreementDialog(context, licenseUtil, a);
            }

            @Override
            public void updateDrawState(@NonNull TextPaint ds) {
                ds.setUnderlineText(false);
            }
        };
        privacyTipsSpannableStr.setSpan(userItemClick, userItemIndex, userItemIndex + userItemStr.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);

        ClickableSpan privacyPolicyClick = new ClickableSpan() {
            @Override
            public void onClick(@NonNull View widget) {
                dismiss();
                SPUtils.getInstance().put(IS_FROM_PRIVACY_DIALOG, true);
                new PrivacyPolicyDialog(context, licenseUtil, a);
            }

            @Override
            public void updateDrawState(@NonNull TextPaint ds) {
                ds.setUnderlineText(false);
            }
        };
        privacyTipsSpannableStr.setSpan(privacyPolicyClick, privacyPolicyIndex, privacyPolicyIndex + privacyPolicyStr.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
		
		// 设置点击后的颜色为透明,否则会一直出现高亮
        tvPrivacyTips.setHighlightColor(Color.TRANSPARENT);
        // 开始响应点击事件
        tvPrivacyTips.setMovementMethod(LinkMovementMethod.getInstance());
        tvPrivacyTips.setText(privacyTipsSpannableStr);
    }
}

以下是隐私政策确认界面的布局代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_config_item_style">

    <TextView
        android:id="@+id/privacy_note"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/dp_20"
        android:text="@string/privacyTipsTitle"
        android:textColor="@color/c_ffffff"
        android:textSize="@dimen/dp_18"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <TextView
        android:id="@+id/privacy_tips"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/dp_20"
        android:text="@string/privacyTips"
        android:textColor="@color/c_ffffff"
        android:textSize="@dimen/dp_18"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/privacy_note" />

    <LinearLayout
        android:id="@+id/layout_to_do"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:orientation="horizontal"
        android:layout_marginHorizontal="@dimen/dp_15"
        android:layout_marginTop="@dimen/dp_25"
        android:background="@drawable/new_broad_send_btn_bg_style"
        app:layout_constraintTop_toBottomOf="@id/privacy_tips">

        <TextView
            android:id="@+id/btn_exit"
            android:layout_width="@dimen/dp_0"
            android:layout_height="@dimen/dp_32"
            android:layout_marginTop="@dimen/dp_8"
            android:layout_weight="1"
            android:minWidth="@dimen/dp_0"
            android:minHeight="@dimen/dp_0"
            android:gravity="center_horizontal"
            android:text="@string/privacyExit"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />

        <View
            android:layout_width="@dimen/dp_0.25"
            android:layout_height="@dimen/dp_15"
            android:layout_gravity="center_vertical"
            android:background="@color/c_eeeeee" />

        <TextView
            android:id="@+id/btn_agree"
            android:layout_width="@dimen/dp_0"
            android:layout_height="@dimen/dp_32"
            android:layout_marginTop="@dimen/dp_8"
            android:layout_weight="1"
            android:minWidth="@dimen/dp_0"
            android:minHeight="@dimen/dp_0"
            android:gravity="center_horizontal"
            android:text="@string/privacyAgree"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />

    </LinearLayout>

    <View
        android:layout_width="@dimen/dp_0.25"
        android:layout_height="@dimen/dp_20"
        android:layout_gravity="center_horizontal"
        app:layout_constraintTop_toBottomOf="@id/layout_to_do"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

以下是隐私政策界面统一定制的样式

<style name="PrivacyDialogTheme" parent="@android:style/Theme.Dialog">
        <!--Dialog的windowFrame框为无-->
        <item name="android:windowFrame">@null</item>
        <!--是否浮现在activity之上-->
        <item name="android:windowIsFloating">true</item>
        <!--是否半透明-->
        <item name="android:windowIsTranslucent">true</item>
        <!--是否显示title-->
        <item name="android:windowNoTitle">false</item>
        <!--设置dialog的背景,(#00000000)-->
        <item name="android:background">@android:color/transparent</item>
        <!--显示区域背景是否透明,(#00000000)-->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!--就是用来控制灰度的值,当为1时,界面除了我们的dialog内容是高亮显示的,dialog以外的区域是黑色的,完全看不到其他内容,系统的默认值是0.5-->
        <item name="android:backgroundDimAmount">0.5</item>
        <!--显示区域以外是否使用黑色半透明背景-->
        <item name="android:backgroundDimEnabled">true</item>
    </style>

以下是BaseDialog的示例代码

public abstract class BaseDialog extends Dialog {

    protected Context context;
    protected Unbinder unbinder;
    protected View view;

    public BaseDialog(@NonNull Context context) {
        super(context);
        this.context = context;
    }

    public BaseDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        this.context = context;
        bindView();
    }

    protected void bindView() {
        view = LayoutInflater.from(context).inflate(setContentView(), null);
        setContentView(view);
        unbinder = ButterKnife.bind(this, view);
    }

    protected abstract int setContentView();

    public void cancelOn() {
        unbinder.unbind();
        cancel();
    }

    protected void showToast(String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }
    protected void showToastLong(String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
    }
    protected void showToast(String msg,int length) {
        Toast.makeText(context, msg,length).show();
    }

    protected int getColor(int colorId){
        return context.getResources().getColor(colorId);
    }

}
## 在启始Activity初始化隐私协议弹窗

```java
public class MainActivity extends BaseActivity {

    @Override
    protected void initEvent() {
        APIManager.getInstance().init();
        ProjectApplication.activity = this;
        SPUtils.getInstance().remove(BroadFiltrationEntity.SPKey);
        licenseUtil = LicenseConfigUtil.getInstance(MainActivity.this);
        checkPrivacyAndPermission();

    }

    private void checkPrivacyAndPermission() {
        isFirstEnterApp = SPUtils.getInstance().getBoolean(IS_FIRST_ENTER_APP, true);
        isHaveUpdate = SPUtils.getInstance().getBoolean(IS_HAVE_UPDATE, false);
        if (isFirstEnterApp || isHaveUpdate) {
            privacyDialog = new PrivacyDialog(this, licenseUtil,this);
            privacyDialog.initDialog(this);
        } else if (!isFirstEnterApp) {
            licenseUtil.checkPermission();
        }
    }

@Override
    protected void onDestroy() {
        super.onDestroy();
        // 防止privacyDialog造成内存泄漏
        if (privacyDialog != null) {
            privacyDialog.cancel();
            privacyDialog = null;
        }
    }

再次确认弹窗

以下是再次确认是否同意隐私协议的弹窗界面逻辑代码

public class ConfirmPrivacyDialog extends BaseDialog implements View.OnClickListener {

    @BindView(R.id.btn_exit)
    TextView tvBtnExit;
    @BindView(R.id.btn_agree)
    TextView tvBtnAgree;

    private Context context;
    private LicenseConfigUtil licenseUtil;
    @Override
    protected int setContentView() {
        return R.layout.dialog_confirm_privacy;
    }

    public ConfirmPrivacyDialog(Context context, LicenseConfigUtil licenseUtil) {
        super(context, R.style.PrivacyDialogTheme);
        bindView();
        this.context = context;
        this.licenseUtil = licenseUtil;
    }

    @Override
    protected void bindView() {
        super.bindView();
        initDialog();
    }

    private void initDialog() {
        Window window = getWindow();
        setCancelable(false);
        setCanceledOnTouchOutside(false);
        window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        window.setGravity(Gravity.CENTER);

        Display display = window.getWindowManager().getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (display.getWidth() * 0.9);
        window.setAttributes(params);

        tvBtnAgree.setOnClickListener(this);
        tvBtnExit.setOnClickListener(this);
        show();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_agree) {
            dismiss();
            PrivacyDialog privacyDialog = new PrivacyDialog(context, licenseUtil);
            privacyDialog.initDialog(context);
        }
        if (v.getId() == R.id.btn_exit) {
            dismiss();
            System.exit(0);
        }
    }

}

以下是再次确认是否同意隐私协议的弹窗界面布局代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_config_item_style">

    <TextView
        android:id="@+id/confirm_privacy_tips"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="@dimen/dp_20"
        android:layout_marginTop="@dimen/dp_70"
        android:text="@string/confirmPrivacy"
        android:textColor="@color/c_ffffff"
        android:textSize="@dimen/dp_18"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/layout_to_do"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:orientation="horizontal"
        android:layout_marginHorizontal="@dimen/dp_15"
        android:layout_marginTop="@dimen/dp_60"
        android:background="@drawable/new_broad_send_btn_bg_style"
        app:layout_constraintTop_toBottomOf="@id/confirm_privacy_tips">

        <TextView
            android:id="@+id/btn_exit"
            android:layout_width="@dimen/dp_0"
            android:layout_height="@dimen/dp_32"
            android:layout_marginTop="@dimen/dp_8"
            android:layout_weight="1"
            android:minWidth="@dimen/dp_0"
            android:minHeight="@dimen/dp_0"
            android:gravity="center_horizontal"
            android:text="@string/noUse"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />

        <View
            android:layout_width="@dimen/dp_0.25"
            android:layout_height="@dimen/dp_15"
            android:layout_gravity="center_vertical"
            android:background="@color/c_eeeeee" />

        <TextView
            android:id="@+id/btn_agree"
            android:layout_width="@dimen/dp_0"
            android:layout_height="@dimen/dp_32"
            android:layout_marginTop="@dimen/dp_8"
            android:layout_weight="1"
            android:minWidth="@dimen/dp_0"
            android:minHeight="@dimen/dp_0"
            android:gravity="center_horizontal"
            android:text="@string/agreePrivacy"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />

    </LinearLayout>

    <View
        android:id="@+id/line"
        android:layout_width="@dimen/dp_0.25"
        android:layout_height="@dimen/dp_20"
        app:layout_constraintTop_toBottomOf="@id/layout_to_do"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

隐私政策&用户协议界面

示例逻辑代码如下:

public class UserAgreementAndPrivacyPolicyDialog extends BaseDialog implements View.OnClickListener {

    @BindView(R.id.user_agreement_and_privacy_policy_exit)
    ImageView ivUserAgreementAndPrivacyPolicyExit;

    @BindView(R.id.user_agreement_bar)
    TextView tvUserAgreementBar;

    @BindView(R.id.privacy_policy_bar)
    TextView tvPrivacyPolicyBar;

    private Context context;
    private LicenseConfigUtil licenseUtil;
    private String IS_FROM_PRIVACY_DIALOG = "is_from_privacy_dialog";

    public UserAgreementAndPrivacyPolicyDialog(@NonNull Context context, LicenseConfigUtil licenseUtil) {
        super(context, R.style.PrivacyDialogTheme);
        this.context = context;
        this.licenseUtil = licenseUtil;
        bindView();
    }

    @Override
    protected int setContentView() {
        return R.layout.dialog_user_agreement_and_privacy_policy;
    }

    @Override
    protected void bindView() {
        super.bindView();
        initDialog();
    }

    private void initDialog() {
        getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        Window window = getWindow();
        window.setGravity(Gravity.CENTER);

        Display display = window.getWindowManager().getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (display.getWidth() * 0.9);
        params.height = (int) (display.getHeight() * 0.9);
        window.setAttributes(params);

        ivUserAgreementAndPrivacyPolicyExit.setOnClickListener(this);
        tvUserAgreementBar.setOnClickListener(this);
        tvPrivacyPolicyBar.setOnClickListener(this);
        show();
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.user_agreement_and_privacy_policy_exit:
                this.dismiss();
                break;
            case R.id.user_agreement_bar:
                dismiss();
                SPUtils.getInstance().put(IS_FROM_PRIVACY_DIALOG,false);
                new UserAgreementDialog(context, licenseUtil);
                break;
            case R.id.privacy_policy_bar:
                this.dismiss();
                SPUtils.getInstance().put(IS_FROM_PRIVACY_DIALOG,false);
                new PrivacyPolicyDialog(context, licenseUtil);
                break;
        }
    }
}

示例布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/dialog_privacy_bg_style">

    <LinearLayout
        android:id="@+id/user_agreement_and_privacy_policy_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/c_1B2F36"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/user_agreement_and_privacy_policy_exit"
            android:layout_width="@dimen/dp_30"
            android:layout_height="@dimen/dp_30"
            android:layout_marginLeft="@dimen/dp_10"
            android:layout_marginTop="@dimen/dp_10"
            android:padding="@dimen/dp_7"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/icon_cancel" />

        <TextView
            android:id="@+id/user_agreement_and_privacy_policy_bar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/dp_10"
            android:text="@string/userAgreementAndPrivacyPolicyTitle"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18"
            />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/user_agreement_and_privacy_policy_bar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/new_broad_list_item_style"
        android:paddingBottom="@dimen/dp_110"
        android:orientation="vertical"
        app:layout_constraintTop_toBottomOf="@+id/user_agreement_and_privacy_policy_bar">

        <TextView
            android:id="@+id/user_agreement_and_privacy_policy_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/dp_16"
            android:text="@string/userAgreementAndPrivacyPolicyWelcome"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/sp_20"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/user_agreement_and_privacy_policy_tips"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp_16"
            android:gravity="center_vertical"
            android:text="@string/userAgreementAndPrivacyPolicyTipsTitle"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_12"
            app:layout_constraintTop_toBottomOf="@+id/user_agreement_and_privacy_policy_title" />

        <LinearLayout
            android:id="@+id/user_agreement_and_privacy_policy_bar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp_16"
            android:background="@drawable/new_broad_list_item_style"
            android:orientation="horizontal"
            app:layout_constraintTop_toBottomOf="@+id/privacy_tips">

            <TextView
                android:id="@+id/user_agreement_and_privacy_policy_note_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/userAgreementAndPrivacyPolicyNote1"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/dp_12" />

            <TextView
                android:id="@+id/user_agreement_bar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/userAgreementBar"
                android:textColor="@color/c_03bcff"
                android:textSize="@dimen/dp_12"/>

            <TextView
                android:id="@+id/user_agreement_and_privacy_policy_note_2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/userAgreementAndPrivacyPolicyNote2"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/dp_12"/>

            <TextView
                android:id="@+id/privacy_policy_bar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="@string/privacyPolicyBar"
                android:textColor="@color/c_03bcff"
                android:textSize="@dimen/dp_12"
                app:layout_constraintBaseline_toBaselineOf ="@+id/user_agreement_bar"/>
        </LinearLayout>

        <TextView
            android:id="@+id/user_agreement_and_privacy_policy_tips_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp_16"
            android:layout_marginBottom="@dimen/dp_10"
            android:gravity="center_vertical"
            android:text="@string/userAgreementAndPrivacyPolicyTipsContent"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_12"
            app:layout_constraintTop_toBottomOf="@+id/user_agreement_and_privacy_policy_bar_layout" />

            <TextView
                android:id="@+id/user_agreement_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginBottom="@dimen/dp_10"
                android:layout_marginTop="@dimen/dp_40"
                android:gravity="center"
                android:text="@string/userAgreementTitle"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_14"
                app:layout_constraintTop_toBottomOf="@+id/privacy_tips" />

            <TextView
                android:id="@+id/user_agreement_time_stamp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginBottom="@dimen/dp_10"
                android:gravity="center|right"
                android:text="@string/userAgreementTimeStamp"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/user_agreement_title" />

        <TextView
            android:id="@+id/user_agreement_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="@dimen/dp_16"
            android:layout_marginBottom="@dimen/dp_10"
            android:gravity="center_vertical"
            android:text="@string/userAgreementContent"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/sp_12"
            app:layout_constraintTop_toBottomOf="@+id/user_agreement_time_stamp" />

        <TextView
                android:id="@+id/privacy_policy_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginTop="@dimen/dp_50"
                android:layout_marginBottom="@dimen/dp_10"
                android:gravity="center"
                android:text="@string/privacyPolicyTitle"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_14"
                app:layout_constraintTop_toBottomOf="@+id/user_agreement_content" />

            <TextView
                android:id="@+id/privacy_policy_time_stamp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginBottom="@dimen/dp_10"
                android:gravity="center|right"
                android:text="@string/privacyPolicyTimeStamp"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/privacy_policy_title" />

            <TextView
                android:id="@+id/privacy_policy_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:gravity="center|left"
                android:text="@string/privacyPolicyContent"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_14"
                app:layout_constraintTop_toBottomOf="@+id/privacy_policy_time_stamp" />
    </LinearLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

界面的样式定义

<!--new_broad_list_item_style.xml-->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!--<solid android:color="@color/c_ffffff" />-->
    <!--<stroke-->
        <!--android:width="1px"-->
        <!--android:color="@color/c_e5ebff" />-->
    <gradient
        android:angle="180"
        android:endColor="@color/new_broad_item_gradient_c1"
        android:startColor="@color/new_broad_item_gradient_c2" />
</shape>

<!--dialog_privacy_bg_style.xml-->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!--填充设置-->
<!--    <solid android:color="@color/c_203B44" />-->
    <gradient
        android:angle="180"
        android:endColor="@color/new_broad_item_gradient_c1"
        android:startColor="@color/new_broad_item_gradient_c2" />
    <!--圆角设置-->
    <corners android:radius="10dip" />

</shape>

用户协议界面

示例逻辑代码如下:

public class UserAgreementDialog extends BaseDialog implements View.OnClickListener {

    @BindView(R.id.user_agreement_exit)
    ImageView ivUserAgreementExit;

    private String IS_FROM_PRIVACY_DIALOG = "is_from_privacy_dialog";
    private LicenseConfigUtil licenseUtil;

    public UserAgreementDialog(Context context, LicenseConfigUtil licenseUtil) {
        super(context, R.style.PrivacyDialogTheme);
        this.licenseUtil = licenseUtil;
        bindView();
    }

    @Override
    protected void bindView() {
        super.bindView();
        initDialogView();
    }

    private void initDialogView() {
        getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        Window window = getWindow();
        window.setGravity(Gravity.CENTER);

        Display display = window.getWindowManager().getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (display.getWidth() * 0.9);
        params.height = (int) (display.getHeight() * 0.9);
        window.setAttributes(params);

        ivUserAgreementExit.setOnClickListener(this);
        show();
    }

    @Override
    protected int setContentView() {
        return R.layout.dialog_user_agreement;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.user_agreement_exit) {
            exitDialog();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            exitDialog();
        }
        return super.onKeyDown(keyCode, event);
    }

    private void exitDialog() {
        this.dismiss();
        Boolean isFromPrivacyDialog = SPUtils.getInstance().getBoolean(IS_FROM_PRIVACY_DIALOG, false);
        if (isFromPrivacyDialog) {
            new PrivacyDialog(context, licenseUtil).initDialog(context);
        } else {
            new UserAgreementAndPrivacyPolicyDialog(context, licenseUtil);
        }
    }
}

示例布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/dialog_privacy_bg_style"
    >

    <LinearLayout
        android:id="@+id/user_agreement_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/c_1B2F36"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/user_agreement_exit"
            android:layout_width="@dimen/dp_30"
            android:layout_height="@dimen/dp_30"
            android:layout_marginLeft="@dimen/dp_10"
            android:layout_marginTop="@dimen/dp_10"
            android:padding="@dimen/dp_1"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_back_white_24" />

        <TextView
            android:id="@+id/user_agreement_bar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/dp_10"
            android:text="@string/userAgreementTitle"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/user_agreement_bar">

        <LinearLayout
            android:id="@+id/user_agreement_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="@dimen/dp_110"
            android:background="@drawable/new_broad_list_item_style"
            android:orientation="vertical"
            app:layout_constraintTop_toBottomOf="@+id/user_agreement_bar">

            <TextView
                android:id="@+id/user_agreement_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/dp_16"
                android:text="@string/userAgreementTitle"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_20"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/user_agreement_release_note"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginBottom="@dimen/dp_16"
                android:gravity="center|left"
                android:text="@string/userAgreementReleaseNote"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/user_agreement_title" />

            <TextView
                android:id="@+id/user_agreement_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:gravity="center_vertical"
                android:text="@string/userAgreementContent"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/user_agreement_note" />
        </LinearLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

隐私政策界面

示例逻辑代码如下:

package com.konka.emergradio.privacyAndAuthorityDialog;

import android.content.Context;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;

import androidx.annotation.NonNull;

import com.blankj.utilcode.util.SPUtils;
import com.konka.emergradio.base.BaseDialog;
import com.konka.emergradio.R;
import com.konka.emergradio.utils.LicenseConfigUtil;

import butterknife.BindView;

public class PrivacyPolicyDialog extends BaseDialog implements View.OnClickListener {

    @BindView(R.id.privacy_policy_exit)
    ImageView ivPrivacyPolicyExit;
    private LicenseConfigUtil licenseUtil;
    private String IS_FROM_PRIVACY_DIALOG = "is_from_privacy_dialog";

    public PrivacyPolicyDialog(Context context, LicenseConfigUtil licenseUtil) {
        super(context, R.style.PrivacyDialogTheme);
        this.licenseUtil = licenseUtil;
        bindView();
    }

    @Override
    protected void bindView() {
        super.bindView();
        initDialogView();
    }

    private void initDialogView() {
        getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        Window window = getWindow();
        window.setGravity(Gravity.CENTER);

        Display display = window.getWindowManager().getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (display.getWidth() * 0.9);
        params.height = (int) (display.getHeight() * 0.9);
        window.setAttributes(params);


        ivPrivacyPolicyExit.setOnClickListener(this);
        show();
    }

    @Override
    protected int setContentView() {
        return R.layout.dialog_privacy_policy;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.privacy_policy_exit) {
            exitDialog();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            exitDialog();
        }
        return super.onKeyDown(keyCode, event);
    }

    private void exitDialog() {
        this.dismiss();
        Boolean isFromPrivacyDialog = SPUtils.getInstance().getBoolean(IS_FROM_PRIVACY_DIALOG, false);
        if (isFromPrivacyDialog) {
            new PrivacyDialog(context, licenseUtil).initDialog(context);
        } else {
            new UserAgreementAndPrivacyPolicyDialog(context, licenseUtil);
        }
    }
}

示例布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/dialog_privacy_bg_style">

    <LinearLayout
        android:id="@+id/privacy_policy_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/c_1B2F36"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/privacy_policy_exit"
            android:layout_width="@dimen/dp_30"
            android:layout_height="@dimen/dp_30"
            android:layout_marginLeft="@dimen/dp_10"
            android:layout_marginTop="@dimen/dp_10"
            android:padding="@dimen/dp_1"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_back_white_24" />

        <TextView
            android:id="@+id/privacy_policy_bar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/dp_10"
            android:text="@string/privacyPolicyTitle"
            android:textColor="@color/c_ffffff"
            android:textSize="@dimen/dp_18" />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/privacy_policy_bar">

        <LinearLayout
            android:id="@+id/privacy_policy_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/new_broad_list_item_style"
            android:orientation="vertical"
            android:paddingBottom="@dimen/dp_110"
            app:layout_constraintTop_toBottomOf="@+id/privacy_policy_bar">

            <TextView
                android:id="@+id/privacy_policy_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/dp_16"
                android:text="@string/privacyPolicyTitle"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_20"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/privacy_policy_time_stamp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:layout_marginBottom="@dimen/dp_16"
                android:gravity="center|right"
                android:text="@string/privacyPolicyTimeStamp"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/privacy_policy_title" />

            <TextView
                android:id="@+id/user_agreement_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_16"
                android:gravity="center_vertical"
                android:text="@string/privacyPolicyContent"
                android:textColor="@color/c_ffffff"
                android:textSize="@dimen/sp_12"
                app:layout_constraintTop_toBottomOf="@+id/user_agreement_time_stamp" />
        </LinearLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

隐私协议的文档

<!-- 用户隐私协议 -->
    <string name="agreeAuthority">去授权</string>
    <string name="confirmPrivacy" translatable="false">
        您需要同意《XX使用协议》和《XX隐私政策》,才能继续使用我们的服务喔
    </string>
    <string name="noUse" translatable="false">暂不使用</string>
    <string name="agreePrivacy" translatable="false">去同意</string>

    <string name="privacyTipsTitle" translatable="false">温馨提示</string>
    <string name="privacyTips" translatable="false">
        为了更好的保护你的权益以及履行监管要求,请你在使用前务必阅读《XX使用协议》和《XX隐私政策》内的所有条款,并特向你说明如下:\n
        1. 为向您提供基本服务,我们会遵守正当、合法、必要的原则收集和使用必要的信息。\n
        2. 基于你的授权,我们可能会收集和使用你的存储、位置信息、设备信息。\n
        3. 上述权限及摄像头、访问网络、访问存储空间、访问相册、GPS等敏感权限均不会默认或强制开启收集信息。\n
        4. 我们已使用符合业界标准的安全防护措施保护你的个人信息。
    </string>
    <string name="privacyExit" translatable="false">不同意</string>
    <string name="privacyAgree" translatable="false">同意</string>
    <string name="agreeNote" translatable="false">登录即代表你已同意</string>
    <string name="agreeUserAgreementAndPrivacyPolicy" translatable="false">\tXX使用协议、隐私政策</string>

    <string name="userAgreementAndPrivacyPolicyTitle">XX使用协议与隐私政策</string>
    <string name="userAgreementAndPrivacyPolicyWelcome">欢迎登录XX</string>

    <string name="userAgreementAndPrivacyPolicyTipsTitle">XX使用协议与XX隐私政策</string>
    <string name="userAgreementAndPrivacyPolicyNote1">以下内容是</string>
    <string name="userAgreementBar">《XX使用协议》</string>
    <string name="userAgreementAndPrivacyPolicyNote2"></string>
    <string name="privacyPolicyBar">《XX隐私政策》</string>
    <string name="userAgreementAndPrivacyPolicyTipsContent" translatable="false">
        在你登录XX前请务必审慎阅读、充分理解协议中相关条款内容。《XX使用协议》包括接受条款;服务说明;你的注册义务;用户账号、密码及安全;用户个人信息保护;提供者之责任;服务变更、中断或终止;
        担保与保证;用户行为;知识产权;用户专属权利;国际使用之特别告知;未成年人使用条款;一般条款。《XX隐私政策》包括我们如何收集和使用你的个人信息;我们如何使用Cookie 和同类技术;
        我们如何共享、转让、公开披露你的个人信息;我们如何保护你的个人信息;你的权利 ;关于儿童的个人信息;你的个人信息如何在全球范围转移;本政策如何更新;如何联系我们。
        你一旦登录XX,即视为你已了解并同意《XX使用协议》及《XX隐私政策》的各项内容。
    </string>

    <string name="userAgreementTitle">XX使用协议</string>
    <string name="userAgreementTimeStamp">2020年9月10日发布更新</string>
    <string name="userAgreementReleaseNote">
        本协议为XX《使用协议》的修订版本,自2020年9月10日公布。\n
        请你务必审慎阅读、充分理解协议中相关条款内容,特别是粗体标注的内容。你一旦登录XX,即视为你已了解并完全同意本协议各项内容,包括XX对使用协议随时所做的任何修改。
        如你不同意本协议及/或随时对其的修改,请你立即停止注册及使用XX所提供的全部服务。</string>
    <string name="userAgreementContent">
        1、接受条款 \n
        1.1 XX app的运营者及相关关联公司(以下简称“XX”)根据本使用协议的条款及不时发布的规则为你提供基于XX app
        (包括XXpc端、XX及XX APP相关客户端、移动网页端等)的互联网服务。本协议的条款可由XX随时修改,修改后的使用协议在网站上一经公布即有效代替原来的使用协议。
        你一旦在XXapp登录,即成为XX用户(以下简称“用户”或“你”),并受本协议的约束。\n
        1.2 当你使用XXapp单项服务时,你和XX应遵守XX随时公布的与该服务相关的指引和规则。前述所有的指引和规则,均构成本使用协议的一部分。\n
        1.3 你应遵守本协议的各项条款,合法合理使用XX提供的服务,否则,XX有权依据本协议中断或终止为你提供服务。同时,XX保留在任何时候收回你所使用的账号的权利。\n
        \n
        2、服务说明\n
        2.1 XX向用户提供包括但不限于如下服务:实现应急广播系统能够移动化办公,能够随时随地对广播进行发送和管理,加大应急广播系统的实用性,尽可能减少因设备、时间、
        地点等客观因素的限制,而无法对广播进行管理,使得应急广播系统更加完善。除非本协议另有其它明示规定,XX增加或强化目前本服务的任何新功能,包括所推出的新产品,均受本使用协议之规范。\n
        2.2 用户了解并同意,XX之服务、产品与资料仅依其当前所呈现的状况提供,而且明确地表示拒绝对于“服务”、“资料”或“产品”等给予任何明示或暗示之担保或保证,包括但不限于,
        为商业使用、适合于特定目的或未侵害他人权利之担保或保证等。XX对于因“服务”、 “产品”或“资料”等所产生之任何直接、间接、附带的或因此而导致之衍生性损失概不负责。
        XX对于任何用户信息或个性化设定之时效、删除、传递错误、未予储存或其它任何问题,均不承担任何责任。\n
        2.3 你同意XX有权制订关于使用本服务的一般措施及限制,包括但不限于本服务将保留所发布内容或其它发布内容之最长期间,以及一定期间内你使用本服务之次数上限(及/或每次使用时间之上限)。
        通过本服务发布或传送之任何信息、通讯资料和其它内容,如被删除或未予储存,你同意XX无须承担任何责任。你也同意,XX有权依其自行之考虑,不论通知与否,随时变更这些一般措施及限制。\n
        \n
        3、你的注册义务\n
        3.1 为了能使用本服务,按照中国法律的要求,你同意以下事项:依本服务注册提示填写你正确的注册邮箱、密码、名号、手机号码等信息,并确保今后更新的登录邮箱、名号、头像及手机号码等资料的真实性、
        有效性和合法性。若你提供任何违法、不道德或XX认为不适合在XXapp上展示的资料;或者XX有理由怀疑你的行为属于程序或恶意操作,
        XX有权无须事先通知即可暂停或终止你使用账号,并拒绝你于现在和未来使用本服务之全部或任何部分。\n
        3.2 XX无须对你(任何用户)的任何注册或登记资料承担任何责任,包括但不限于鉴别、核实任何注册或登记资料的真实性、正确性、完整性、适用性及/或是否为最新资料的责任。\n
        \n
        4、用户账号、密码及安全\n
        4.1 完成本服务的注册程序并成功注册之后,你可使用你的注册邮箱/手机号码和密码,登录到你在XXapp的账号(下称“账号”)。
        登录完成之时,你便获得了账号的使用权。保护账号安全,是你的责任。\n
        4.2 你应对所有使用你的账号的行为负完全的责任。你同意:\n
        1)你的XX账号遭到未获授权的使用,或者发生其它任何安全问题时,你将立即通知XX;\n
        2)如果你未保管好自己的账号和密码,因此而产生的任何损失或损害,XX不承担任何责任;\n
        3)你要对使用账号的所有行为给你、XX或第三方造成的损害负全责,包括你未保管好自己的账号或密码的情形。\n
        4.3 由于通过账号可获取到用户的个人信息,且账号的所有权归XX所有,除法律明文规定外,未经XX同意,用户不得将账号转让、出售或出借给他人使用。\n
        4.4 若你连续六个月未登录XX平台,且不存在未到期的有效业务,XX有权限制你对账号的使用。由此造成的不利后果由你自行承担。\n
        4.5 你选择将XX账号与第三方账号进行绑定的,除你自行解除绑定关系外,如发生下列任何一种情形,你已绑定的第三方账号也有可能被解除绑定而XX无需对你或任何第三方承担任何责任:\n
        1)你违反法律法规、国家政策或本协议的;\n
        2)你违反第三方账户用户协议或其相关规定的;\n
        3)其他需要解除绑定的情形。\n
        \n
        5、用户个人信息保护\n
        5.1 保护你个人信息安全既是法律要求,也是XX长期坚持的一项基本原则。你提供的注册资料及XX保留的有关你的其它资料将受到中国有关法律的保护。
        XX将根据中国法律、本协议、《XX隐私政策》的规定收集、存储、使用和透露你的个人信息。\n
        5.2 一般情况下,你可随时浏览、修改你在XX上的信息,但出于安全性和身份识别的考虑,你可能无法修改注册时提供的初始注册信息及其他验证信息。\n
        \n
        6、提供者之责任\n
        6.1 根据有关法律法规,XX在此郑重提请你注意,任何经由本服务而发布、上传的文字、音乐、图片、图形、视频或其他资料(以下简称“内容 ”),
        无论系公开还是非公开传送,均由内容提供者承担责任。XX仅为用户提供信息存储空间服务,无法控制经由本服务传送之内容,因此不保证内容的正确性、完整性或有效性。
        你已预知使用本服务时,可能会接触到令人不快、不适当或令人厌恶之内容。在任何情况下,XX均不为任何内容负责,但XX有权依法停止传输任何前述内容并采取相应行动,
        包括但不限于暂停用户使用本服务的全部或部分,保存有关记录,并向有关机关报告等。\n
        6.2 你明确了解并同意,基于以下原因而造成的,包括但不限于经济、信誉、数据损失或其他无形损失,XX不承担任何直接、间接、附带、特别、衍生性或惩罚性赔偿责任:\n
        1)本服务之使用或无法使用;\n
        2)为替换从或通过本服务购买或取得之任何商品、数据、信息、服务,收到的讯息,或与第三方缔结交易而发生的成本;\n
        3)你的传输或数据遭到未获授权的存取或改变;\n
        4)任何第三方在本服务中所作之声明或行为;\n
        5)第三方以任何方式发布或投递欺诈性信息,或诱导用户受到经济损失;\n
        6)与本服务相关的其他事宜,但本使用协议有明确规定的除外。\n
        \n
        7、服务变更、中断或终止\n
        7.1 XX可能会对服务内容进行变更、也可能会中断、终止服务。\n
        7.2 鉴于网络服务的特殊性(包括但不限于服务器的稳定性问题、恶意的网络攻击等行为或XX无法控制的情形),你同意XX有权随时中断或终止部分或全部的服务。\n
        7.3 你理解,XX需要定期或不定期对提供服务的平台或相关设备进行维护、升级或其他目的暂停部分或全部服务,如因此类情况而造成服务在合理时间内的中断,XX无需为此承担任何责任。\n
        7.4 如发生以下任何一种情形,XX有权随时中断或终止向你提供本协议项下的服务而无需对你或任何第三方承担责任:\n
        1)你提供个人资料不真实;\n
        2)你违反法律、政策或违反本使用协议。\n
        7.5 你同意XX基于其自行之考虑,因任何理由,包含但不限于缺乏使用,或XX认为你已经违反本使用协议,终止你的账号或本服务之使用(或服务之任何部分),
        并将你在本服务内任何内容加以移除并删除。你同意依本使用协议任何规定提供之服务,无需进行事先通知即可中断或终止。你承认并同意,XX可立即关闭或注销你的账号及删除你账号中所有相关信息及文件,
        及/或禁止继续使用前述文件或本服务。此外,你同意若本服务之使用被中断或终止或你的账号及相关信息和文件被关闭或注销,XX对你或任何第三人均不承担任何责任。\n
        \n
        8、担保与保证\n
        你明确了解并同意∶\n
        1)本使用协议的任何规定不会免除XX因过错而造成你人身伤害或财产损失的任何责任;\n
        2)XX不保证以下事项∶\n
        \t· 本服务将符合你的要求;\n
        \t· 本服务将不受干扰、及时提供、安全可靠或不会出错;\n
        \t· 使用本服务取得之结果正确可靠;\n
        \t· 你经由本服务购买或取得之任何产品、服务、资讯或其它信息将符合你的期望;\n
        3)是否使用本服务下载或取得任何资料应由你自行考虑且自负风险,因任何资料之下载而导致的你电脑系统之任何损坏或数据丢失等后果,由你自行承担;\n
        4)你自XX或经由本服务取得的任何建议或信息,无论是书面或口头形式,除非本使用协议有明确规定,将不构成本使用协议以外之任何保证。\n
        \n
        9、用户行为\n
        9.1 你应遵守中华人民共和国相关法律法规,并同意对以任何方式使用你的登录账号而使用本服务的任何行为及其结果承担全部责任。如你的行为违反国家法律,你将依法承担全部法律责任;
        如涉嫌构成犯罪,司法机关将追究你的刑事责任,XXapp将严格按照法律规定的义务及司法机关的要求进行配合。同时,如果XX有理由认为你的任何行为,包括但不限于你的任何言论或其它行为违反
        或可能违反国家法律法规的任何规定,XX可在任何时候不经任何事先通知终止向你提供服务。\n
        9.2 你同意将不会利用本服务进行任何违法或不正当的活动,包括但不限于下列行为∶\n
        1)发布或以其他方式传送含有下列内容之一的信息:\n
        \t· 反对宪法所确定的基本原则的;\n
        \t· 危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;\n
        \t· 损害国家荣誉和利益的;\n
        \t· 煽动民族仇恨、民族歧视、破坏民族团结的;\n
        \t· 破坏国家宗教政策,宣扬邪教和封建迷信的;\n
        \t· 散布谣言,扰乱社会秩序,破坏社会稳定的;\n
        \t· 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;\n
        \t· 侮辱或者诽谤他人,侵害他人合法权利的;\n
        \t· 含有虚假、诈骗、有害、胁迫、侵害他人隐私、骚扰、侵害、中伤、粗俗、猥亵、或其他道德上令人反感的内容;\n
        \t· 含有中国法律、法规、(部门)规章以及任何具有法律效力之规范所限制或禁止的其他内容的;\n
        \t· 含有XX认为不适合在XX展示的内容;\n
        2)以任何方式危害他人的合法权益;\n
        3)冒充其他任何人或机构,或以虚伪不实的方式陈述或谎称与任何人或机构有关;\n
        4)将依据任何法律、合约或法定关系(例如由于雇佣关系和依据保密合约所得知或揭露之内部资料、专属及机密资料)而知悉但无权传送之任何内容加以发布、发送电子邮件或以其它方式传送;\n
        5)将侵害他人著作权、专利权、商标权、商业秘密、或其他专属权利(以下简称“专属权利”)之内容加以发布或以其他方式传送;\n
        6)将任何“广告信函”、“促销资料”、“垃圾邮件”、“滥发信件”、“连锁信件”、“直销”或其他任何形式的劝诱资料加以发布、发送或以其它方式传送;\n
        7)将设计目的在于干扰、破坏或限制任何计算机软件、硬件或通讯设备功能之计算机病毒(包括但不限于木马程序(trojan horses)、蠕虫(worms)、定时炸弹、删除蝇(cancelbots)
        (以下简称“病毒”)或其他计算机代码、档案和程序之任何资料,加以发布、发送或以其他方式传送;\n
        8)干扰或破坏本服务或与本服务相连线之服务器和网络,或违反任何关于本服务连线网络之规定、程序、政策或规范;\n
        9)跟踪、人肉搜索或以其他方式骚扰他人;\n
        10)故意或非故意地违反任何适用的当地、国家法律,以及任何具有法律效力的规则;\n
        11)未经合法授权而截获、篡改、收集、储存或删除你或他人的个人信息、站内邮件或其他数据资料,或将获知的此类资料用于任何非法或不正当目的。
        你已认可XX未对用户的使用行为进行全面控制,你使用任何内容时,包括依赖前述内容之正确性、完整性或有效性时,你同意将自行加以判断并承担所有风险,而不依赖于XX。
        但XX依其自行之考虑,有权拒绝和删除经由本服务提供之违反本条款的或其他引起XX反感的任何内容。\n
        9.3 由于你通过本服务提供、发布或传送之内容、你与本服务连线、你违反本使用协议、或你侵害他人任何权利因而衍生或导致任何第三人提出任何索赔或请求,
        包括但不限于合理的律师费、诉讼费,你同意赔偿XX及其子公司、关联公司、高级职员、代理人、品牌共有人或其他合作伙伴及员工,并使其免受损害,并承担由此引发的全部法律责任。\n
        9.4 你同意不对本服务任何部分或本服务之使用或获得,进行复制、拷贝、出售、转售或用于任何其他商业目的。\n
        \n
        10、知识产权\n
        10.1 XX在本服务中提供的内容(包括但不限于网页、界面设计、版面框架、文字、音频、视频、图片或其他资料等)等知识产权归XX或相关权利人所有。
        除另有约定外,XX提供本服务时所依托的软件、系统等的著作权、专利权及其他知识产权归XX所有。XXapp、XX以及其他XX标识及产品、
        服务名称,均为XX之商标。未经XX事先书面同意,你不得擅自删除、掩盖或更改XX的版权声明、商标或其它权利声明,不得将XX的商标以任何方式展示或使用
        或作其它处理,或表示你有权展示、使用或另行处理XX的商标。\n
        10.2 你在XXapp上传或发布的内容,应保证为其著作权人或已取得合法授权,并且该内容不会侵犯任何第三方的合法权益。点击同意本协议,即表明你同意授予XX所有上述内容的非
        独家使用权许可,据该许可XX将有权以展示、推广等不为我国法律所禁止的方式使用前述内容。同时你同意许可XX视具体情况就任何主体侵犯你权益的事宜进行维权,包括但不限于发
        送维权函件、提起诉讼、申请仲裁等,其效力及于用户在XXapp发布的任何受著作权法保护的内容,你也可以授权其他第三方为你维权,且可以随时终止对XX的授权。\n
        10.3 你有权将你在XXapp上发布的内容授权给他人使用。XX欢迎你优先选择XX就相关内容进行合作。\n
        10.4 你了解并同意,本服务及本服务所使用之相关软件含有受到相关知识产权及其他法律保护之专有保密资料。你也了解并同意,经由本服务或广告商向你呈现之赞助广告或信息所包含之内容,
        亦受到著作权、商标权、专利权或其他专属权利之法律保护。未经XX或广告商明示授权,你不得修改、出租、出借、出售、散布本服务或软件之任何部分或全部,或据以制作衍生著作,
        或使用擅自修改后的软件等。XX仅授予你个人、不可移转及非专属之使用权,使你得于在单机计算机上使用其软件之目的,但你不得(且不得允许任何第三人)复制、修改、改编、翻译、
        创作衍生著作、进行还原工程、反向组译、传播或以其它方式发现原始码,或出售、转让、再授权或提供软件设定担保,或以其它方式移转软件之任何权利。你同意将通过由XX所提供的
        界面而非任何其它途径使用本服务。\n
        10.5 如你违反世界版权公约、中华人民共和国著作权法、商标法、专利法、反不正当竞争法及其他与知识产权方面相关的法律法规或本协议约定,你应自行承担因此而给他人(包括XX)造成的损害,承担相应的法律责任。\n
        \n
        11、用户专属权利\n
        11.1 XX尊重他人合法权益(包括知识产权、名誉权、商誉权等),呼吁你也尊重他人合法权益。\n
        11.2 如果你违反法律法规的禁止性规定、对他人的合法权益或公众利益造成了侵害,XX将依国家法律法规的规定,或在适当的情形下,依本协议或其相关规定,删除特定内容或以至终止你对账户的使用。\n
        11.3 若你认为你的合法权益遭到侵害,请你查看《XX侵权投诉指引》,按照指引提示提交投诉,XX将依法进行处理。\n
        \n
        12、国际使用之特别告知\n
        你已了解互联网的无国界性,同意遵守当地所有关于网上行为及内容之法律法规。你特别同意遵守有关从中国或你所在国家或地区输出信息之传输的所有适用法律法规。\n
        \n
        13、未成年人使用条款\n
        如你是未成年用户,请在法定监护人的陪同下仔细阅读本使用协议,你及法定监护人应按照法律及本协议规定承担责任。\n
        \n
        14、一般条款\n
        14.1 XX公布的《社区指导原则》、《版权声明》、《XX隐私政策》均是本协议的有效组成部分,本协议及与XX服务相关的指引和规则(包括XX单项服务指引,
        如:《XX小站服务协议》共同规范你对于本服务之使用行为。在你使用相关服务、使用第三方提供的内容或软件时,亦应遵从所适用之附加条款及条件。\n
        14.2 本使用协议及你与XX之关系,均适用中华人民共和国法律。你与XX就本服务、本使用协议或其他有关事项发生的争议,应首先友好协商解决,
        协商不成时应提请XX实际运营者所在地有管辖权的人民法院通过诉讼解决。\n
        14.3 XX未行使或执行本使用协议任何权利或规定,不构成对前述权利或权利之放弃。\n
        14.4 倘若本使用协议之任何规定因与中华人民共和国法律抵触而无效,本使用协议其他规定仍应具有完整的效力及效果。\n
        14.5 本使用协议之标题仅供方便而设,不具任何法律或契约效果。\n
    </string>

    <string name="privacyPolicyTitle">XX隐私政策</string>
    <string name="privacyPolicyTimeStamp">2020年9月10日更新</string>
    <string name="privacyPolicyContent">
        \n
        引言\n
        \n
        XX深知个人信息(含个人敏感信息)对你的重要性,并会全力保护你的个人信息安全。我们致力于维持你对我们的信任,恪守以下原则,保护你的个人信息:权责一致原则、目的明确原则、
        选择同意原则、最小必要原则、公开透明原则、确保安全原则、主体参与原则等。同时,XX承诺,我们将按业界成熟的安全标准,采取相应的安全保护措施来保护你的个人信息。\n
        \n
        本隐私政策(以下简称“本政策”)适用于XX的所有相关产品与/或服务。如XX及关联公司的产品与/或服务中使用了XX提供的产品与/或服务但未设立独立的隐私政策的,
        则本政策同样适用于该产品与/或服务。如XX及关联公司就其向你提供的产品与/或服务单独设立有隐私政策的,则相应的产品与/或服务适用于相应隐私政策。在使用XX各项产品与/或服务前,
        请你务必仔细阅读并透彻理解本政策,并做出你认为适当的选择。一旦你开始使用XX的各项产品与/或服务,即表示你已充分理解并同意本政策。需要提醒你注意,本隐私政策仅适用于我们所收集的信息,
        不适用于通过我们的产品与/或服务而接入的第三方产品与/或服务(包括任何第三方网站)收集的信息以及通过在我们产品与/或服务中进行广告服务的其他公司或机构所收集的信息。\n
        \n
        本政策将帮助你了解以下内容:\n
        \n
        1、我们如何收集和使用你的个人信息\n
        2、我们如何使用Cookie 和同类技术\n
        3、我们如何共享、转让、公开披露你的个人信息\n
        4、我们如何保护你的个人信息\n
        5、你的权利\n
        6、关于儿童的个人信息\n
        7、你的个人信息如何在全球范围转移\n
        8、本政策如何更新\n
        9、如何联系我们\n
        10、争议解决\n
        \n
        \n
        相关术语及定义\n
        \n
        1、XX:指XXapp或对XXapp享有所有权或运营权的主体北京豆网科技有限公司及其关联公司。\n
        2、个人信息:指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息,包括个人基本资料(姓名、出生日期)、
        个人身份信息(身份证、军官证、护照、工作证)、个人生物识别信息(个人基因、指纹)、网络身份标识信息(系统账号、IP地址、邮箱地址及前述有关的密码、口令、口令保护答案)、
        个人健康生理信息、个人教育工作信息(个人职业、职位、工作单位、学历、学位、教育经历)、个人财产信息(银行账号、存款信息、交易和消费记录、财产信息、征信信息)、
        个人通信信息(通信通讯联系方式、通信记录和内容)、联系人信息(通讯录、好友列表、群列表)、个人上网记录(指通过日志存储的用户操作记录)、个人常用设备记录(包括硬件序列号、设备MAC
        地址、软件列表、唯一设备识别码)、个人位置信息(包括行踪轨迹、精准定位信息、住宿信息等)其他信息(婚史、宗教信息、性取向、未公开的违法犯罪记录等)。
        本定义出自于GB/T 35273-2017《信息安全技术 个人信息安全规范》。\n
        3、个人敏感信息:指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息。包括个人财产信息(银行账号、鉴别信息、交易和消费记
        录、流水记录等)、个人生物识别信息、个人身份信息(如身份证、军官证、护照、工作证)、网络身份标识信息(如系统账号、邮箱地址及前述有关的密码、口令、口令保护答案)、其他信息(个人电话号
        码、性取向、婚史、行踪轨迹、网页浏览记录、精确定位信息)等,我们将在本隐私政策中对全部个人敏感信息加粗斜体处理。本定义出自于GB/T 35273-2017《信息安全技术 个人信息安全规范》。\n
        4、收集:指获得对个人信息的控制权的行为,包括由个人信息主体主动提供、通过与个人信息主体交互或记录个人信息主体行为等自动采集,以及通过共享、转让、搜集公开信息间接获取等方式。\n
        5、删除:指在实现日常业务功能所涉及的系统中去除个人信息的行为,使其保持不可被检索、访问的状态。\n
        6、公开披露:指向社会或不特定人群发布信息的行为。\n
        7、转让:指将个人信息控制权由一个控制者向另一个控制者转移的过程。\n
        8、共享:指个人信息控制者向其他控制者提供个人信息,且双方分别对个人信息拥有独立控制权的过程。\n
        9、匿名化:指通过对个人信息的技术处理,使得个人信息主体无法被识别,且处理后的信息不能被复原的过程。注:个人信息经匿名化处理后所得的信息不属于个人信息。\n
        10、去标识化:指通过对个人信息的技术处理,使其在不借助额外信息的情况下,无法识别个人信息主体的过程。\n
        11、关联公司:指相互之间存在关联关系的公司,关联关系是指公司控股股东、实际控制人、董事、监事、高级管理人员与其直接或者间接控制的企业之间的关系,以及可能导致公司利益转移的其他关系。\n
        \n
        \n
        一、我们如何收集和使用你的个人信息\n
        \n
        (一)我们如何收集你的个人信息\n
        你在使用XX提供的产品与/或服务时,为了更好地实现你的目的,我们可能收集和使用你的个人信息。包括:\n
        \n
        1、你在登录XX账号时提供的信息\n
        登录XX账号时,需要你提供手机号码、IP地址、端口的信息,我们将通过发送短信验证码或邮件的方式来验证你的账号是否有效。你可根据自身需求补充填写个人
        信息(头像、昵称、性别、生日)。\n
        \n
        2、在你使用产品与/或服务的过程中收集的信息\n
        使用本隐私政策“(二)我们如何使用你的个人信息”中所列举的XX产品与/或服务时,我们可能会收集你使用的设备信息(包括操作系统、软件版本、语言设置、IP地址),浏览信息
        (包括搜索关键词、访问页面链接和访问时间),发表信息(包括文字、图片、视频),位置信息(包括设备位置信息),身份信息(包括回传参数时需要提供的邮箱、手机号码)。\n
        \n
        3、第三方向XX提供的信息:\n
        你在第三方产品与/或服务中使用XX的时候,我们会收集第三方产品与/或服务向我们提供的有关信息。\n
        你提供的上述信息,将在你使用本产品与/或服务期间持续授权我们使用。在你注销账号时,我们将停止使用并删除上述信息。\n
        上述信息将存储于中华人民共和国境内,不会进行跨境传输。\n
        提供上述信息,尤其是个人敏感信息,你可能面临用户信息泄露或用户账号被盗、个人隐私及财产安全难以保障等风险,但我们将尽最大努力避免上述风险发生。\n
        如你选择不提供上述信息,你可能无法注册成为我们的用户或无法享受我们提供的某些产品与/或服务,或者无法达到相关产品与/或服务拟达到的效果。\n
        \n
        (二)我们如何使用你的个人信息\n
        我们会在下列情况下使用你的个人信息:\n
        1、向你提供你使用的各项产品与/或服务,并维护、改进这些服务。\n
        (1) 广播播发功能:支持广播列表,包含应急、日常、演练等三种模式的广播;支持应急广播、日常广播、演练广播等三种广播的播发;
        支持纯文本、文字转语音、音频、录音、平台音源通道等多种资源的广播播发;支持县、镇、村、以及指定设备的广播播发。\n
        (2) 广播审核功能:支持广播审核功能;支持未通过审核的广播进行重新审核功能;支持未审核、未通过、已通过等广播审核详情的查看。\n
        (3) 参数配置功能:支持未通过审核的广播进行重新审核功能;支持对指定区域下的所有设备进行参数配置;支持对单个设备进行参数设置。\n
        (4) 平台检测功能:支持对平台服务器使用率(CPU、内存)的监测;支持对平台服务器的连接数量进行监测(http、tcp、rtsp)。\n
        (5) 查阅设备信息:支持查看当前平台已有设备的列表;支持查看指定区域或指定条件下的设备列表;支持查看设备所在的地理位置以及设备详情。\n
        (6) 经你同意的其他目的,包括但不限于向你发出产品和服务信息,或通过系统向你展示个性化的第三方推广信息,或在征得你同意的情况下与我们的合作伙伴共享信息以
        便他们向你发送有关其产品和服务的信息。有的信息有可能是你不希望接收的信息。\n
        \n
        2、需要提醒你注意,以下情形中,使用你的个人信息无需你的同意:\n
        (1) 与个人信息控制者履行法律法规规定的义务相关的;\n
        (2) 与国家安全、国防安全直接相关的;\n
        (3) 与公共安全、公共卫生、重大公共利益直接相关的;\n
        (4) 与刑事侦查、起诉、审判和判决执行等直接相关的;\n
        (5) 出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;\n
        (6) 所收集的个人信息是你自行向社会公众公开的;\n
        (7) 从合法公开披露的信息中收集的你的个人信息的,如合法的新闻报道、政府信息公开等渠道;\n
        (8) 根据你的要求签订和履行合同所必需的;\n
        (9) 用于维护所提供的产品与/或服务的安全稳定运行所必需的,例如发现、处置产品与/或服务的故障;\n
        (10) 出于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的。\n
        \n
        \n
        二、我们如何使用Cookie和同类技术\n
        \n
        (一)Cookie\n
        使用 Cookie 能帮助你实现你的联机体验的个性化,你可以接受或拒绝 Cookie ,大多数 Web 浏览器会自动接受 Cookie,但你通常可根据自己的需要来修改浏览器的设置以拒绝 Cookie。
        为了让你在访问XX时能得到更好的服务,XX有时会使用 Cookie 以便知道哪些网站受欢迎。Cookie不会跟踪个人信息。\n
        当你登录XX时,XX亦会使用 Cookie。在这种情况下,XX会收集并存储有用信息,当你再次访问XX时,我们可辨认你的身份。
        来自XX的 Cookie 只能被XX读取。如果你的浏览器被设置为拒绝 Cookie,你仍然能够访问XX的大多数界面。\n
        (二)网站信标和像素标签\n
        除 Cookie 外,我们还会在网站上使用网站信标和像素标签等其他同类技术。例如,我们向你发送的电子邮件可能含有链接至我们网站内容的点击 URL。如果你点击该链接,我们则会跟踪此次点击,
        帮助我们了解你的产品或服务偏好并改善客户服务。网站信标通常是一种嵌入到网站或电子邮件中的透明图像。借助于电子邮件中的像素标签,我们能够获知电子邮件是否被打开。
        如果你不希望自己的活动以这种方式被追踪,则可以随时从我们的寄信名单中退订。\n
        (三)Do Not Track(请勿追踪)\n
        很多网络浏览器均设有 Do Not Track 功能,该功能可向网站发布 Do Not Track 请求。目前,主要互联网标准组织尚未设立相关政策来规定网站应如何应对此类请求。
        但如果你的浏览器启用了 Do Not Track,那么我们的网站都会尊重你的选择。\n
        \n
        \n
        三、我们如何共享、转让、公开披露你的个人信息\n
        \n
        我们充分知晓因违法共享、转让、公开披露个人信息对个人信息主体造成损害时所应承担的法律责任,对于你的个人信息的一切共享、转让、公开披露,我们将严格按照以下条款进行:\n
        \n
        (一)共享\n
        尊重用户个人隐私是XX的一项基本原则。除以下情形外,我们不会与任何公司、组织和个人分享你的个人信息:\n
        1、在获取明确同意的情况下共享:获得你的明确同意后,我们会与其他方共享你的个人信息;\n
        2、我们可能会按照司法机关或行政机关的要求,对外共享你的个人信息;\n
        3、与我们的关联公司共享:你的个人信息可能会与XX的关联公司共享。我们只会共享必要的个人信息,且受本隐私政策中所声明目的的约束。关联公司如要改变个人信息的处理目的,将再次征求你的授权同意。\n
        4、与授权合作伙伴共享:仅为实现本政策中声明的目的,我们的某些产品与/或服务将由授权合作伙伴提供。我们可能会与合作伙伴共享你的某些个人信息,
        以提供更好的客户服务和用户体验。我们仅会出于合法、正当、必要、特定、明确的目的共享你的个人信息,并且只会共享提供产品与/或服务所必要的个人信息,
        并对我们与之共享个人信息的公司、组织和个人签署严格的保密协定,要求他们按照我们的说明、本隐私政策以及其他任何相关的保密和安全措施来处理个人信息。\n
        目前,我们的合作伙伴包括:\n
        (1) 平台合作的第三方商家:为帮助你实现产品或服务的使用或者为你提供售后服务,我们会与平台的第三方商家共享你的订单和交易相关信息。\n
        (2) 合作的第三方SDK服务商:当你使用APP中由第三方提供的功能时,我们可能会接入由第三方提供的软件开发包(SDK)以实现相关功能。具体包括如下:\n
        A. 地理位置服务:为给你提供位置服务,第三方地理位置服务商高德SDK会收集你的设备信息及地理位置信息以便可以向你推送附近内容的服务;\n
        B. 数据统计功能:我们会使用友盟SDK以准确记录App的活跃情况、设备信息、网络相关信息。\n
        C.消息推送:为给你提供及时的消息推送,第三方推送服务商可能会获取你必要设备信息、手机状态信息、地理位置信息、网络相关信息以便推送你可能更感兴趣的信息,
        这些SDK包括:Vivo Push(仅对Vivo市场生效) 、OPPO Push(仅对OPPO市场生效)、华为推送(仅对华为生效)、小米(仅对小米生效)。\n
        D. 其它功能:如App崩溃统计,我们使用了Bugly、Crashlytics 等,相关功能可能会获取你的设备信息和网络相关信息。\n
        \n
        (二)转让\n
        我们不会将你的个人信息转让给任何公司、组织和个人,但以下情况除外:\n
        1、在获取明确同意的情况下转让:获得你的明确同意后,我们会向其他方转让你的个人信息。\n
        2、在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会在要求新的持有你个人信息的公司、组织继续受此隐私政策的约束,否则我们将要求该公司、组织重新向你征求授权同意。\n
        \n
        (三)公开披露\n
        除了因XX社区维护需要,对违规账号、欺诈、辱骂等严重损害XX社区的行为进行处罚公告(如公布被处罚账号的主页链接),
        或者公布中奖/获胜者名单时展示相关信息等必要事宜而进行必要披露之外,我们仅会在获得你明确同意后,公开披露你的个人信息。\n
        \n
        (四)共享、转让、公开披露个人信息授权同意的例外情形\n
        根据法律法规的规定,在下述情况下,共享、转让、公开披露你的个人信息无需事先征得你的授权同意:\n
        1、与我们履行法律法规规定的义务相关的;\n
        2、与国家安全、国防安全直接相关的;\n
        3、与公共安全、公共卫生、重大公共利益直接相关的;\n
        4、与刑事侦查、起诉、审判和判决执行等直接相关的;\n
        5、出于维护你或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;\n
        6、你自行向社会公众公开的个人信息;\n
        7、从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。\n
        \n
        \n
        四、我们如何保护你的个人信息\n
        \n
        (一) 我们已使用符合业界标准的安全防护措施保护你提供的个人信息, 防止数据遭到未经授权访问、公开披露、使用、修改、损坏或丢失。我们会采取一切合理可行的措施,
        保护你的个人信息。例如,在你的浏览器与 “服务”之间交换数据(如信用卡信息)时受SSL加密保护;我们同时对XXapp提供 https 安全浏览方式;我们会使用加密技术确保数据的保密性;
        我们会使用受信赖的保护机制防止数据遭到恶意攻击;我们会部署访问控制机制,确保只有授权人员才可访问个人信息;以及我们会举办安全和隐私保护培训课程,加强员工对于保护个人信息重要性的认识。\n
        \n
        (二) 我们会采取一切合理可行的措施,确保未收集无关的个人信息。除非取得你的书面许可,我们将在且仅在你删除或注销账户后36个月保留你的个人信息, 超出此期限后,我们将会对你的个人
        信息进行匿名化处理或销毁。\n
        \n
        (三) 互联网并非绝对安全的环境,而且电子邮件、即时通讯以及与其他XX用户的交流方式并未加密,我们强烈建议你不要通过此类方式发送个人信息。请使用复杂密码,协助我们保证你的账号安全。\n
        \n
        (四) 互联网环境并非百分之百安全,我们将尽力确保你发送给我们的任何信息的安全性。如果我们的物理、技术或管理防护设施遭到破坏,导致信息被非授权访问、公开披露、
        篡改或毁坏,导致你的合法权益受损,我们将承担相应的法律责任。\n
        \n
        (五) 在不幸发生个人信息安全事件后,我们将按照《网络安全法》第42条第二款之规定及时向你告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、你可自主防范和降
        低风险的建议、对你的补救措施等。我们将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知你,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。\n
        \n
        同时,我们还将按照监管部门要求,主动上报个人信息安全事件的处置情况。\n
        \n
        \n
        五、你的权利\n
        \n
        无论你何时使用XX的相关产品与/或服务,我们都会尽一切可能保证你可以顺利访问自己的账户信息。如果这些信息有误,我们会努力提供各种方式来让你快速更新或删除账户内信息。
        为了使你拥有充分的能力保障你的隐私和安全,你拥有如下权利:\n
        \n
        (一)访问你的个人信息\n
        除司法机关或行政机关另有要求外,你有权随时访问你的个人信息。包括以下信息:\n
        1、账户信息:\n
        如果你希望访问或编辑你的账户中的名号/昵称、域名、头像、登录邮箱、手机号、隐私设置等,
        可以通过访问首页设置页面进行设置执行此类操作。\n
        2、使用信息:\n
        你可以在相关产品页面随时查阅你的使用信息,包括:广播发布内容、设备详情、广播审核等。\n
        如果你无法通过上述方式访问,你可以随时联系我们,我们将尽快回复你的请求。\n
        \n
        (二)更正你的个人信息\n
        当你发现你所填写的或者我们处理的关于你的个人信息有错误时,你有权自行更正。当你无法自行更正时,你可以随时联系我们,我们将尽快回复你的更正请求。\n
        \n
        (三)删除你的个人信息\n
        你有权随时自行删除或者联系我们删除你的个人信息。在以下情形中,你可以向我们提出删除个人信息的请求:\n
        1、我们处理个人信息的行为违反法律法规的;\n
        2、我们收集、使用你的个人信息,却未征得你的同意;\n
        3、我们处理个人信息的行为违反了与你的约定;\n
        4、你不再使用我们的产品或服务,或你注销了账号;\n
        5、我们不再为你提供产品或服务。\n
        \n
        若我们决定响应你的删除请求,我们还将同时通知以合作方式从XX获得你的个人信息的实体,要求其及时删除,除非这些实体另行获得你的独立授权。
        但请知悉,若你在XX的公开信息被其它用户或与我们没有合作、关联以及不受我们控制的独立第三方抓取、缓存、储存、复制,
        或通过其它用户在其它网站上传、保存时,相关信息将不受XX的控制。\n
        当你从我们的服务中删除你的个人信息后,我们也会从备份系统中删除相应的信息。\n
        如因经营不善等原因,我们停止运营了,我们会立即停止对你对应个人信息的收集,并删除已收集的个人信息。\n
        \n
        (四)改变你授权同意的范围或撤回你的授权\n
        每个业务功能需要一些基本的个人信息才能得以完成(见本政策“第一部分”)。对于额外收集的个人信息的收集和使用,你可以随时给予或收回你的授权同意。
        你可以通过删除信息、关闭移动设备对应功能(如使用iOS系统用户可通过“设置”-“XX”App,从而改变或撤回对我们访问你的位置、照片、相机等的授权,
        如android系统用户可通过“设置”-“应用”-“管理权限”-“XX”从而改变或撤回相应授权)、在XXpc端及移动端中进行隐私设置
        (方式:在XXapp“设置”—“推送”,打开或关闭“兴趣精选”)等方式改变你授权同意的范围或撤回你的授权。
        当你收回同意后,我们将不再处理相应的个人信息。但你收回同意的决定,不会影响此前基于你的授权而开展的个人信息处理。\n
        \n
        (五)注销/删除账号\n
        你可以选择注销/删除XX账号,账号被注销/删除后将不可恢复,你的个人信息将被删除或匿名化处理,建议你做好备份。注销/删除后手机号可自动解除绑定,之后可以与其它XX账号绑定。\n
        如果你确定要注销账号,在XXApp中通过「设置」-「注销账号」。
        \n
        (六)获取你的个人信息副本\n
        我们将根据你的书面请求,为你提供以下类型的个人信息副本:\n
        你的个人基本资料、个人身份信息。但请注意,我们为你提供的信息副本仅以我们收集的信息为限。\n
        \n
        (七)约束信息系统自动决策\n
        在某些业务功能中,我们可能仅依据信息系统、算法等在内的非人工自动决策机制做出决定。如果这些决定显著影响你的合法权益,你有权要求我们做出解释,我们也将提供适当的救济方式。\n
        \n
        (八)响应你的上述请求\n
        为保障安全,你可能需要提供书面请求,或以其他方式证明你的身份。我们可能会先要求你验证自己的身份,然后再处理你的请求。\n
        我们将在十五个工作日内做出答复。如你不满意,还可以通过以下途径投诉:发送邮件到liaoxiaoyin@konka.com 。 对于你合理的请求,我们原则上不收取费用,
        但对多次重复、超出合理限度的请求,我们将视情收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、
        给他人合法权益带来风险或者非常不切实际(例如,涉及备份磁带上存放的信息)的请求,我们可能会予以拒绝。\n
        \n
        \n
        在以下情形中,按照法律法规要求,我们将无法响应你的请求:\n
        1、与个人信息控制者履行法律法规规定的义务相关的;\n
        2、与国家安全、国防安全直接相关的;\n
        3、与公共安全、公共卫生、重大公共利益直接相关的;\n
        4、与刑事侦查、起诉、审判和判决执行等直接相关的;\n
        5、有充分证据表明你存在主观恶意或滥用权利的;\n
        6、响应你的请求将导致你或其他个人、组织的合法权益受到严重损害的;\n
        7、出于维护你或其他个人的生命、财产等重大合法权益但又很难得到本人授权同意的;\n
        8、涉及商业秘密的。\n
        \n
        \n
        六、关于儿童的个人信息\n
        \n
        我们的产品与/或服务主要面向成人。如果没有父母或监护人的同意,未成年人不得创建自己的用户账户。对于经父母同意而收集未成年个人信息的情况,我们只会在司法机关或行政机关要求、
        父母或监护人明确同意或者保护未成年人所必要的情况下使用或公开披露此信息。\n
        \n
        尽管当地法律和习俗对未成年人的定义不同,但我们将不满 16 周岁的任何人均视为未成年人。\n
        \n
        如果我们发现在未事先获得可证实的父母同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关数据。\n
        \n
        \n
        七、你的个人信息如何在全球范围转移\n
        \n
        我们在中华人民共和国境内收集和产生的个人信息,将存储在中华人民共和国境内,不会存在个人信息出境之情况。\n
        \n
        \n
        八、本政策如何更新\n
        \n
        我们的隐私政策将不定时更新。\n
        \n
        通常情况下,我们不会削减你按照本隐私政策所应享有的权利。我们会在本页面上发布更新后的版本并且以弹框或与弹框同等显著的方式通知你本政策所做的任何变更,
        你同意后,即表示同意受经修订的本政策的约束。\n
        \n
        我们还会将本政策的旧版本存档,供你查阅。\n
        \n
        \n
        九、如何联系我们\n
        \n
        如果你对本隐私政策有任何疑问、意见或建议,可以通过如下任一方式联系我们:\n
        1、拨打0755-26608866-6663客服电话。\n
        2、发送邮件至liaoxiaoyin@konka.com 与我们个人信息保护负责人联系。\n
        3、除此之外,你还可以将相关函件邮寄至下列地址:深圳市南山区科技南十二路28号康佳研发大厦18楼B 区 软件部(收)。\n
        我们将尽快审核所涉问题,并在验证你的身份后,于15个工作日内进行回复。\n
        \n
        \n
        十、争议解决\n
        \n
        1、如果你认为我们的个人信息处理行为损害了你的合法权益,你可向有关政府部门反映。\n
        2、本隐私政策以及我们处理你个人信息事宜引起的争议,你还可以通过向XX住所地有管辖权的人民法院提起诉讼的方式寻求解决。\n
    </string>

授权访问的实现

授权访问的逻辑:

  1. 每次apk启动运行检查是否已经开启相关授权,如果授权没有开启弹出授权开启提示窗;
  2. 点击开启授权后弹出各个授权(如GPS,摄像头,读取信息等)的弹窗;
  3. 如果一一同意授权后则进入登录界面,如果一一拒绝后弹出再次确认授权的弹窗,进入手机系统授权界面手动授权。

初始化授权访问

在每次apk启动运行,在MainActivity检查是否授权

示例逻辑代码如下:

public class MainActivity extends BaseActivity {

    private LicenseConfigUtil licenseUtil;
    private PrivacyDialog privacyDialog;
    private boolean isFirstEnterApp;
    private boolean isHaveUpdate;
    private String IS_FIRST_ENTER_APP = "is_first_enter_app";
    private String IS_HAVE_UPDATE = "is_have_update";
    private String TAG = MainActivity.class.getSimpleName();

    @Override
    protected int getLayout() {
        return R.layout.activity_main;
    }

    @Override
    protected void initEvent() {
        ...
        checkPrivacyAndPermission();

    }

    private void checkPrivacyAndPermission() {
        isFirstEnterApp = SPUtils.getInstance().getBoolean(IS_FIRST_ENTER_APP, true);
        isHaveUpdate = SPUtils.getInstance().getBoolean(IS_HAVE_UPDATE, false);
        if (isFirstEnterApp || isHaveUpdate) {
            privacyDialog = new PrivacyDialog(this, licenseUtil);
            privacyDialog.initDialog(this);
        } else if (!isFirstEnterApp) {
            licenseUtil.checkPermission();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("MainActivity", " -=-=- onResume: isToSetting:" + ConfirmAuthorityDialog.isToSetting);
        // 在界面从后台重新唤起时,确认是否需要跳转手机系统设置界面开启授权
        if (ConfirmAuthorityDialog.isToSetting) {
            new Thread(() -> {
                try {
                    Log.d("MainActivity", " -=-=- onResume: sleep 1 :");
                    Thread.sleep(100);
                    Log.d("MainActivity", " -=-=- onResume: sleep 2 :");
                    licenseUtil.openWIFI();
                    ConfirmAuthorityDialog.isToSetting = false;
                } catch (Exception e) {
                    Log.e("MainActivity", " -=-=- onResume: sleep error", e);
                }
            }).start();
        }
    }

授权访问工具类

检查授权LicenseUtil的代码如下:

public class LicenseConfigUtil {

    private Activity a;
    private WifiManager wifiManager;
    private static LicenseConfigUtil instance;

    private static String deviceID;
    private static String spDeviceID;

    private LicenseConfigUtil(Activity a) {
        this.a = a;
    }

    public static LicenseConfigUtil getInstance(Activity a) {
        if (instance == null) synchronized (LicenseConfigUtil.class) {
            if (instance == null) instance = new LicenseConfigUtil(a);
        }
        deviceID = GetDeviceId.getDeviceId(a);
        spDeviceID = SPUtils.getInstance().getString(SpConfig.SP_DEVICES_ID, "");
        Log.d("LicenseConfigUtil", " -=-=- getInstance:  deviceID:"
                + deviceID + "  spDeviceID:" + spDeviceID);
        return instance;
    }

	// 检查apk的授权
    public boolean checkPermission() {
        if (TextUtils.isEmpty(deviceID) || TextUtils.isEmpty(spDeviceID)) {
            if (!PermissionUtils.hasDeviceIdPermission(a)) {
                AuthorizationExplainDialog d = new AuthorizationExplainDialog(a);
                d.setOnClickListener(v -> {
                    PermissionUtils.deviceIdPermissionRequest(a);
                    d.dismiss();
                });
                return false;
            } else {
                openWIFI();
                return true;
            }
        } else {
            return true;
        }
    }

    public void showMsg(String msg) {
        new ConfirmAuthorityDialog(a, a, msg);
    }

	// 通过WiFi获取设备的唯一标识符
    public void openWIFI() {
        Log.d("MainActivity", " -=-=- openWIFI: ");
        wifiManager = (WifiManager) ProjectApplication.application.getSystemService(Context.WIFI_SERVICE);
        if (!wifiManager.isWifiEnabled()) initDeviceId(wifiManager.setWifiEnabled(true));
        else initDeviceId(true);
    }

    private void initDeviceId(boolean isOpenWifi) {
        new Thread(() -> {
            try {

                while (!wifiManager.isWifiEnabled() && isOpenWifi) {
                    Thread.sleep(1000);
                    Log.d("MainActivity", " -=-=- initDeviceId: 等待WIFI开启:");
                }

                //获取保存在sd中的 设备唯一标识符
                String readDeviceID = GetDeviceId.readDeviceID(a);
                //获取缓存在  sharepreference 里面的 设备唯一标识
                String string = SPUtils.getInstance().getString(SpConfig.SP_DEVICES_ID, readDeviceID);
                if (string != null) { // 判断 app 内部是否已经缓存,  若已经缓存则使用app 缓存的 设备id
                    //app 缓存的和SD卡中保存的不相同 以app 保存的为准, 同时更新SD卡中保存的 唯一标识符
                    if (TextUtils.isEmpty(readDeviceID) && !string.equals(readDeviceID)) {
                        if (TextUtils.isEmpty(readDeviceID) && !TextUtils.isEmpty(string)) { // 取有效地 app缓存 进行更新操作
                            readDeviceID = string;
                            GetDeviceId.saveDeviceID(readDeviceID, a);
                        }
                    }
                }
                if (TextUtils.isEmpty(readDeviceID)) { // app 没有缓存 (这种情况只会发生在第一次启动的时候)
                    readDeviceID = GetDeviceId.getDeviceId(a); // 保存设备id
                }
                Log.d("MainActivity", " -=-=- initDeviceId: readDeviceID:" + readDeviceID);
                // 左后再次更新app 的缓存
                SPUtils.getInstance().put(SpConfig.SP_DEVICES_ID, readDeviceID);
            } catch (Exception e) {
                Log.e("ProjectApplication", " -=-=- initDeviceId: error", e);
            }
        }).start();
    }

}

/**
	* PermissionUtils的deviceIdPermissionRequest方法具体实现
**/
public static void deviceIdPermissionRequest(Activity a){
        EasyPermissions.requestPermissions(a, "正在请求必要权限,没有权限该应用将无法使用", DEVICE_ID_REQUEST_CODE, deviceIdPermissions);
    }

/**
     * EasyPermissions的requestPermissions方法
     * Request a set of permissions, showing a rationale if the system requests it.
     *
     * @param host        requesting context.
     * @param rationale   a message explaining why the application needs this set of permissions;
     *                    will be displayed if the user rejects the request the first time.
     * @param requestCode request code to track this request, must be &lt; 256.
     * @param perms       a set of permissions to be requested.
     * @see Manifest.permission
     */
    public static void requestPermissions(
            @NonNull Activity host, @NonNull String rationale,
            int requestCode, @Size(min = 1) @NonNull String... perms) {
        requestPermissions(
                new PermissionRequest.Builder(host, requestCode, perms)
                        .setRationale(rationale)
                        .build());
    }

隐私协议&授权访问的示例项目

隐私协议的demo项目:
隐私协议&授权访问的示例项目:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值