public class AppModel extends BaseModel {

    public interface UpdateCheckCallback {
        void onSuccess(UpdateInfo updateInfo);

        void onFailure(String msg);
    }

    public static void checkUpdate(Context context, AppModel.UpdateCheckCallback callback) {
        final String currentVersion = context.getResources().getString(R.string.current_version);

        HttpUtil.load(URLs.UPDATE_URL)
                .addParam("version2", currentVersion)
                .post(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        mHandler.post(() -> callback.onFailure("连接更新服务器失败。"));
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        UpdateInfo updateInfo;
                        try {
                            updateInfo = new Gson().fromJson(response.body().string(), UpdateInfo.class);
                            updateInfo.setCurrentVersion(currentVersion);
                        } catch (JsonSyntaxException e) {
                            e.printStackTrace();
                            callback.onFailure("服务器错误。");
                            return;
                        }

                        if (updateInfo != null) {
                            mHandler.post(() -> callback.onSuccess(updateInfo));
                        } else {
                            mHandler.post(() -> callback.onFailure("检查更新异常。"));
                        }
                    }
                });
    }
} public class BaseModel {

    protected static final String TAG = "";

    static final String CONNECT_FAILED = "网络连接失败。";
    static final String RETURN_DATA_ERROR = "服务器数据出错。";

    static Handler mHandler = new Handler(Looper.getMainLooper());

    public interface BaseCallback {
        void onFailure(String msg);

        void onSuccess();
    }

    /**
     * 检查服务器返回为true还是false
     */
    private static void checkStatusResponse(Response response, BaseCallback callback) throws IOException {
        String result = response.body().string();
        Log.d(TAG, "checkStatusResponse: " + result);
        mHandler.post(() -> {
            if (result.equals("true")) {
                callback.onSuccess();
            } else {
                callback.onFailure(RETURN_DATA_ERROR);
            }
        });
    }

    private static void checkJsonStatusResponse(Response response, BaseCallback callback) throws IOException {
        String jsonStr = response.body().string();
        Log.d(TAG, "checkJsonStatusResponse: " + jsonStr);

        mHandler.post(() -> {
            Status status = null;
            try {
                status = new Gson().fromJson(jsonStr, Status.class);
                if (status.getResult()) {
                    callback.onSuccess();
                } else {
                    callback.onFailure(status.getMessage());
                }
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                callback.onFailure(RETURN_DATA_ERROR);
            }
        });
    }

    static Callback getStatusHttpCallback(BaseCallback callback) {
        return new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                mHandler.post(() -> callback.onFailure(CONNECT_FAILED));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                checkStatusResponse(response, callback);
            }
        };
    }

    static Callback getJsonStatusHttpCallback(BaseCallback callback) {
        return new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                mHandler.post(() -> callback.onFailure(CONNECT_FAILED));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                checkJsonStatusResponse(response, callback);
            }
        };
    }
} public class RunningModel extends BaseModel {
    public interface GetTimesCallback {
        void onFailure(String msg);

        void onSuccess(int serverTimes, int localTimes);
    }

    public interface GetRunningInfoCallback {
        void onFailure(String msg);

        void onSuccess(Running running);
    }

    /**
     * 获取服务器上的跑步次数和本地跑步次数
     */
    public static void getRunningTimes(String username, GetTimesCallback callback) {
        HttpUtil.load(URLs.GET_RUN_TIMES)
                .addParam("userName", username)
                .post(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        mHandler.post(() -> callback.onFailure(CONNECT_FAILED));
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        String result = response.body().string();
                        mHandler.post(() -> {
                            int serverTimes;
                            try {
                                serverTimes = Integer.parseInt(result);
                            } catch (NumberFormatException e) {
                                callback.onFailure(RETURN_DATA_ERROR);
                                e.printStackTrace();
                                return;
                            }
                            int localTimes = DataSupport.count(RunningInfo.class);
                            int finalServerTimes = serverTimes;
                            callback.onSuccess(finalServerTimes, localTimes);
                        });
                    }
                });
    }

    public static void getRunningInfo(String username, GetRunningInfoCallback callback) {
        HttpUtil.load(URLs.GET_RUN_INFO)
                .addParam("userName", username)
                .post(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        mHandler.post(() -> callback.onFailure("网络连接失败。"));
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        String result = response.body().string();
                        mHandler.post(() -> {
                            Running running = null;
                            try {
                                running = new Gson().fromJson(result, Running.class);
                                callback.onSuccess(running);
                            } catch (JsonSyntaxException e) {
                                callback.onFailure(RETURN_DATA_ERROR);
                                e.printStackTrace();
                            }
                        });
                    }
                });
    }

    public static void uploadAll(String username, BaseCallback callback) {
        Running running = new Running();
        running.username = username;
        List<RunningInfo> infoList = RunningQueryUtil.findAllOrder();
        running.times = infoList.size();
        running.dataList = infoList;
        String json = new Gson().toJson(running);
        Log.d(TAG, json);
        HttpUtil.load(URLs.UPLOAD_ALL_INFO)
                .addParam("json", json)
                .post(getStatusHttpCallback(callback));
    }

    public static void upload(String username, RunningInfo runningInfo, BaseCallback callback) {
        HttpUtil.load(URLs.UPLOAD_RUN_INFO)
                .addParam("userName", username)
                .addParam("runId", runningInfo.getRunId())
                .addParam("runMode", runningInfo.getRunMode())
                .addParam("year", runningInfo.getYear())
                .addParam("month", runningInfo.getMonth())
                .addParam("date", runningInfo.getDate())
                .addParam("startTime", runningInfo.getStartTime())
                .addParam("duration", runningInfo.getDuration())
                .addParam("steps", String.valueOf(runningInfo.getSteps()))
                .addParam("distance", String.valueOf(runningInfo.getDistance()))
                .addParam("energy", String.valueOf(runningInfo.getEnergy()))
                .addParam("speed", String.valueOf(runningInfo.getSpeed()))
                .addParam("trailList", runningInfo.getCompressedTrailList())
                .post(getStatusHttpCallback(callback));
    }

    public static void delete(String username, String deleteId, BaseCallback callback) {
        HttpUtil.load(URLs.DELETE_ITEM)
                .addParam("userName", username)
                .addParam("runId", deleteId)
                .post(getStatusHttpCallback(callback));
    }

    public static void deleteAll(String username, BaseCallback callback) {
        HttpUtil.load(URLs.CLEAR_DATA)
                .addParam("userName", username)
                .post(getStatusHttpCallback(callback));
    }
} public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    private List<String> title;
    private List<Fragment> views;

    public MyFragmentPagerAdapter(FragmentManager fm, List<String> title, List<Fragment> views) {
        super(fm);
        this.title = title;
        this.views = views;
    }

    @Override
    public Fragment getItem(int position) {
        return views.get(position);
    }

    @Override
    public int getCount() {
        return views.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return title.get(position);
    }
} public class Types {
    public final static int TYPE_YEAR = 1000;
    public final static int TYPE_MONTH = 1001;
    public final static int TYPE_DATE = 1002;
    public final static int TYPE_HOUR = 1003;
    public final static int TYPE_MINUTE = 1004;
    public final static int TYPE_SECOND = 1005;
    public final static int TYPE_MONTH_DATE = 1006;
    public final static int TYPE_CURRENT_TIME = 1007;
    public final static int TYPE_AM_PM = 1008;
    public final static int TYPE_CHANGE_PROFILE = 1009;
    public final static int TYPE_CHANGE_MENU_BG = 1010;
    public final static int MANUAL_UPDATE = 1011;
    public final static int AUTO_UPDATE = 1012;
    public final static int TYPE_SAVE_PROFILE = 1013;
    public final static int TYPE_STRING_FORM=1014;
} public class URLs {
    public static final String DOWNLOAD = "http://d1.51gugu.com/170258/RunHDU";
    public static final String LOGIN = "http://112.74.115.231:8080/CXSJ/Login";
    public static final String REGISTER="http://112.74.115.231:8080/CXSJ/Register";
    public static final String GET_RUN_INFO = "http://112.74.115.231:8080/chuangxinshijian/ReadAll";
    public static final String UPLOAD_RUN_INFO = "http://112.74.115.231:8080/chuangxinshijian/Write";
    public static final String CLEAR_DATA = "http://112.74.115.231:8080/chuangxinshijian/ClearTheTable";
    public static final String UPDATE_URL = "http://112.74.115.231:8080/chuangxinshijian/VersionCompare";
    public static final String GET_RUN_TIMES = "http://112.74.115.231:8080/chuangxinshijian/ReadUserNameAndTimesOnly";
    public static final String UPLOAD_ALL_INFO = "http://112.74.115.231:8080/chuangxinshijian/WriteByJson";
    public static final String UPLOAD_PROFILE = "http://112.74.115.231:8080/CXSJ/UploadHead";
    public static final String PROFILE_URL = "http://112.74.115.231:8080/CXSJ/Image/";
    public static final String FEEDBACK_URL = "http://112.74.115.231:8080/chuangxinshijian/WriteFeedback";
    public static final String SUNNY_RUN_QUERY_API = "http://hdu.sunnysport.org.cn/api/student/achievements/";
    public static final String SUNNY_RUN_INFO_API = "http://hdu.sunnysport.org.cn/api/student/info/";
    public static final String DELETE_ITEM = "http://112.74.115.231:8080/chuangxinshijian/ClearByUserNameAndRunId";
    public static final String APPLY_FRIEND = "http://112.74.115.231:8080/CXSJ/Apply";
    public static final String REPLY_FRIEND = "http://112.74.115.231:8080/CXSJ/BeFriend";
    public static final String GET_FRIEND = "http://112.74.115.231:8080/CXSJ/MyFriends";
    public static final String DELETE_FRIEND = "http://112.74.115.231:8080/CXSJ/DeleteFriend";
    public static final String OFF_LINE = "http://112.74.115.231:8080/CXSJ/Xiaxian";
} public class DataQueryModel {
    public interface RunningInfoCallback {
        void onDataPrepare(int steps, int times, int dis, int energy);
    }

    public interface StatisticsCallback {
        void onDataPrepare(int allSteps, int allEnergy, double allDis,
                           double averSteps, double averEnergy, double averDis,
                           int allTimes, double averTimes, double allTime);
    }

    /**
     * 获取某个日期跑步数据
     */
    public static void getRunningInfo(Calendar calendar, RunningInfoCallback callback) {
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        String month = String.valueOf(calendar.get(Calendar.MONTH) + 1);
        String day = String.valueOf(calendar.get(Calendar.DATE));

        List<RunningInfo> runningInfoList = RunningQueryUtil.findOrder(
                "year = ? and month = ? and date = ?",
                year, month, day);
        int steps = 0;
        int times = 0;
        int dis = 0;
        int energy = 0;
        for (RunningInfo info : runningInfoList) {
            steps += info.getSteps();
            times++;
            dis += info.getDistance();
            energy += info.getEnergy();
        }
        callback.onDataPrepare(steps, times, dis, energy);
    }

    /**
     * 设置柱状图数据
     *
     * @param chartColumnNum 柱状图显示天数
     */
    public static ColumnChartData getColumnChartData(int chartColumnNum) {
        List<String> chartLabels = new ArrayList<>();
        List<Float> chartValues = new ArrayList<>();
        //初始化ColumnChart
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd", Locale.CHINA);
        for (int i = 0; i < chartColumnNum; i++) {
            chartLabels.add(sdf.format(c.getTime()));
            List<RunningInfo> runningInfoList = RunningQueryUtil.findOrder(
                    "year = ? and month = ? and date = ?",
                    String.valueOf(c.get(Calendar.YEAR)),
                    String.valueOf(c.get(Calendar.MONTH) + 1),
                    String.valueOf(c.get(Calendar.DATE)));
            int steps = 0;
            for (RunningInfo info : runningInfoList) {
                steps += info.getSteps();
            }
            chartValues.add((float) steps);
            c.add(Calendar.DATE, -1);
        }
        Collections.reverse(chartLabels);
        Collections.reverse(chartValues);

        if (chartLabels.size() != chartValues.size()
                || chartLabels.isEmpty()
                || chartValues.isEmpty()) {
            return null;
        }

        ColumnChartData data;
        // 列，每列1个柱状图。
        int numSubcolumns = 1;
        int numColumns = chartLabels.size();
        //圆柱对象集合
        List<Column> columns = new ArrayList<>();
        //子列数据集合
        List<SubcolumnValue> values;
        List<AxisValue> axisValues = new ArrayList<>();
        //遍历列数numColumns
        for (int i = 0; i < numColumns; ++i) {
            values = new ArrayList<>();
            //遍历每一列的每一个子列
            for (int j = 0; j < numSubcolumns; ++j) {
                //为每一柱图添加颜色和数值
                values.add(new SubcolumnValue(chartValues.get(i), Color.parseColor("#03A9F4")));
            }
            //创建Column对象
            Column column = new Column(values);
            //是否有数据标注
            column.setHasLabels(true);
            //是否是点击圆柱才显示数据标注
            column.setHasLabelsOnlyForSelected(false);
            columns.add(column);
            //给x轴坐标设置描述
            axisValues.add(new AxisValue(i).setLabel(chartLabels.get(i)));
        }
        //创建一个带有之前圆柱对象column集合的ColumnChartData
        data = new ColumnChartData(columns);

        //定义x轴y轴相应参数
        Axis axisX = new Axis();
        axisX.setTextColor(Color.parseColor("#ffffff"));
        axisX.setValues(axisValues);
        //把X轴Y轴数据设置到ColumnChartData 对象中
        data.setAxisXBottom(axisX);
        return data;
    }

    /**
     * 获取跑步详情列表
     */
    public static List<RunningInfoSection> getSectionList(List<RunningInfo> list) {
        List<RunningInfoSection> runningInfoSectionList = new ArrayList<>();
        if (list.isEmpty()) {
            return null;
        }
        String oldYear = list.get(0).getYear();
        String oldMonth = list.get(0).getMonth();
        int times = 0;
        List<RunningInfo> tempList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            RunningInfo info = list.get(i);
            String year = info.getYear();
            String month = info.getMonth();

            if (year.equals(oldYear) && month.equals(oldMonth)) {
                times++;
                tempList.add(info);
            } else {
                RunningInfoSection section = new RunningInfoSection(true, oldYear + "年" + oldMonth + "月");
                section.setTimes(String.valueOf(times));

                if (tempList != null) {
                    for (RunningInfo inf : tempList) {
                        RunningInfoSection s = new RunningInfoSection(inf);
                        runningInfoSectionList.add(s);
                    }
                }

                runningInfoSectionList.add(section);
                oldYear = year;
                oldMonth = month;
                times = 1;
                tempList = new ArrayList<>();
                tempList.add(info);
            }
            if (i == list.size() - 1) {
                RunningInfoSection section = new RunningInfoSection(true, oldYear + "年" + oldMonth + "月");
                section.setTimes(String.valueOf(times));
                if (tempList != null) {
                    for (RunningInfo inf : tempList) {
                        RunningInfoSection s = new RunningInfoSection(inf);
                        runningInfoSectionList.add(s);
                    }
                }
                runningInfoSectionList.add(section);
            }
        }
        Collections.reverse(runningInfoSectionList);
        return runningInfoSectionList;
    }

    /**
     * 设置统计数据
     */
    public static void setStatisticsData(StatisticsCallback callback) {
        int allStepsNum = DataSupport.sum(RunningInfo.class, "steps", int.class);
        int allEnergyNum = DataSupport.sum(RunningInfo.class, "energy", int.class);
        double allDisNum = DataSupport.sum(RunningInfo.class, "distance", int.class);
        double averStepsNum = DataSupport.average(RunningInfo.class, "steps");
        double averEnergyNum = DataSupport.average(RunningInfo.class, "energy");
        double averDisNum = DataSupport.average(RunningInfo.class, "distance");
        int allTimesNum = DataSupport.count(RunningInfo.class);
        double averTimesNum = 0;
        double allTimeNum = 0;

        List<RunningInfo> list = RunningQueryUtil.findAllOrder();
        String oldDate = null;
        int runDays = 0;
        for (RunningInfo info : list) {
            String date = info.getDate();
            if (!date.equals(oldDate)) runDays++;
            oldDate = date;
            allTimeNum += Utility.getMinutes(info.getDuration());

        }

        if (runDays != 0) {
            averTimesNum = (double) allTimesNum / runDays;
        }

        callback.onDataPrepare(allStepsNum, allEnergyNum, allDisNum,
                averStepsNum, averEnergyNum, averDisNum,
                allTimesNum, averTimesNum, allTimeNum);
    }
} public class Running {
    @SerializedName("userName")
    public String username;
    public int times;
    public List<RunningInfo> dataList;
} public class UpdateInfo {
    private boolean isUpdate;
    private String latestVersion;
    private String currentVersion;
    private String statement;

    public boolean isUpdate() {
        return isUpdate;
    }

    public void setUpdate(boolean update) {
        isUpdate = update;
    }

    public String getLatestVersion() {
        return latestVersion;
    }

    public void setLatestVersion(String latestVersion) {
        this.latestVersion = latestVersion;
    }

    public String getCurrentVersion() {
        return currentVersion;
    }

    public void setCurrentVersion(String currentVersion) {
        this.currentVersion = currentVersion;
    }

    public String getStatement() {
        return statement;
    }

    public void setStatement(String statement) {
        this.statement = statement;
    }
} public class RunningInfo extends DataSupport implements Serializable {


    private String runId;

    private String runMode;

    private String year;

    private String month;

    private String date;

    private String startTime;

    private String duration;

    private int steps;

    private int distance;

    private int energy;

    private float speed;

    private String trailList;

    public RunningInfo() {
    }

    public RunningInfo(String runId,
                       String runMode,
                       String year,
                       String month,
                       String date,
                       String startTime,
                       String duration,
                       int steps,
                       int distance,
                       int energy,
                       float speed,
                       String trailList) {
        this.runId = runId;
        this.runMode = runMode;
        this.year = year;
        this.month = month;
        this.date = date;
        this.startTime = startTime;
        this.duration = duration;
        this.steps = steps;
        this.distance = distance;
        this.energy = energy;
        this.speed = speed;
        this.trailList = ZipUtil.compress(trailList);
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getStartTime() {
        return startTime;
    }

    public void setStartTime(String startTime) {
        this.startTime = startTime;
    }

    public String getDuration() {
        return duration;
    }

    public void setDuration(String duration) {
        this.duration = duration;
    }

    public int getSteps() {
        return steps;
    }

    public void setSteps(int steps) {
        this.steps = steps;
    }

    public int getDistance() {
        return distance;
    }

    public void setDistance(int distance) {
        this.distance = distance;
    }

    public int getEnergy() {
        return energy;
    }

    public void setEnergy(int energy) {
        this.energy = energy;
    }

    public float getSpeed() {
        return speed;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

    public String getTrailList() {
        return ZipUtil.decompress(trailList);
    }

    public String getCompressedTrailList() {
        return trailList;
    }

    public void setTrailList(String trailList) {
        this.trailList = ZipUtil.compress(trailList);
    }

    public String getRunId() {
        return runId;
    }

    public void setRunId(String runId) {
        this.runId = runId;
    }

    public String getRunMode() {
        return runMode;
    }

    public void setRunMode(String runMode) {
        this.runMode = runMode;
    }
} public class ActivityManager {

    private static String TAG = "ActivityManager";
    private static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity) {
        Log.d(TAG, "addActivity: "+activity.getLocalClassName());
        activities.add(activity);
    }

    public static void removeActivity(Activity activity) {
        if (activity != null) {
            Log.d(TAG, "removeActivity: "+activity.getLocalClassName());
            activities.remove(activity);
        }
    }

    public static void finishAll() {
        for (Activity activity : activities) {
            if (activity != null) {
                Log.d(TAG, "finishAll: " + activity.getLocalClassName());
                activity.finish();
            }
        }
    }
} public class HttpUtil {
    private static RequestManager manager;

    public static RequestManager load(String url) {
        manager = new RequestManager();
        manager.url(url);
        return manager;
    }

    public static class RequestManager {
        private Request.Builder requestBuilder = new Request.Builder();
        private FormBody.Builder formBuilder = new FormBody.Builder();
        private Call call;

        private void url(String url) {
            formBuilder = new FormBody.Builder();
            requestBuilder = new Request.Builder();

            requestBuilder = requestBuilder.url(url);
        }

        private void cancel() {
            if (call != null) {
                call.cancel();
            }
        }

        public RequestManager addHeader(String key, String value) {
            requestBuilder.addHeader(key, value);
            return this;
        }

        public RequestManager addParam(String key, String value) {
            formBuilder = formBuilder.add(key, value);
            return this;
        }

        public void post(Callback callback) {
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(3, TimeUnit.SECONDS)
                    .followRedirects(false)
                    .followSslRedirects(false)
                    .build();

            Request request = requestBuilder.post(formBuilder.build()).build();
            client.newCall(request).enqueue(callback);
        }

        public void get(Callback callback) {
            OkHttpClient client = new OkHttpClient.Builder().build();
            Request request = requestBuilder.build();
            call = client.newCall(request);
            call.enqueue(callback);
        }
    }
} public class ImageUtil {
    /**
     * 保存图片到相册。
     *
     * @param context  上下文
     * @param bitmap
     * @param fileName 保存的路径
     */
    public static String saveToSDCard(Context context, Bitmap bitmap, String fileName) {
        FileOutputStream fos;
        String saveDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
                + fileName;
        try {
            fos = new FileOutputStream(saveDir);
            if (null != fos) {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
                fos.flush();
                fos.close();
                return saveDir;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存图片至服务器
     *
     * @param username
     * @param bitmap
     */
    public static void saveToServer(String username, Bitmap bitmap) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
        byte[] imgArray = bos.toByteArray();
        String imgStr = Base64.encodeToString(imgArray, Base64.DEFAULT);
        HttpUtil.load(URLs.UPLOAD_PROFILE)
                .addParam("UserName", username)
                .addParam("Image", imgStr)
                .post(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                    }
                });
    }

    /**
     * 对Activity截图
     *
     * @param activity
     * @return Bitmap对象。
     */
    public static Bitmap takeScreenShot(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b1 = view.getDrawingCache();
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
        int width = activity.getWindowManager().getDefaultDisplay().getWidth();
        int height = activity.getWindowManager().getDefaultDisplay()
                .getHeight();
        Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);
        view.destroyDrawingCache();
        return b;
    }

    public static Bitmap takeScreenShot(View view) {
        view.setDrawingCacheEnabled(true);
        Bitmap tBitmap = view.getDrawingCache();
        tBitmap = Bitmap.createBitmap(tBitmap);
        view.setDrawingCacheEnabled(false);
        if (tBitmap != null) {
            return tBitmap;
        } else {
            return null;
        }
    }

    public static void openPhotoChooser(Activity activity, int resultCode) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");//相片类型
        activity.startActivityForResult(intent, resultCode);
    }

    public static void openPhotoCutter(Activity activity, Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 192);
        intent.putExtra("outputY", 192);
        intent.putExtra("return-data", true);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        activity.startActivityForResult(intent, Types.TYPE_SAVE_PROFILE);
    }
} public class RunningQueryUtil {
    /**
     * 普通查找
     * @param conditions 查找条件
     * @return
     */
    public static List<RunningInfo> find(String... conditions) {
        return DataSupport.where(conditions).find(RunningInfo.class);
    }

    /**
     * 按跑步时间排序查找
     * @param conditions 查找条件
     * @return
     */
    public static List<RunningInfo> findOrder(String... conditions) {
        return DataSupport.where(conditions).order("runId").find(RunningInfo.class);
    }

    /**
     * 按跑步时间跑需，查找所有
     * @return
     */
    public static List<RunningInfo> findAllOrder() {
        return DataSupport.order("runId").find(RunningInfo.class);
    }
} public class ShareUtil {

    private static int delayTime = 0;

    public static void setDelay(int time) {
        delayTime = time;
    }

    public static void shareImg(Activity activity, String imagePath) {
        Intent intent = new Intent(Intent.ACTION_SEND);
        File file = new File(imagePath);
        intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
        intent.setType("image/jpeg");
        Intent chooser = Intent.createChooser(intent, "分享运动数据");
        if (intent.resolveActivity(activity.getPackageManager()) != null) {
            activity.startActivity(chooser);
        }
    }

    public static void shareText(Context context, String content) {
        if (TextUtils.isEmpty(content)) {
            Toast.makeText(context, "文字为空。", Toast.LENGTH_SHORT).show();
        }
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_TEXT, content);
        intent.setType("text/plain");
        Intent chooser = Intent.createChooser(intent, content);
        context.startActivity(chooser);
    }
} public class Utility {
    /**
     * GPS是否打开
     *
     * @param context
     * @return GPS开启状态
     */
    public static boolean isGPSOpen(Context context) {
        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean result = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        return result;
    }

    /**
     * 位置集合里每连续两点距离的总和
     *
     * @param points 位置集合
     * @return 距离总和
     */
    public static int getRunningDistance(List<LatLng> points) {
        if (points.size() == 0 || points.size() == 1) return 0;
        double result = 0.0;
        for (int i = 0; i < points.size() - 1; i++) {
            result += DistanceUtil.getDistance(points.get(i), points.get(i + 1));
        }
        return (int) result;
    }


    /**
     * 是否有网络
     *
     * @param context
     * @return 网络是否可用
     */
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                // 当前网络是连接的
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    // 当前所连接的网络可用
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param d   需要处理的数字
     * @param num 保留位数(只能是1或者2)
     * @return 保留num位小数后的字符串
     */
    public static String formatDecimal(double d, int num) {
        if (num == 2) {
            return String.format("%.2f", d);
        } else {
            return String.format("%.1f", d);
        }

    }

    /**
     * 获取特定类型的时间的字符串表示
     *
     * @param type 获取的时间类型，
     *             Types.TYPE_AM_PM：返回上午/下午/晚上
     *             Types.TYPE_MONTH_DATE：返回日期，例如2月15日
     *             Types.TYPE_CURRENT_TIME：返回时间，例如18：23
     *             其他类型：Calendar.TYPE
     * @return 类型字符串
     */
    @SuppressLint("WrongConstant")
    public static String getTime(int type) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());

        switch (type) {
            case Types.TYPE_AM_PM:
                int hour = calendar.get(Calendar.HOUR_OF_DAY);
                if (hour >= 6 && hour < 9) {
                    return "早上";
                } else if (hour >= 9 && hour < 12) {
                    return "上午";
                } else if (hour >= 12 && hour < 13) {
                    return "中午";
                } else if (hour >= 13 && hour < 19) {
                    return "下午";
                } else {
                    return "晚上";
                }
            case Types.TYPE_MONTH_DATE:
                return new SimpleDateFormat("M月d日", Locale.getDefault()).format(new Date());
            case Types.TYPE_CURRENT_TIME:
                return new SimpleDateFormat("HH:mm", Locale.getDefault()).format(new Date());
            case Types.TYPE_MONTH:
                return String.valueOf(calendar.get(Calendar.MONTH) + 1);
            case Types.TYPE_STRING_FORM:
                return new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(new Date());
            default:
                return String.valueOf(calendar.get(type));
        }
    }

    /**
     * 返回计时器时间字符串的分钟数量。
     *
     * @return 两个时间间隔的分钟数
     */
    public static int getMinutes(String time) {
        String[] times = time.split(":");
        int minutes = Integer.parseInt(times[1]);
        int hours = Integer.parseInt(times[0]);
        int seconds = Integer.parseInt(times[2]);
        return hours * 60 + minutes + seconds / 60;
    }

    public static Uri getDownloadUri(String latestVersion) {
        return Uri.parse(URLs.DOWNLOAD + latestVersion.replace(".", "") + ".apk");
    }

    public static void loadFriendProfileImg(Context context, String username, ImageView view) {
        Glide.with(context).load(URLs.PROFILE_URL + username + ".JPEG")
                .signature(new StringSignature(Utility.getTime(Calendar.HOUR_OF_DAY)))
                .dontAnimate().error(R.drawable.photo).into(view);
    }
} public class GradeProgressView extends View {

    private static final String TAG = GradeProgressView.class.getSimpleName();

    private static final int DEFAULT_PROGRESS_COLOR = Color.WHITE;
    private static final int DEFAULT_BACKGROUND_COLOR = 0x5AFFFFFF;

    private int mBackgroundColor = DEFAULT_BACKGROUND_COLOR;
    private int mProgressColor = DEFAULT_PROGRESS_COLOR;

    //进度条的每格线宽，间距，长度
    private int dashWith = 2;
    private int dashSpace = 6;
    private int lineWidth = 30;

    //最外圈线的宽度和与进度条之间的间距
    private int outLineWidth = 6;
    private int gapWidth = 25;

    //指针的线宽度， 半径， 以及指针与进度条的间距
    private int pointLineWidth = 10;
    private int pointRadius = 25;
    private int pointGap = 20;

    private int mProgress = 0;

    //外线
    private RectF mOuterRectF;
    private Paint mOuterPaint;

    //进度条
    private RectF mRectF;
    private Paint mPaint;
    private Paint mProgressPaint;

    //指针
    private Paint mInnerCirclePaint;
    private Paint mPointerPaint;
    private Path mPointerPath;

    private float centerX;
    private float centerY;

    private ValueAnimator animator;

    private OnProgressChangeListener mListener;

    public GradeProgressView(Context context) {
        this(context, null);
    }

    public GradeProgressView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GradeProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setup();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public GradeProgressView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    private void setup() {

        mRectF = new RectF();
        mOuterRectF = new RectF();

        mOuterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mOuterPaint.setStrokeWidth(outLineWidth);
        mOuterPaint.setColor(mBackgroundColor);
        mOuterPaint.setStyle(Paint.Style.STROKE);

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(lineWidth);
        mPaint.setColor(mBackgroundColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setPathEffect(new DashPathEffect(new float[]{dashWith, dashSpace}, dashSpace));

        mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressPaint.setStrokeWidth(lineWidth);
        mProgressPaint.setColor(mProgressColor);
        mProgressPaint.setStyle(Paint.Style.STROKE);
        mProgressPaint.setPathEffect(new DashPathEffect(new float[]{dashWith, dashSpace}, dashSpace));

        mPointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPointerPaint.setStrokeWidth(pointLineWidth / 2);
        mPointerPaint.setColor(mProgressColor);
        mPointerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPointerPaint.setStrokeCap(Paint.Cap.ROUND);
        mPointerPaint.setShadowLayer(4, 3, 0, 0x20000000);

        mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mInnerCirclePaint.setStrokeWidth(pointLineWidth);
        mInnerCirclePaint.setColor(mProgressColor);
        mInnerCirclePaint.setStyle(Paint.Style.STROKE);
        mInnerCirclePaint.setShadowLayer(4, 3, 0, 0x20000000);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        int value = outLineWidth / 2;
        mOuterRectF.set(value, value, w - value, h - value);
        int gap = lineWidth / 2 + outLineWidth + gapWidth;

        mRectF.set(mOuterRectF.left + gap,
                mOuterRectF.top + gap,
                mOuterRectF.right - gap,
                mOuterRectF.bottom - gap);

        centerX = mRectF.centerX();
        centerY = mRectF.centerY();

        mPointerPath = new Path();
        mPointerPath.moveTo(centerX + pointRadius, centerY - 7);
        mPointerPath.lineTo(centerX + pointRadius, centerY + 7);
        mPointerPath.lineTo(mRectF.right - pointGap - lineWidth / 2, centerY);
        mPointerPath.lineTo(centerX + pointRadius, centerY - 7);
        mPointerPath.close();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float degree = 2.7f * mProgress;

        //draw out arc
        canvas.drawArc(mOuterRectF, 135, 128, false, mOuterPaint);

        canvas.drawArc(mOuterRectF, 277, 128, false, mOuterPaint);

        //draw background arc
        canvas.drawArc(mRectF, 135 + degree, 270 - degree, false, mPaint);

        //draw progress arc
        canvas.drawArc(mRectF, 135, degree, false, mProgressPaint);


        //draw pointer
        //canvas.drawCircle(centerX, centerY, pointRadius, mInnerCirclePaint);

        canvas.save();
        canvas.rotate(135 + degree, centerX, centerY);
        //canvas.drawPath(mPointerPath, mPointerPaint);
        canvas.restore();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(Math.min(measureHeight, measureWidth), Math.min(measureHeight, measureWidth));
    }

    public void setOnProgressChangeListener(OnProgressChangeListener listener) {
        this.mListener = listener;
    }

    public int getProgressColor() {
        return mProgressColor;
    }

    public void setProgressColor(int progressColor) {
        this.mProgressColor = progressColor;
        if (mProgressPaint != null) {
            mProgressPaint.setColor(mProgressColor);
        }

        if (mPointerPaint != null) {
            mPointerPaint.setColor(mProgressColor);
        }

        if (mInnerCirclePaint != null) {
            mInnerCirclePaint.setColor(mProgressColor);
        }
        postInvalidate();
    }

    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    public void setBackgroundColor(int backgroundColor) {

        this.mBackgroundColor = backgroundColor;
        if (mPaint != null) {
            mPaint.setColor(mBackgroundColor);
        }

        if (mOuterPaint != null) {
            mOuterPaint.setColor(mBackgroundColor);
        }
        postInvalidate();
    }

    public int getLineWidth() {
        return lineWidth;
    }

    public void setLineWidth(int lineWidth) {
        this.lineWidth = lineWidth;
        if (mPaint != null) {
            mPaint.setStrokeWidth(lineWidth);
        }

        if (mProgressPaint != null) {
            mProgressPaint.setStrokeWidth(lineWidth);
        }
        postInvalidate();
    }

    public int getOutLineWidth() {
        return outLineWidth;
    }

    public void setOutLineWidth(int outLineWidth) {
        this.outLineWidth = outLineWidth;
        if (mOuterPaint != null) {
            mOuterPaint.setStrokeWidth(outLineWidth);
        }
        postInvalidate();
    }

    public int getGapWidth() {
        return gapWidth;
    }

    public void setGapWidth(int gapWidth) {
        this.gapWidth = gapWidth;
    }

    public int getProgress() {
        return mProgress;
    }

    public void setProgress(@IntRange(from = 0, to = 100) int progress) {
        if (progress > 100) {
            progress = 100;
        }

        if (progress < 0) {
            progress = 0;
        }
        this.mProgress = progress;
        if (mListener != null) {
            mListener.onProgressChanged(GradeProgressView.this, mProgress);
        }
        postInvalidate();
    }

    public void setProgressWidthAnimation(@IntRange(from = 0, to = 100) int progress) {

        if (progress > 100) {
            progress = 100;
        }

        if (progress < 0) {
            progress = 0;
        }

        if (animator != null && animator.isRunning()) {
            animator.cancel();
            animator = null;
        }

        animator = ValueAnimator.ofInt(mProgress, progress);
        int duration = 15 * Math.abs(progress - mProgress);
        animator.setDuration(duration);

        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value = (int) valueAnimator.getAnimatedValue();
                if (mProgress != value) {
                    mProgress = value;
                    if (mListener != null) {
                        mListener.onProgressChanged(GradeProgressView.this, mProgress);
                    }
                    postInvalidate();
                }
            }
        });
        animator.start();

    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        if (animator != null) {
            animator.cancel();
            animator = null;
        }

    }


    public interface OnProgressChangeListener {

        void onProgressChanged(GradeProgressView gradeProgressView, int progress);
    }
}
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.cxsj.runhdu.Model.AppModel;
import com.cxsj.runhdu.Model.BaseModel;
import com.cxsj.runhdu.Model.RunningModel;
import com.cxsj.runhdu.adapters.MyFragmentPagerAdapter;
import com.cxsj.runhdu.constant.Types;
import com.cxsj.runhdu.constant.URLs;
import com.cxsj.runhdu.Model.DataQueryModel;
import com.cxsj.runhdu.bean.gson.Running;
import com.cxsj.runhdu.bean.gson.UpdateInfo;
import com.cxsj.runhdu.bean.sport.RunningInfo;
import com.cxsj.runhdu.utils.ActivityManager;
import com.cxsj.runhdu.utils.HttpUtil;
import com.cxsj.runhdu.utils.ImageUtil;
import com.cxsj.runhdu.utils.RunningQueryUtil;
import com.cxsj.runhdu.utils.ShareUtil;
import com.cxsj.runhdu.utils.Utility;
import com.cxsj.runhdu.view.GradeProgressView;
import org.litepal.LitePal;
import org.litepal.LitePalDB;
import org.litepal.crud.DataSupport;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
import lecho.lib.hellocharts.gesture.ContainerScrollType;
import lecho.lib.hellocharts.listener.ColumnChartOnValueSelectListener;
import lecho.lib.hellocharts.model.ColumnChartData;
import lecho.lib.hellocharts.model.SubcolumnValue;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.view.ColumnChartView;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
package com.cxsj.runhdu;






public class MainActivity extends BaseActivity
        implements NavigationView.OnNavigationItemSelectedListener, View.OnClickListener {

    private CollapsingToolbarLayout collapsingToolbarLayout;
    private GradeProgressView circleProgress;
    private ImageView menuButton;
    private ImageView menuBgImg;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private TextView dataDescription;
    private TextView progressRunTimesText;
    private TextView progressStepsText;
    private TextView progressDisEnergyText;
    private TextView welcomeText;
    private CircleImageView profileImage;
    private DrawerLayout drawerLayout;
    private FloatingActionButton fab;
    private ColumnChartView columnChart;
    private RunListFragment runListFragment;
    private StatisticsFragment statisticsFragment;
    private RelativeLayout progressViewLayout;
    private RelativeLayout chartView;

    private List<String> mTitle = new ArrayList<>();
    private List<Fragment> mFragment = new ArrayList<>();

//    private SocialService socialService;
//    private SocialServiceConn conn;
//    private SocialReceiver receiver;

    private int chartColumnNum;//图表显示的列数
    private float targetSteps;
    private UpdateInfo mUpdateInfo = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (TextUtils.isEmpty(username)) exitLogin();

        //初始化view
        initView();
        //检查更新
        checkUpdate();

//        bindService(new Intent(this, SocialService.class), conn, BIND_AUTO_CREATE);
//        registerSocialReceiver();

        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                if (tab.getPosition() == 0) {
                    chartView.setVisibility(View.INVISIBLE);
                    progressViewLayout.setVisibility(View.VISIBLE);
                } else {
                    chartView.setVisibility(View.VISIBLE);
                    progressViewLayout.setVisibility(View.INVISIBLE);
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });


        columnChart.setOnValueTouchListener(new ColumnChartOnValueSelectListener() {
            @SuppressLint({"SetTextI18n", "WrongConstant"})
            @Override
            public void onValueSelected(int columnIndex, int subcolumnIndex, SubcolumnValue value) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.add(Calendar.DATE, -1 * (chartColumnNum - columnIndex - 1));
                DataQueryModel.getRunningInfo(calendar, (steps, times, dis, energy)
                        -> dataDescription.setText(
                        String.format("%s月%s日 跑步%d次 | %d步 | %d米",
                                calendar.get(Calendar.MONTH) + 1,
                                calendar.get(Calendar.DATE),
                                times, steps, dis)));
            }

            @Override
            public void onValueDeselected() {

            }
        });
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: 已经调用");
        super.onResume();
        //更新设置选项
        initSettings();
        //设置ProgressView和柱状图
        setMainData();
        //检查服务器数据是否与本地一致
        checkServerData();
    }

    @Override
    protected void onDestroy() {
        closeProgressDialog();
        HttpUtil.load(URLs.OFF_LINE)
                .addParam("UserName", username)
                .post(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                    }
                });
//        unbindService(conn);
//        if (receiver != null) {
//            unregisterReceiver(receiver);
//        }
        super.onDestroy();
    }

    //检查网络数据
    private void checkServerData() {
        if (!isSyncOn) return;
        //获取服务器端的跑步次数
        RunningModel.getRunningTimes(username, new RunningModel.GetTimesCallback() {