支持取消下载

android
jenly1314 5 years ago
parent 76f489f8d2
commit 62210f4b88
  1. 4
      .gitignore
  2. BIN
      .idea/caches/build_file_checksums.ser
  3. 52
      .idea/codeStyles/Project.xml
  4. 8
      .idea/compiler.xml
  5. 456
      .idea/dbnavigator.xml
  6. 6
      .idea/encodings.xml
  7. 20
      .idea/gradle.xml
  8. 83
      .idea/markdown-navigator.xml
  9. 3
      .idea/markdown-navigator/profiles_settings.xml
  10. 44
      .idea/misc.xml
  11. 12
      .idea/runConfigurations.xml
  12. 6
      .idea/vcs.xml
  13. 4
      app-updater/src/main/AndroidManifest.xml
  14. 25
      app-updater/src/main/java/com/king/app/updater/AppUpdater.java
  15. 17
      app-updater/src/main/java/com/king/app/updater/UpdateConfig.java
  16. 18
      app-updater/src/main/java/com/king/app/updater/http/HttpManager.java
  17. 4
      app-updater/src/main/java/com/king/app/updater/http/IHttpManager.java
  18. 45
      app-updater/src/main/java/com/king/app/updater/service/DownloadService.java
  19. 48
      app/src/main/java/com/king/appupdater/MainActivity.java
  20. 13
      app/src/main/res/layout/activity_main.xml

4
.gitignore vendored

@ -1,9 +1,7 @@
*.iml *.iml
.gradle .gradle
/local.properties /local.properties
/.idea/libraries /.idea
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store .DS_Store
/build /build
/captures /captures

@ -1,52 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
</code_scheme>
</component>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
</annotationProcessing>
</component>
</project>

@ -1,456 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DBNavigator.Project.DataEditorManager">
<record-view-column-sorting-type value="BY_INDEX" />
<value-preview-text-wrapping value="true" />
<value-preview-pinned value="false" />
</component>
<component name="DBNavigator.Project.DataExportManager">
<export-instructions>
<create-header value="true" />
<quote-values-containing-separator value="true" />
<quote-all-values value="false" />
<value-separator value="" />
<file-name value="" />
<file-location value="" />
<scope value="GLOBAL" />
<destination value="FILE" />
<format value="EXCEL" />
<charset value="GBK" />
</export-instructions>
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="true" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.EditorStateManager">
<last-used-providers />
</component>
<component name="DBNavigator.Project.MethodExecutionManager">
<method-browser />
<execution-history>
<group-entries value="true" />
<execution-inputs />
</execution-history>
<argument-values-cache />
</component>
<component name="DBNavigator.Project.ObjectDependencyManager">
<last-used-dependency-type value="INCOMING" />
</component>
<component name="DBNavigator.Project.ObjectQuickFilterManager">
<last-used-operator value="EQUAL" />
<filters />
</component>
<component name="DBNavigator.Project.ScriptExecutionManager" clear-outputs="true">
<recently-used-interfaces />
</component>
<component name="DBNavigator.Project.Settings">
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
<navigation-history-size value="100" />
<show-object-details value="false" />
</general>
<filters>
<object-type-filter>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
</object-type-filter>
</filters>
<sorting>
<object-type name="COLUMN" sorting-type="NAME" />
<object-type name="FUNCTION" sorting-type="NAME" />
<object-type name="PROCEDURE" sorting-type="NAME" />
<object-type name="ARGUMENT" sorting-type="POSITION" />
</sorting>
<default-editors>
<object-type name="VIEW" editor-type="SELECTION" />
<object-type name="PACKAGE" editor-type="SELECTION" />
<object-type name="TYPE" editor-type="SELECTION" />
</default-editors>
</browser-settings>
<navigation-settings>
<lookup-filters>
<lookup-objects>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="false" />
<object-type name="ROLE" enabled="false" />
<object-type name="PRIVILEGE" enabled="false" />
<object-type name="CHARSET" enabled="false" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED VIEW" enabled="true" />
<object-type name="NESTED TABLE" enabled="false" />
<object-type name="COLUMN" enabled="false" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET TRIGGER" enabled="true" />
<object-type name="DATABASE TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="false" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE ATTRIBUTE" enabled="false" />
<object-type name="ARGUMENT" enabled="false" />
<object-type name="DIMENSION" enabled="false" />
<object-type name="CLUSTER" enabled="false" />
<object-type name="DBLINK" enabled="true" />
</lookup-objects>
<force-database-load value="false" />
<prompt-connection-selection value="true" />
<prompt-schema-selection value="true" />
</lookup-filters>
</navigation-settings>
<dataset-grid-settings>
<general>
<enable-zooming value="true" />
<enable-column-tooltip value="true" />
</general>
<sorting>
<nulls-first value="true" />
<max-sorting-columns value="4" />
</sorting>
<tracking-columns>
<columnNames value="" />
<visible value="true" />
<editable value="false" />
</tracking-columns>
</dataset-grid-settings>
<dataset-editor-settings>
<text-editor-popup>
<active value="false" />
<active-if-empty value="false" />
<data-length-threshold value="100" />
<popup-delay value="1000" />
</text-editor-popup>
<values-actions-popup>
<show-popup-button value="true" />
<element-count-threshold value="1000" />
<data-length-threshold value="250" />
</values-actions-popup>
<general>
<fetch-block-size value="100" />
<fetch-timeout value="30" />
<trim-whitespaces value="true" />
<convert-empty-strings-to-null value="true" />
<select-content-on-cell-edit value="true" />
<large-value-preview-active value="true" />
</general>
<filters>
<prompt-filter-dialog value="true" />
<default-filter-type value="BASIC" />
</filters>
<qualified-text-editor text-length-threshold="300">
<content-types>
<content-type name="Text" enabled="true" />
<content-type name="Properties" enabled="true" />
<content-type name="XML" enabled="true" />
<content-type name="DTD" enabled="true" />
<content-type name="HTML" enabled="true" />
<content-type name="XHTML" enabled="true" />
<content-type name="Java" enabled="true" />
<content-type name="SQL" enabled="true" />
<content-type name="PL/SQL" enabled="true" />
<content-type name="Groovy" enabled="true" />
<content-type name="AIDL" enabled="true" />
<content-type name="YAML" enabled="true" />
<content-type name="Manifest" enabled="true" />
</content-types>
</qualified-text-editor>
<record-navigation>
<navigation-target value="VIEWER" />
</record-navigation>
</dataset-editor-settings>
<code-editor-settings>
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
<revert-changes value="true" />
</confirmations>
</code-editor-settings>
<code-completion-settings>
<filters>
<basic-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="false" />
<filter-element type="OBJECT" id="view" selected="false" />
<filter-element type="OBJECT" id="materialized view" selected="false" />
<filter-element type="OBJECT" id="index" selected="false" />
<filter-element type="OBJECT" id="constraint" selected="false" />
<filter-element type="OBJECT" id="trigger" selected="false" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="false" />
<filter-element type="OBJECT" id="procedure" selected="false" />
<filter-element type="OBJECT" id="function" selected="false" />
<filter-element type="OBJECT" id="package" selected="false" />
<filter-element type="OBJECT" id="type" selected="false" />
<filter-element type="OBJECT" id="dimension" selected="false" />
<filter-element type="OBJECT" id="cluster" selected="false" />
<filter-element type="OBJECT" id="dblink" selected="false" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</basic-filter>
<extended-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</extended-filter>
</filters>
<sorting enabled="true">
<sorting-element type="RESERVED_WORD" id="keyword" />
<sorting-element type="RESERVED_WORD" id="datatype" />
<sorting-element type="OBJECT" id="column" />
<sorting-element type="OBJECT" id="table" />
<sorting-element type="OBJECT" id="view" />
<sorting-element type="OBJECT" id="materialized view" />
<sorting-element type="OBJECT" id="index" />
<sorting-element type="OBJECT" id="constraint" />
<sorting-element type="OBJECT" id="trigger" />
<sorting-element type="OBJECT" id="synonym" />
<sorting-element type="OBJECT" id="sequence" />
<sorting-element type="OBJECT" id="procedure" />
<sorting-element type="OBJECT" id="function" />
<sorting-element type="OBJECT" id="package" />
<sorting-element type="OBJECT" id="type" />
<sorting-element type="OBJECT" id="dimension" />
<sorting-element type="OBJECT" id="cluster" />
<sorting-element type="OBJECT" id="dblink" />
<sorting-element type="OBJECT" id="schema" />
<sorting-element type="OBJECT" id="role" />
<sorting-element type="OBJECT" id="user" />
<sorting-element type="RESERVED_WORD" id="function" />
<sorting-element type="RESERVED_WORD" id="parameter" />
</sorting>
<format>
<enforce-code-style-case value="true" />
</format>
</code-completion-settings>
<execution-engine-settings>
<statement-execution>
<fetch-block-size value="100" />
<execution-timeout value="20" />
<debug-execution-timeout value="600" />
<focus-result value="false" />
<prompt-execution value="false" />
</statement-execution>
<script-execution>
<command-line-interfaces />
<execution-timeout value="300" />
</script-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
</execution-engine-settings>
<operation-settings>
<transactions>
<uncommitted-changes>
<on-project-close value="ASK" />
<on-disconnect value="ASK" />
<on-autocommit-toggle value="ASK" />
</uncommitted-changes>
<multiple-uncommitted-changes>
<on-commit value="ASK" />
<on-rollback value="ASK" />
</multiple-uncommitted-changes>
</transactions>
<session-browser>
<disconnect-session value="ASK" />
<kill-session value="ASK" />
<reload-on-filter-change value="false" />
</session-browser>
<compiler>
<compile-type value="KEEP" />
<compile-dependencies value="ASK" />
<always-show-controls value="false" />
</compiler>
<debugger>
<debugger-type value="ASK" />
<use-generic-runners value="true" />
</debugger>
</operation-settings>
<ddl-file-settings>
<extensions>
<mapping file-type-id="VIEW" extensions="vw" />
<mapping file-type-id="TRIGGER" extensions="trg" />
<mapping file-type-id="PROCEDURE" extensions="prc" />
<mapping file-type-id="FUNCTION" extensions="fnc" />
<mapping file-type-id="PACKAGE" extensions="pkg" />
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
<mapping file-type-id="TYPE" extensions="tpe" />
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
</extensions>
<general>
<lookup-ddl-files value="true" />
<create-ddl-files value="false" />
<synchronize-ddl-files value="true" />
<use-qualified-names value="false" />
<make-scripts-rerunnable value="true" />
</general>
</ddl-file-settings>
<general-settings>
<regional-settings>
<date-format value="MEDIUM" />
<number-format value="UNGROUPED" />
<locale value="SYSTEM_DEFAULT" />
<use-custom-formats value="false" />
</regional-settings>
<environment>
<environment-types>
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
</environment-types>
<visibility-settings>
<connection-tabs value="true" />
<dialog-headers value="true" />
<object-editor-tabs value="true" />
<script-editor-tabs value="false" />
<execution-result-tabs value="true" />
</visibility-settings>
</environment>
</general-settings>
</component>
<component name="DBNavigator.Project.StatementExecutionManager">
<execution-variables />
</component>
</project>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/app-dialog" />
<option value="$PROJECT_DIR$/app-updater" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownProjectSettings" wasCopied="true">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
<PanelProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
</PanelProvider>
</PreviewSettings>
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="0" emojiImages="0">
<PegdownExtensions>
<option name="ABBREVIATIONS" value="false" />
<option name="ANCHORLINKS" value="true" />
<option name="ASIDE" value="false" />
<option name="ATXHEADERSPACE" value="true" />
<option name="AUTOLINKS" value="true" />
<option name="DEFINITIONS" value="false" />
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
<option name="FENCED_CODE_BLOCKS" value="true" />
<option name="FOOTNOTES" value="false" />
<option name="HARDWRAPS" value="false" />
<option name="HTML_DEEP_PARSER" value="false" />
<option name="INSERTED" value="false" />
<option name="QUOTES" value="false" />
<option name="RELAXEDHRULES" value="true" />
<option name="SMARTS" value="false" />
<option name="STRIKETHROUGH" value="true" />
<option name="SUBSCRIPT" value="false" />
<option name="SUPERSCRIPT" value="false" />
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
<option name="SUPPRESS_INLINE_HTML" value="false" />
<option name="TABLES" value="true" />
<option name="TASKLISTITEMS" value="true" />
<option name="TOC" value="false" />
<option name="WIKILINKS" value="true" />
</PegdownExtensions>
<ParserOptions>
<option name="ADMONITION_EXT" value="false" />
<option name="ATTRIBUTES_EXT" value="false" />
<option name="COMMONMARK_LISTS" value="false" />
<option name="DUMMY" value="false" />
<option name="EMOJI_SHORTCUTS" value="true" />
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
<option name="FLEXMARK_FRONT_MATTER" value="false" />
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="true" />
<option name="GFM_TABLE_RENDERING" value="true" />
<option name="GITBOOK_URL_ENCODING" value="false" />
<option name="GITHUB_LISTS" value="true" />
<option name="GITHUB_WIKI_LINKS" value="true" />
<option name="GITLAB_EXT" value="false" />
<option name="GITLAB_MATH_EXT" value="false" />
<option name="GITLAB_MERMAID_EXT" value="false" />
<option name="HEADER_ID_NON_ASCII_TO_LOWERCASE" value="false" />
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
<option name="JEKYLL_FRONT_MATTER" value="false" />
<option name="MACROS_EXT" value="false" />
<option name="NO_TEXT_ATTRIBUTES" value="false" />
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
</ParserOptions>
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false">
<GeneratorProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
<bodyTop />
<bodyBottom />
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="false" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<cssText />
<cssUriHistory />
</CssSettings>
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
</project>

@ -1,3 +0,0 @@
<component name="MarkdownNavigator.ProfileManager">
<settings default="" pdf-export="" plain-text-search-scope="Project Files" />
</component>

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -11,10 +11,10 @@
<application> <application>
<service android:name=".service.DownloadService"/> <service android:name="com.king.app.updater.service.DownloadService"/>
<provider <provider
android:name=".provider.AppUpdaterFileProvider" android:name="com.king.app.updater.provider.AppUpdaterFileProvider"
android:authorities="${applicationId}.fileProvider" android:authorities="${applicationId}.fileProvider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">

@ -111,6 +111,21 @@ public class AppUpdater {
} }
} }
/**
* 停止
*/
public void stop(){
stopDownloadService();
}
/**
* 停止下载服务
*/
private void stopDownloadService(){
Intent intent = new Intent(mContext, DownloadService.class);
intent.putExtra(Constants.KEY_STOP_DOWNLOAD_SERVICE,true);
mContext.startService(intent);
}
/** /**
* AppUpdater构建器 * AppUpdater构建器
@ -296,6 +311,16 @@ public class AppUpdater {
return this; return this;
} }
/**
* 设置是否自动删除取消下载的文件
* @param isDeleteCancelFile 是否删除取消下载的文件默认为true
* @return
*/
public Builder setDeleteCancelFile(boolean isDeleteCancelFile){
mConfig.setDeleteCancelFile(isDeleteCancelFile);
return this;
}
public AppUpdater build(@NonNull Context context){ public AppUpdater build(@NonNull Context context){
AppUpdater appUpdater = new AppUpdater(context,mConfig); AppUpdater appUpdater = new AppUpdater(context,mConfig);
return appUpdater; return appUpdater;

@ -87,6 +87,11 @@ public class UpdateConfig implements Parcelable {
*/ */
private Map<String,String> mRequestProperty; private Map<String,String> mRequestProperty;
/**
* 是否删除取消下载的文件
*/
private boolean isDeleteCancelFile = true;
public UpdateConfig() { public UpdateConfig() {
@ -233,6 +238,15 @@ public class UpdateConfig implements Parcelable {
} }
public boolean isDeleteCancelFile() {
return isDeleteCancelFile;
}
public void setDeleteCancelFile(boolean deleteCancelFile) {
isDeleteCancelFile = deleteCancelFile;
}
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
@ -262,7 +276,7 @@ public class UpdateConfig implements Parcelable {
dest.writeString(entry.getValue()); dest.writeString(entry.getValue());
} }
} }
dest.writeByte(this.isDeleteCancelFile ? (byte) 1 : (byte) 0);
} }
protected UpdateConfig(Parcel in) { protected UpdateConfig(Parcel in) {
@ -288,6 +302,7 @@ public class UpdateConfig implements Parcelable {
String value = in.readString(); String value = in.readString();
this.mRequestProperty.put(key, value); this.mRequestProperty.put(key, value);
} }
this.isDeleteCancelFile = in.readByte() != 0;
} }
public static final Creator<UpdateConfig> CREATOR = new Creator<UpdateConfig>() { public static final Creator<UpdateConfig> CREATOR = new Creator<UpdateConfig>() {

@ -27,6 +27,8 @@ public class HttpManager implements IHttpManager {
private int mTimeout; private int mTimeout;
private boolean isCancel;
private static HttpManager INSTANCE; private static HttpManager INSTANCE;
public static HttpManager getInstance(){ public static HttpManager getInstance(){
@ -49,9 +51,14 @@ public class HttpManager implements IHttpManager {
@Override @Override
public void download(String url, String path, String filename, @Nullable Map<String,String> requestProperty, DownloadCallback callback) { public void download(String url, String path, String filename, @Nullable Map<String,String> requestProperty, DownloadCallback callback) {
isCancel = false;
new DownloadTask(url,path,filename,requestProperty,callback).execute(); new DownloadTask(url,path,filename,requestProperty,callback).execute();
} }
@Override
public void cancel() {
isCancel = true;
}
/** /**
* 异步下载任务 * 异步下载任务
@ -118,6 +125,10 @@ public class HttpManager implements IHttpManager {
File file = new File(path,filename); File file = new File(path,filename);
FileOutputStream fos = new FileOutputStream(file); FileOutputStream fos = new FileOutputStream(file);
while ((len = is.read(buffer)) != -1){ while ((len = is.read(buffer)) != -1){
if(isCancel){
cancel(true);
break;
}
fos.write(buffer,0,len); fos.write(buffer,0,len);
progress += len; progress += len;
//更新进度 //更新进度
@ -130,6 +141,10 @@ public class HttpManager implements IHttpManager {
connect.disconnect(); connect.disconnect();
if(isCancelled()){
return null;
}
return file; return file;
}else {//连接失败 }else {//连接失败
throw new ConnectException(String.format("responseCode = %d",responseCode)); throw new ConnectException(String.format("responseCode = %d",responseCode));
@ -168,8 +183,11 @@ public class HttpManager implements IHttpManager {
protected void onProgressUpdate(Integer... values) { protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values); super.onProgressUpdate(values);
if(callback!=null){ if(callback!=null){
if(!isCancelled()){
callback.onProgress(values[0],values[1]); callback.onProgress(values[0],values[1]);
} }
}
} }

@ -22,6 +22,10 @@ public interface IHttpManager {
*/ */
void download(String url, String path, String filename, @Nullable Map<String,String> requestProperty, DownloadCallback callback); void download(String url, String path, String filename, @Nullable Map<String,String> requestProperty, DownloadCallback callback);
/**
* 取消下载
*/
void cancel();
interface DownloadCallback extends Serializable{ interface DownloadCallback extends Serializable{
/** /**

@ -54,6 +54,10 @@ public class DownloadService extends Service {
*/ */
private int mCount = 0; private int mCount = 0;
private IHttpManager mHttpManager;
private File mFile;
private Context getContext(){ private Context getContext(){
return this; return this;
} }
@ -62,11 +66,11 @@ public class DownloadService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null){ if(intent != null){
if(!isDownloading){
boolean isStop = intent.getBooleanExtra(Constants.KEY_STOP_DOWNLOAD_SERVICE,false); boolean isStop = intent.getBooleanExtra(Constants.KEY_STOP_DOWNLOAD_SERVICE,false);
if(isStop){ if(isStop){
stopService(); stopDownload();
}else{ } else if(!isDownloading){
//是否实通过通知栏触发重复下载 //是否实通过通知栏触发重复下载
boolean isReDownload = intent.getBooleanExtra(Constants.KEY_RE_DOWNLOAD,false); boolean isReDownload = intent.getBooleanExtra(Constants.KEY_RE_DOWNLOAD,false);
if(isReDownload){ if(isReDownload){
@ -75,7 +79,6 @@ public class DownloadService extends Service {
//获取配置信息 //获取配置信息
UpdateConfig config = intent.getParcelableExtra(Constants.KEY_UPDATE_CONFIG); UpdateConfig config = intent.getParcelableExtra(Constants.KEY_UPDATE_CONFIG);
startDownload(config,null,null); startDownload(config,null,null);
}
}else{ }else{
Log.w(Constants.TAG,"Please do not repeat the download."); Log.w(Constants.TAG,"Please do not repeat the download.");
} }
@ -127,23 +130,23 @@ public class DownloadService extends Service {
filename = AppUtils.INSTANCE.getAppFullName(getContext(),url,getResources().getString(R.string.app_name)); filename = AppUtils.INSTANCE.getAppFullName(getContext(),url,getResources().getString(R.string.app_name));
} }
File file = new File(path,filename); mFile = new File(path,filename);
if(file.exists()){//文件是否存在 if(mFile.exists()){//文件是否存在
Integer versionCode = config.getVersionCode(); Integer versionCode = config.getVersionCode();
if(versionCode!=null){ if(versionCode!=null){
try{ try{
if(AppUtils.INSTANCE.apkExists(getContext(),versionCode,file)){ if(AppUtils.INSTANCE.apkExists(getContext(),versionCode,mFile)){
//本地已经存在要下载的APK //本地已经存在要下载的APK
Log.d(Constants.TAG,"CacheFile:" + file); Log.d(Constants.TAG,"CacheFile:" + mFile);
if(config.isInstallApk()){ if(config.isInstallApk()){
String authority = config.getAuthority(); String authority = config.getAuthority();
if(TextUtils.isEmpty(authority)){//如果为空则默认 if(TextUtils.isEmpty(authority)){//如果为空则默认
authority = getContext().getPackageName() + ".fileProvider"; authority = getContext().getPackageName() + ".fileProvider";
} }
AppUtils.INSTANCE.installApk(getContext(),file,authority); AppUtils.INSTANCE.installApk(getContext(),mFile,authority);
} }
if(callback!=null){ if(callback!=null){
callback.onFinish(file); callback.onFinish(mFile);
} }
stopService(); stopService();
return; return;
@ -153,17 +156,28 @@ public class DownloadService extends Service {
} }
} }
//删除旧文件 //删除旧文件
file.delete(); mFile.delete();
} }
Log.d(Constants.TAG,"File:" + file); Log.d(Constants.TAG,"File:" + mFile);
if(httpManager != null){ if(httpManager != null){
httpManager.download(url,path,filename,config.getRequestProperty(),new AppDownloadCallback(config,callback)); mHttpManager = httpManager;
}else{ }else{
HttpManager.getInstance().download(url,path,filename,config.getRequestProperty(),new AppDownloadCallback(config,callback)); mHttpManager = HttpManager.getInstance();
} }
mHttpManager.download(url,path,filename,config.getRequestProperty(),new AppDownloadCallback(config,callback));
} }
/**
* 停止下载
*/
public void stopDownload(){
if(mHttpManager!=null){
mHttpManager.cancel();
}
}
/** /**
* 获取缓存路径 * 获取缓存路径
* @param context * @param context
@ -326,6 +340,9 @@ public class DownloadService extends Service {
if(callback!=null){ if(callback!=null){
callback.onCancel(); callback.onCancel();
} }
if(mFile!=null){
mFile.delete();
}
stopService(); stopService();
} }
} }

@ -34,6 +34,8 @@ public class MainActivity extends AppCompatActivity {
private Toast toast; private Toast toast;
private AppUpdater mAppUpdater;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -64,7 +66,8 @@ public class MainActivity extends AppCompatActivity {
* 简单一键后台升级 * 简单一键后台升级
*/ */
private void clickBtn1(){ private void clickBtn1(){
new AppUpdater(getContext(),mUrl).start(); mAppUpdater = new AppUpdater(getContext(),mUrl);
mAppUpdater.start();
} }
/** /**
@ -74,7 +77,7 @@ public class MainActivity extends AppCompatActivity {
UpdateConfig config = new UpdateConfig(); UpdateConfig config = new UpdateConfig();
config.setUrl(mUrl); config.setUrl(mUrl);
config.addHeader("token","xxxxxx"); config.addHeader("token","xxxxxx");
new AppUpdater(getContext(),config) mAppUpdater = new AppUpdater(getContext(),config)
.setUpdateCallback(new UpdateCallback() { .setUpdateCallback(new UpdateCallback() {
@Override @Override
@ -112,8 +115,8 @@ public class MainActivity extends AppCompatActivity {
public void onCancel() { public void onCancel() {
progressBar.setVisibility(View.INVISIBLE); progressBar.setVisibility(View.INVISIBLE);
} }
}) });
.start(); mAppUpdater.start();
} }
/** /**
@ -126,7 +129,7 @@ public class MainActivity extends AppCompatActivity {
.setPositiveButton("升级", new DialogInterface.OnClickListener() { .setPositiveButton("升级", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new AppUpdater.Builder() mAppUpdater = new AppUpdater.Builder()
.serUrl(mUrl) .serUrl(mUrl)
.build(getContext()) .build(getContext())
.setUpdateCallback(new AppUpdateCallback() { .setUpdateCallback(new AppUpdateCallback() {
@ -139,8 +142,8 @@ public class MainActivity extends AppCompatActivity {
public void onFinish(File file) { public void onFinish(File file) {
showToast("下载完成"); showToast("下载完成");
} }
}) });
.start(); mAppUpdater.start();
} }
}).show(); }).show();
} }
@ -156,7 +159,8 @@ public class MainActivity extends AppCompatActivity {
.setOnClickOk(new View.OnClickListener() { .setOnClickOk(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
new AppUpdater(getContext(),mUrl).start(); mAppUpdater = new AppUpdater(getContext(),mUrl);
mAppUpdater.start();
AppDialog.INSTANCE.dismissDialog(); AppDialog.INSTANCE.dismissDialog();
} }
}); });
@ -176,10 +180,10 @@ public class MainActivity extends AppCompatActivity {
.setOnClickOk(new View.OnClickListener() { .setOnClickOk(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
new AppUpdater.Builder() mAppUpdater = new AppUpdater.Builder()
.serUrl(mUrl) .serUrl(mUrl)
.build(getContext()) .build(getContext());
.start(); mAppUpdater.start();
AppDialog.INSTANCE.dismissDialog(); AppDialog.INSTANCE.dismissDialog();
} }
}); });
@ -208,14 +212,14 @@ public class MainActivity extends AppCompatActivity {
btnOK.setOnClickListener(new View.OnClickListener() { btnOK.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
new AppUpdater.Builder() mAppUpdater = new AppUpdater.Builder()
.serUrl(mUrl) .serUrl(mUrl)
.setPath(Environment.getExternalStorageDirectory() + "/.AppUpdater") .setPath(Environment.getExternalStorageDirectory() + "/.AppUpdater")
.setVersionCode(BuildConfig.VERSION_CODE)//设置versionCode之后,新版本相同的apk只下载一次,优先取本地缓存。 .setVersionCode(BuildConfig.VERSION_CODE)//设置versionCode之后,新版本相同的apk只下载一次,优先取本地缓存。
.setFilename("AppUpdater1.apk") .setFilename("AppUpdater1.apk")
.setVibrate(true) .setVibrate(true)
.build(getContext()) .build(getContext());
.start(); mAppUpdater.start();
AppDialog.INSTANCE.dismissDialog(); AppDialog.INSTANCE.dismissDialog();
} }
}); });
@ -234,12 +238,12 @@ public class MainActivity extends AppCompatActivity {
.setOnClickOk(new View.OnClickListener() { .setOnClickOk(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
new AppUpdater.Builder() mAppUpdater = new AppUpdater.Builder()
.serUrl(mUrl) .serUrl(mUrl)
.setVibrate(true) .setVibrate(true)
.setSound(true) .setSound(true)
.build(getContext()) .build(getContext());
.start(); mAppUpdater.start();
AppDialog.INSTANCE.dismissDialogFragment(getSupportFragmentManager()); AppDialog.INSTANCE.dismissDialogFragment(getSupportFragmentManager());
} }
}); });
@ -247,6 +251,13 @@ public class MainActivity extends AppCompatActivity {
} }
private void clickCancel(){
if(mAppUpdater != null){
mAppUpdater.stop();
}
}
public void OnClick(View v){ public void OnClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.btn1: case R.id.btn1:
@ -270,6 +281,9 @@ public class MainActivity extends AppCompatActivity {
case R.id.btn7: case R.id.btn7:
clickBtn7(); clickBtn7();
break; break;
case R.id.btnCancel:
clickCancel();
break;
} }
} }
} }

@ -104,4 +104,17 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
style="@style/OnClick"/> style="@style/OnClick"/>
<Button
android:id="@+id/btnCancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:text="取消下载"
app:layout_constraintTop_toBottomOf="@+id/btn7"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
style="@style/OnClick"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
Loading…
Cancel
Save