Administrator
2021-11-03 2d2f1ee2dd3cc4dc00735fc25d87064adbd10231
app/src/main/java/com/duqing/missions/base/BaseActivity.java
@@ -1,14 +1,61 @@
package com.duqing.missions.base;
import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.ColorRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import androidx.viewbinding.ViewBinding;
import com.duqing.missions.MyApplication;
import com.duqing.missions.R;
import com.duqing.missions.data.ApkUpGradeResult;
import com.duqing.missions.util.MyLog;
import com.duqing.missions.util.ResPonse;
import com.duqing.missions.util.SpUtils;
import com.permissionx.guolindev.PermissionX;
import com.permissionx.guolindev.callback.ExplainReasonCallbackWithBeforeParam;
import com.permissionx.guolindev.callback.ForwardToSettingsCallback;
import com.permissionx.guolindev.callback.RequestCallback;
import com.permissionx.guolindev.request.ExplainScope;
import com.permissionx.guolindev.request.ForwardScope;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
 * Created by Administrator on 2021/10/27 0027.
@@ -16,12 +63,49 @@
public abstract class BaseActivity<B extends ViewBinding> extends AppCompatActivity {
    protected  B binding;
    protected String TAG ;
    public final String[] FILE_PERMISSIONS = new String []{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
    public final String[] LOCATION_PERMISSIONS = new String []{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};
    public final String[] CAMERA_PERMISSIONS = new String[]{ FILE_PERMISSIONS[0],FILE_PERMISSIONS[1], Manifest.permission.CAMERA};
    public final String[] CAMERA_RECORD_PERMISSIONS = new String[]{ FILE_PERMISSIONS[0],FILE_PERMISSIONS[1], Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO};
    public static final int RESULT_LOGIN = 100,RESULT_LOGIN_RECREATE = 103,RESULT_BIND = 101,RESULT_SENDEDFILES = 105,RESULT_DISSCONNECT = 104,
            RESULT_UPDATEUSER =  115,RESULT_LOGOUT = 113, REQUEST_CODE_ACTIVITY = 333;
    public static final int REQUEST_CODE_LOGOUT = 20009,/*退出*/
            REQUEST_CODE_ORDER = 10010,/*订单详情*/
            REQUEST_CODE_LOGIN = 20010,/*登录*/
            REQUEST_CODE_SCAN = 20011/*扫描请求*/,
            REQUEST_CODE_PIC = 20012,/*选择图片*/
            REQUEST_CODE_PAYPASS = 20112,/*支付验证*/
            REQUEST_CODE_PAYPASS_FOR_ALIPAY = 20110,/*支付宝修改支付验证*/
            REQUEST_CODE_PAYPASS_FOR_REALNAME = 20111,/*支付宝修改支付验证*/
            REQUEST_CODE_PERMISSION = 20013,/*请求权限*/
            REQUEST_VERSION_PERMISSION = 20013,/*检查更新*/
            REQUEST_INSTALL_PERMISSION = 20014,/*请求安装权限*/
            REQUEST_CODE_MANAGE_GROUP = 20015,/*选择分组*/
            REQUEST_CODE_MANAGE_DEL = 20016,/*选择删除*/
            REQUEST_CODE_MANAGE_EDIT = 20017,/*选择编辑*/
            REQUEST_CODE_MANAGE_ADD = 20018,/*选择添加*/
            REQUEST_CODE_MANAGE_DRAFT = 20019,/*选择草稿编辑*/
            REQUEST_CODE_WEPAY = 20020,/*微信支付*/
            REQUEST_CODE_ALIPAY = 20021,/*支付宝*/
            REQUEST_CODE_PINKAGE = 20022,/*包邮设置*/
            REQUEST_INSTALL_APK = 20200,/*请求安装权限*/
            REQUEST_CODE_COMMENT_REFRESH = 20222,/*请求安装权限*/
            RESULT_CODE_DRAFT = 4041/*草稿*/,
            RESULT_CODE_UPDATED = 4042/*更新*/,
            RESULT_CODE_FAILD = 4044/*失败*/,
            RESULT_CODE_SUCESS = 4046/*成功*/,
            RESULT_CODE_CANCEL = 4043/*取消*/;
    protected Context mContext;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // get genericity "B"
        setStatusBarBgColor(R.color.white);
        setStatusBarTextColor(true);
        Class<B> entityClass = (Class<B>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        try {
            Method method = entityClass.getMethod("inflate", LayoutInflater.class);//get method from name "inflate";
@@ -30,5 +114,398 @@
            e.printStackTrace();
        }
        setContentView(binding.getRoot());
        mContext = this;
        try {
            //设置坚屏 一定要放到try catch里面,否则会崩溃
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } catch (Exception e) {
        }
        TAG = this.getClass().getSimpleName();
        initViews();
    }
    public abstract void initViews();
    public void setStatusBarTransparent(boolean isBlack){
        //透明状态栏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        //透明导航栏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    }
    /**
     * 修改状态栏颜色,支持4.4以上版本
     * @param colorId
     */
    public void setStatusBarBgColor(@ColorRes int colorId) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        getWindow().setStatusBarColor(getResources().getColor(colorId));
    }
    /**
     * 修改状态栏文本颜色
     * @param isBlack
     */
    public void setStatusBarTextColor(boolean isBlack){
        View decor = getWindow().getDecorView();
        if (isBlack) {
            decor.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        } else {
            decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        }
    }
    /**
     * 隐藏虚拟按键
     */
    public void hideBottomUIMenu() {
        //隐藏虚拟按键
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView = getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY  ;
            decorView.setSystemUiVisibility(uiOptions);
        }
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {  //把操作放在用户点击的时候
            View v = getCurrentFocus();      //得到当前页面的焦点,ps:有输入框的页面焦点一般会被输入框占据
            if (isShouldHideKeyboard(v, ev)) { //判断用户点击的是否是输入框以外的区域
                hideSoftKeyboard ();   //收起键盘
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    /**
     * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {  //判断得到的焦点控件是否包含EditText
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],    //得到输入框在屏幕中上下左右的位置
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击位置如果是EditText的区域,忽略它,不收起键盘。
                return false;
            } else {
                return true;
            }
        }
        // 如果焦点不是EditText则忽略
        return false;
    }
    /**
     * 判断软键盘输入法是否弹出
     */
    public boolean isKeyboardVisbility(Context context, View v) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(context.INPUT_METHOD_SERVICE);
        if (imm.hideSoftInputFromWindow(v.getWindowToken(), 0)) {
            imm.showSoftInput(v, 0);
            return true;//键盘显示中
        } else {
            return false;//键盘未显示
        }
    }
    protected void hideSoftKeyboard() {
        if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
            if (getCurrentFocus() != null)
                ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }
    /**
     * 状态栏高度
     * @return
     */
    public int getStatusBarHeight() {
        int result = 0;
        int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resId > 0) {
            result = getResources().getDimensionPixelOffset(resId);
        }
        return result;
    }
    long mExitTime= 0 ;
    /**
     * 返回键退出程序
     */
    public void backExit() {
        if ((System.currentTimeMillis() - mExitTime) > 2000) {
            Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
            mExitTime = System.currentTimeMillis();
        } else {
            //此方法导致app关闭后重启
            MyApplication.getApplication().quitApp();
            System.exit(0);
            //quitApp();
        }
    }
    public void showToast(String message){
        Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
    }
    public void showToast(@StringRes int msg){
        showToast(getString(msg));
    }
    ApkUpGradeResult.AppInfo apkUpGrade;
    ProgressDialog progressDialog ;
    public void showUpdateDialog(){
        if(apkUpGrade == null){
            return;
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("新版本").setMessage("有新版更新\n"+apkUpGrade.content)
            .setPositiveButton("", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    okHttpDownload(apkUpGrade.url, new ResPonse<String>() {
                        @Override
                        public void doSuccess(String path) {
                            apkUpGrade.remark = path;
                            openAPK(new File(path));
                        }
                        @Override
                        public void doError(String path) {
                            if(apkUpGrade.isImportant==1){
                                showUpdateDialog();
                            }else {
                                if(path != null) {
                                    apkUpGrade.remark = path;
                                    openAPK(new File(path));
                                }
                            }
                        }
                    });
                }
            })
            .setNegativeButton(apkUpGrade.isImportant==1?"退出":"取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if(apkUpGrade.isImportant==1){
                        MyApplication.getApplication().quitApp();
                    }else {
                        SpUtils.getInstance().putLongValOfProject(mContext,"version", new Date().getTime());//记录今天已经请求过更新  不在自动请求
                    }
                }
            });
    }
    /**
     * okhttp下载文件
     * @param downloadUrl
     * @param resPonse
     */
    protected void okHttpDownload(final String downloadUrl, final ResPonse<String> resPonse){
        PermissionX.init(this).permissions(FILE_PERMISSIONS).onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam() {
            @Override
            public void onExplainReason(ExplainScope scope, List<String> deniedList, boolean beforeRequest) {
                scope.showRequestReasonDialog(deniedList, "即将申请的权限是程序必须依赖的权限", "继续申请","我已明白");
            }
        }).onForwardToSettings(new ForwardToSettingsCallback() {
            @Override
            public void onForwardToSettings(ForwardScope scope, List<String> deniedList) {
                scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置当中手动开启权限", "去设置","我已明白");
            }
        }).request(new RequestCallback() {
            @Override
            public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList) {
                if(allGranted){
                    OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
                    Request request = new Request.Builder()
                            .url(downloadUrl)
                            .get()
                            .build();
                    okHttpClient.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
                            Log.e("tag", "onFailure: " + e.getMessage());
                        }
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            ResponseBody body = response.body();        // 获取到请求体
                            InputStream inputStream = body.byteStream();    // 转换成字节流
                            progressDialog = new ProgressDialog(mContext);
                            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                            progressDialog.setTitle("正在下载...");
                            progressDialog.setCancelable(false);
                            progressDialog.show();
                            saveFile(inputStream, getSaveFilePath(downloadUrl), body.contentLength(),resPonse);
                        }
                    });
                } else {
                    Toast.makeText(mContext, "您拒绝了权限申请!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
    /**
     * @param inputStream
     * @param filePath           存放的地址
     * @param l           文件的长度
     */
    private void saveFile(InputStream inputStream, final String filePath, final long l, final ResPonse<String> resPonse) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressDialog.setMax((int)l);// 设置进度条最大值
            }
        });
        long count = 0;
        try {
            File file = new File(filePath);
            Log.i(TAG, "文件保存路径:" + filePath+" 文件是否存在:"+file.exists());
            if (!file.exists()) {//文件不存在
                file.createNewFile();
            }else{
                file.delete();
            }
            // 获取到输出流,写入到的地址
            FileOutputStream outputStream = new FileOutputStream(file);
            int length = -1;
            byte[] bytes = new byte[1024 * 10];
            while ((length = inputStream.read(bytes)) != -1) {
                // 写入文件
                outputStream.write(bytes, 0, length);
                count += length;
                final long finalCount = count;
                final int finalLenght = length;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressDialog.setProgress((int) finalCount);     // 设置进度
                    }
                });
            }
            inputStream.close();        // 关闭输入流
            outputStream.close();       // 关闭输出流
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // 如果写入的进度值完毕,Toast
                    progressDialog.dismiss();
                    resPonse.doSuccess(filePath);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取文件保存路径 sdcard根目录/download/文件名称
     * @param fileUrl
     * @return
     */
    public static String getSaveFilePath(String fileUrl){
        String fileName=fileUrl.substring(fileUrl.lastIndexOf("/")+1,fileUrl.length());//获取文件名称
        String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Download";
        File appDir = new File(storePath);
        if (!appDir.exists()) {
            appDir.mkdirs();
        }
        return storePath + File.separator +fileName;
    }
    /**
     * 打开apk文件
     * @param file
     */
    public void openAPK(final File file){
        //android 8及以上需要设置权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !getPackageManager().canRequestPackageInstalls()) {
            // 申请安装权限。
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("需要允许安装权限").setMessage("应用需要手动设置,才能打开安装包升级应用").setCancelable(false)
                    .setNegativeButton("", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Uri packageUri = Uri.parse("package:" + getPackageName());
                            Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageUri);
                            startActivityForResult(intent, REQUEST_INSTALL_PERMISSION);
                            dialog.dismiss();
                        }
                    })
                    .setPositiveButton(apkUpGrade.isImportant==1?"退出":"取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if(apkUpGrade.isImportant==1){
                                MyApplication.getApplication().quitApp();
                            }
                        }
                    }).create().show();
            return;
        }
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        Uri photoURI = null ;
        if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) { //判读版本是否在7.0以上
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            photoURI = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", file);//添加这一句表示对目标应用临时授权该Uri所代表的文件
        }else{
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            photoURI = Uri.fromFile(file);
        }
        intent.setDataAndType(photoURI,"application/vnd.android.package-archive");
        startActivityForResult(intent,REQUEST_INSTALL_APK);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        MyLog.i(TAG,String.format("onActivityResult requestCode:%s, resultCode:%s, data:%s",requestCode, resultCode, data));
        if(requestCode == REQUEST_INSTALL_PERMISSION){
            openAPK(new File(apkUpGrade.remark));
        }else if(requestCode == REQUEST_INSTALL_APK && apkUpGrade.isImportant==1){
            /*showDialog("强制更新", "需要安装新版本才能继续使用","安装","退出", new ResPonse() {
                @Override
                public void doSuccess(Object obj) {
                }
                @Override
                public void doError(Object obj) {
                    super.doError(obj);
                }
            });*/
        }
    }
    protected boolean onBackKeyDown() {
        onBackPressed();
        return false;
    }
}