Initial commit
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
116
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,116 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
16
.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<compositeConfiguration>
|
||||
<compositeBuild compositeDefinitionSource="SCRIPT" />
|
||||
</compositeConfiguration>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
14
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?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
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
29
app/build.gradle
Normal file
@@ -0,0 +1,29 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.android.buildToolsVersion
|
||||
defaultConfig {
|
||||
applicationId rootProject.ext.android.applicationId
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode rootProject.ext.android.versionCode
|
||||
versionName rootProject.ext.android.versionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.androidxconstraintlayout
|
||||
testImplementation rootProject.ext.dependencies.junit
|
||||
androidTestImplementation rootProject.ext.dependencies.androidxjunit
|
||||
androidTestImplementation rootProject.ext.dependencies.androidxespressocore
|
||||
}
|
||||
21
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.launcher;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith( AndroidJUnit4.class )
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals( "com.mogo.launcher", appContext.getPackageName() );
|
||||
}
|
||||
}
|
||||
16
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.launcher">
|
||||
|
||||
<application
|
||||
android:name=".MogoApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.App">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
17
app/src/main/java/com/mogo/launcher/MogoApplication.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.mogo.launcher;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-12-18
|
||||
* <p>
|
||||
* Launcher application
|
||||
*/
|
||||
public class MogoApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
}
|
||||
34
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
6
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
</resources>
|
||||
3
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">MogoLauncher</string>
|
||||
</resources>
|
||||
37
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.App" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@null</item>
|
||||
<item name="android:windowEnterAnimation">@null</item>
|
||||
<item name="android:windowExitAnimation">@null</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation</item>
|
||||
</style>
|
||||
|
||||
<style name="Animation">
|
||||
<item name="android:activityOpenEnterAnimation">@null</item>
|
||||
<item name="android:activityOpenExitAnimation">@null</item>
|
||||
<item name="android:activityCloseEnterAnimation">@null</item>
|
||||
<item name="android:activityCloseExitAnimation">@null</item>
|
||||
<item name="android:taskOpenEnterAnimation">@null</item>
|
||||
<item name="android:taskOpenExitAnimation">@null</item>
|
||||
<item name="android:taskCloseEnterAnimation">@null</item>
|
||||
<item name="android:taskCloseExitAnimation">@null</item>
|
||||
<item name="android:taskToFrontEnterAnimation">@null</item>
|
||||
<item name="android:taskToFrontExitAnimation">@null</item>
|
||||
<item name="android:taskToBackEnterAnimation">@null</item>
|
||||
<item name="android:taskToBackExitAnimation">@null</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
17
app/src/test/java/com/mogo/launcher/ExampleUnitTest.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.mogo.launcher;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals( 4, 2 + 2 );
|
||||
}
|
||||
}
|
||||
45
build.gradle
Normal file
@@ -0,0 +1,45 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
apply from: "config.gradle"
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.61+'
|
||||
repositories {
|
||||
maven {
|
||||
url 'http://maven.aliyun.com/nexus/content/groups/public/'
|
||||
}
|
||||
maven {
|
||||
url 'http://nexus.zhidaoauto.com/repository/maven-releases/'
|
||||
}
|
||||
maven {
|
||||
url 'http://nexus.zhidaoauto.com/repository/maven-public/'
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
url 'http://maven.aliyun.com/nexus/content/groups/public/'
|
||||
}
|
||||
maven {
|
||||
url 'http://nexus.zhidaoauto.com/repository/maven-releases/'
|
||||
}
|
||||
maven {
|
||||
url 'http://nexus.zhidaoauto.com/repository/maven-public/'
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
53
config.gradle
Normal file
@@ -0,0 +1,53 @@
|
||||
ext {
|
||||
android = [
|
||||
applicationId : "com.mogo.launcher",
|
||||
compileSdkVersion: 29,
|
||||
buildToolsVersion: "29.0.2",
|
||||
minSdkVersion : 19,
|
||||
targetSdkVersion : 22,
|
||||
versionCode : 1,
|
||||
versionName : "1.0.0",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
// androidx
|
||||
androidxappcompat : "androidx.appcompat:appcompat:1.0.2",
|
||||
androidxconstraintlayout: "androidx.constraintlayout:constraintlayout:1.1.3",
|
||||
// 测试
|
||||
junit : "junit:junit:4.12",
|
||||
androidxjunit : "androidx.test.ext:junit:1.1.0",
|
||||
androidxespressocore : "androidx.test.espresso:espresso-core:3.1.1",
|
||||
// 地图
|
||||
amapnavi3dmap : "com.amap.api:navi-3dmap:latest.integration",
|
||||
amapsearch : "com.amap.api:search:latest.integration",
|
||||
amaplocation : "com.amap.api:location:latest.integration",
|
||||
// json 转换
|
||||
gson : "com.google.code.gson:gson:2.8.4",
|
||||
// 内存泄漏检测
|
||||
debugleakcanary : "com.squareup.leakcanary:leakcanary-android:1.6.1",
|
||||
releaseleakcanary : "com.squareup.leakcanary:leakcanary-android-no-op:1.6.1",
|
||||
testleakcanary : "com.squareup.leakcanary:leakcanary-android-no-op:1.6.1",
|
||||
//rxJava
|
||||
rxjava : "io.reactivex.rxjava2:rxjava:2.2.2",
|
||||
rxandroid : "io.reactivex.rxjava2:rxandroid:2.1.0",
|
||||
// arouter
|
||||
arouter : "com.alibaba:arouter-api:1.5.0",
|
||||
aroutercompiler : "com.alibaba:arouter-compiler:1.2.2",
|
||||
// glide
|
||||
glide : 'com.github.bumptech.glide:glide:4.8.0',
|
||||
glideokhttp3 : 'com.github.bumptech.glide:okhttp3-integration:4.8.0',
|
||||
glideanno : 'com.github.bumptech.glide:annotations:4.8.0',
|
||||
glidecompiler : 'com.github.bumptech.glide:compiler:4.8.0',
|
||||
supportannos : "com.android.support:support-annotations:28.0.0",
|
||||
// fresco
|
||||
fresco : 'com.facebook.fresco:fresco:1.1.0',
|
||||
// 公司服务 - 语音
|
||||
aiassist : "com.zhidaoauto.common:service:1.0.4",
|
||||
|
||||
// retrofit
|
||||
retrofit : "com.squareup.retrofit2:retrofit:2.3.0",
|
||||
retrofitadapter : "com.squareup.retrofit2:adapter-rxjava:2.1.0",
|
||||
retrofitconvertergson : "com.squareup.retrofit2:converter-gson:2.3.0",
|
||||
retrofitconverterscalars: "com.squareup.retrofit2:converter-scalars:2.1.0",
|
||||
]
|
||||
}
|
||||
1
foudations/mogo-commons/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
31
foudations/mogo-commons/build.gradle
Normal file
@@ -0,0 +1,31 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api rootProject.ext.dependencies.aiassist
|
||||
implementation project(":foudations:mogo-utils")
|
||||
}
|
||||
0
foudations/mogo-commons/consumer-rules.pro
Normal file
21
foudations/mogo-commons/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
2
foudations/mogo-commons/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.commons" />
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.commons;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-12-23
|
||||
* <p>
|
||||
* 描述
|
||||
*/
|
||||
public class AbsMogoApplication extends Application {
|
||||
|
||||
private static Application sApp;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
sApp = this;
|
||||
}
|
||||
|
||||
public static Application getApp() {
|
||||
return sApp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.commons.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by congtaowang on 2019/1/7.
|
||||
*/
|
||||
public class BaseData implements Serializable, Cloneable {
|
||||
|
||||
public int code = -1;
|
||||
public String msg;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.commons.network;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-08-30
|
||||
* <p>
|
||||
* 信任所有域名
|
||||
*/
|
||||
public class AllAllowedHostnameVerifier implements HostnameVerifier {
|
||||
|
||||
@Override
|
||||
public boolean verify( String hostname, SSLSession session ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.commons.network;
|
||||
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-08-30
|
||||
* <p>
|
||||
* 描述
|
||||
*/
|
||||
public class X509TrustManagerImpl implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted( X509Certificate[] chain, String authType ) throws CertificateException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted( X509Certificate[] chain, String authType ) throws CertificateException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.mogo.commons.voice;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.zhidao.auto.platform.voice.VoiceClient;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-10-03
|
||||
* <p>
|
||||
* 语音助手通信助手
|
||||
*/
|
||||
public class AIAssist implements VoiceClient.VoiceCmdCallBack {
|
||||
|
||||
private static volatile AIAssist sInstance;
|
||||
|
||||
public static AIAssist getInstance( Context context ) {
|
||||
if ( sInstance == null ) {
|
||||
synchronized ( AIAssist.class ) {
|
||||
if ( sInstance == null ) {
|
||||
sInstance = new AIAssist( context );
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public synchronized void release() {
|
||||
sInstance = null;
|
||||
}
|
||||
|
||||
private final VoiceClient mVoiceClient;
|
||||
private Map< String, IMogoVoiceCmdCallBack > mUnWakeupCmdMap = new HashMap<>();
|
||||
|
||||
private AIAssist( Context context ) {
|
||||
// private constructor
|
||||
mVoiceClient = new VoiceClient( context.getApplicationContext() );
|
||||
mVoiceClient.setCallBack( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdSelected( String cmd ) {
|
||||
final IMogoVoiceCmdCallBack cmdCallBack = mUnWakeupCmdMap.get( cmd );
|
||||
if ( cmdCallBack != null ) {
|
||||
cmdCallBack.onCmdSelected( cmd );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdAction( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCmdCancel( String speakText ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakEnd( String speakText ) {
|
||||
IMogoVoiceCmdCallBack callBack = mUnWakeupCmdMap.get( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakEnd( speakText );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakSelectTimeOut( String speakText ) {
|
||||
IMogoVoiceCmdCallBack callBack = mUnWakeupCmdMap.get( speakText );
|
||||
if ( callBack != null ) {
|
||||
callBack.onSpeakSelectTimeOut( speakText );
|
||||
}
|
||||
}
|
||||
|
||||
public void speakTTSVoice( String text ) {
|
||||
try {
|
||||
mVoiceClient.speakDefault( text );
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoVoiceCmdCallBack callBack ) {
|
||||
mUnWakeupCmdMap.put( cmd, callBack );
|
||||
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
|
||||
}
|
||||
|
||||
public void unregisterUnWakeupCommand( String cmd ) {
|
||||
mUnWakeupCmdMap.remove( cmd );
|
||||
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
|
||||
}
|
||||
|
||||
public void registerTTSCallback( String tts, IMogoVoiceCmdCallBack cmdCallBack ) {
|
||||
mUnWakeupCmdMap.put( tts, cmdCallBack );
|
||||
}
|
||||
|
||||
public void unregisterTTSCallback( String tts ) {
|
||||
mUnWakeupCmdMap.remove( tts );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mogo.commons.voice;
|
||||
|
||||
public interface IMogoVoiceCmdCallBack {
|
||||
/**
|
||||
* 免唤醒命令响应回调
|
||||
*
|
||||
* @param cmd
|
||||
*/
|
||||
void onCmdSelected( String cmd );
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“确定”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
void onCmdAction( String speakText );
|
||||
|
||||
/**
|
||||
* 语音播报临时免唤醒“取消”命令
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
void onCmdCancel( String speakText );
|
||||
|
||||
/**
|
||||
* 语音播报完毕
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
void onSpeakEnd( String speakText );
|
||||
|
||||
/**
|
||||
* 语音播报完临时命令选择超时
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
void onSpeakSelectTimeOut( String speakText );
|
||||
}
|
||||
2
foudations/mogo-commons/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
3
foudations/mogo-commons/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">mogo-commons</string>
|
||||
</resources>
|
||||
1
foudations/mogo-utils/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
40
foudations/mogo-utils/build.gradle
Normal file
@@ -0,0 +1,40 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api rootProject.ext.dependencies.glide
|
||||
implementation rootProject.ext.dependencies.glideanno
|
||||
implementation rootProject.ext.dependencies.glideokhttp3
|
||||
implementation rootProject.ext.dependencies.supportannos
|
||||
annotationProcessor rootProject.ext.dependencies.supportannos
|
||||
annotationProcessor rootProject.ext.dependencies.glidecompiler
|
||||
api rootProject.ext.dependencies.retrofit
|
||||
api rootProject.ext.dependencies.retrofitadapter
|
||||
api rootProject.ext.dependencies.retrofitconvertergson
|
||||
api rootProject.ext.dependencies.retrofitconverterscalars
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
}
|
||||
0
foudations/mogo-utils/consumer-rules.pro
Normal file
21
foudations/mogo-utils/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith( AndroidJUnit4.class )
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals( "com.mogo.utils.test", appContext.getPackageName() );
|
||||
}
|
||||
}
|
||||
2
foudations/mogo-utils/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.utils" />
|
||||
@@ -0,0 +1,335 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ActivityLifecycleManager {
|
||||
private Application mApplication;
|
||||
/**
|
||||
* 当前出于 Start 状态的 Activity
|
||||
*/
|
||||
private ArrayList< Activity > mStartedActivities = new ArrayList<>();
|
||||
|
||||
private ArrayList<AppStateListener> mAppStateListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 当前存活的 Activity
|
||||
*/
|
||||
private HashMap< Activity, ActivityTrace> mAliveActivities = new HashMap<>();
|
||||
|
||||
/**
|
||||
* App 是否出于前台
|
||||
*/
|
||||
private volatile boolean mIsAppActive = false;
|
||||
|
||||
private Activity mCurrentResumedActivity;
|
||||
|
||||
/**
|
||||
* Home 键事件广播的接受器
|
||||
*/
|
||||
private HomeKeyEventReceiver mHomeKeyEventReceiver;
|
||||
/**
|
||||
* Home 键事件监听者列表
|
||||
*/
|
||||
private ArrayList<HomeKeyEventListener> mHomeKeyEventListeners = new ArrayList<>();
|
||||
|
||||
private DefActivityLifecycleCallbacks mInnerActivityListener = new DefActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityStarted( Activity activity) {
|
||||
if (mStartedActivities.isEmpty()) {
|
||||
mIsAppActive = true;
|
||||
notifyAppStateChanged( AppStateListener.ACTIVE);
|
||||
}
|
||||
mStartedActivities.add(activity);
|
||||
|
||||
ActivityTrace trace = mAliveActivities.get(activity);
|
||||
if (trace != null) {
|
||||
trace.startCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped( Activity activity) {
|
||||
mStartedActivities.remove(activity);
|
||||
if (mStartedActivities.isEmpty()) {
|
||||
mIsAppActive = false;
|
||||
notifyAppStateChanged( AppStateListener.INACTIVE);
|
||||
}
|
||||
|
||||
ActivityTrace trace = mAliveActivities.get(activity);
|
||||
if (trace != null) {
|
||||
trace.stopCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed( Activity activity) {
|
||||
mCurrentResumedActivity = activity;
|
||||
ActivityTrace trace = mAliveActivities.get(activity);
|
||||
if (trace != null) {
|
||||
trace.resumeCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused( Activity activity) {
|
||||
ActivityTrace trace = mAliveActivities.get(activity);
|
||||
if (trace != null) {
|
||||
trace.pauseCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated( Activity activity, Bundle savedInstanceState) {
|
||||
mAliveActivities.put(activity, new ActivityTrace(activity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed( Activity activity) {
|
||||
mAliveActivities.remove(activity);
|
||||
}
|
||||
};
|
||||
|
||||
private ActivityLifecycleManager() {}
|
||||
|
||||
public static ActivityLifecycleManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class SingletonHolder{
|
||||
private static final ActivityLifecycleManager INSTANCE = new ActivityLifecycleManager();
|
||||
}
|
||||
|
||||
public void start( Application application) {
|
||||
this.mApplication = application;
|
||||
registerInnerActivityListener();
|
||||
registerHomeKeyEventReceiver();
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
unregisterActivityLifecycleCallbacks(mInnerActivityListener);
|
||||
unregisterHomeKeyEventReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 Activity 生命周期的回调
|
||||
*
|
||||
* @param callbacks Activity 生命周期的回调
|
||||
*/
|
||||
public void registerActivityLifecycleCallbacks( Application.ActivityLifecycleCallbacks callbacks) {
|
||||
if (mApplication == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return;
|
||||
}
|
||||
|
||||
mApplication.registerActivityLifecycleCallbacks(callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消注册 Activity 生命周期的回调
|
||||
*
|
||||
* @param callbacks Activity 生命周期的回调
|
||||
*/
|
||||
public void unregisterActivityLifecycleCallbacks( Application.ActivityLifecycleCallbacks callbacks) {
|
||||
if (mApplication == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return;
|
||||
}
|
||||
|
||||
mApplication.unregisterActivityLifecycleCallbacks(callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用是否出于前台
|
||||
*/
|
||||
public boolean isAppActive() {
|
||||
return mIsAppActive;
|
||||
}
|
||||
|
||||
public Activity getCurrentActivity(){
|
||||
return mCurrentResumedActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加应用状态的监听
|
||||
*/
|
||||
public void addAppStateListener(AppStateListener listener) {
|
||||
synchronized (mAppStateListeners) {
|
||||
mAppStateListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除应用状态的监听
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void removeAppStateListener(AppStateListener listener) {
|
||||
synchronized (mAppStateListeners) {
|
||||
mAppStateListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 home 键的事件监听
|
||||
*/
|
||||
public void addHomeKeyEventListener(HomeKeyEventListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (mHomeKeyEventListeners) {
|
||||
mHomeKeyEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除 home 键的事件监听
|
||||
*/
|
||||
public void removeHomeKeyEventListener(HomeKeyEventListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mHomeKeyEventListeners) {
|
||||
mHomeKeyEventListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册Activity生命周期的监听
|
||||
*/
|
||||
private void registerInnerActivityListener() {
|
||||
registerActivityLifecycleCallbacks(mInnerActivityListener);
|
||||
}
|
||||
|
||||
private void notifyAppStateChanged(int state) {
|
||||
Object[] listeners = collectAppStateListeners();
|
||||
if (listeners != null) {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
((AppStateListener) listeners[i]).onStateChanged(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] collectAppStateListeners() {
|
||||
Object[] listeners = null;
|
||||
synchronized (mAppStateListeners) {
|
||||
if (mAppStateListeners.size() > 0) {
|
||||
listeners = mAppStateListeners.toArray();
|
||||
}
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
private Object[] collectHomeKeyEventListeners() {
|
||||
Object[] listeners = null;
|
||||
synchronized (mHomeKeyEventListeners) {
|
||||
if (mHomeKeyEventListeners.size() > 0) {
|
||||
listeners = mHomeKeyEventListeners.toArray();
|
||||
}
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
private void registerHomeKeyEventReceiver() {
|
||||
android.content.IntentFilter filter = new android.content.IntentFilter();
|
||||
filter.addAction( Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
|
||||
mHomeKeyEventReceiver = new HomeKeyEventReceiver();
|
||||
mApplication.registerReceiver(mHomeKeyEventReceiver, filter);
|
||||
}
|
||||
|
||||
private void unregisterHomeKeyEventReceiver() {
|
||||
mApplication.unregisterReceiver(mHomeKeyEventReceiver);
|
||||
}
|
||||
|
||||
private void onHomeKeyPressed() {
|
||||
Object[] listeners = collectHomeKeyEventListeners();
|
||||
if (listeners != null) {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
((HomeKeyEventListener) listeners[i]).onHomeKeyPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi( Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
public static abstract class DefActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
|
||||
@Override
|
||||
public void onActivityCreated( Activity activity, Bundle savedInstanceState) {}
|
||||
@Override
|
||||
public void onActivityStarted( Activity activity) {}
|
||||
@Override
|
||||
public void onActivityResumed( Activity activity) {}
|
||||
@Override
|
||||
public void onActivityPaused( Activity activity) {}
|
||||
@Override
|
||||
public void onActivityStopped( Activity activity) {}
|
||||
@Override
|
||||
public void onActivitySaveInstanceState( Activity activity, Bundle outState) {}
|
||||
@Override
|
||||
public void onActivityDestroyed( Activity activity) {}
|
||||
}
|
||||
|
||||
public interface AppStateListener {
|
||||
int INACTIVE = 0;
|
||||
int ACTIVE = 1;
|
||||
/**
|
||||
* App 状态的回调
|
||||
*/
|
||||
void onStateChanged( int state );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* home 键的监听
|
||||
*/
|
||||
public interface HomeKeyEventListener {
|
||||
void onHomeKeyPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity 的生命周期调用痕迹
|
||||
*/
|
||||
static class ActivityTrace {
|
||||
Activity activity;
|
||||
int resumeCnt;
|
||||
int pauseCnt;
|
||||
int startCnt;
|
||||
int stopCnt;
|
||||
|
||||
ActivityTrace( Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
}
|
||||
|
||||
private final class HomeKeyEventReceiver extends BroadcastReceiver {
|
||||
private final String SYSTEM_DIALOG_REASON_KEY = "reason";
|
||||
private final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
|
||||
|
||||
@Override
|
||||
public void onReceive( Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if ( Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
|
||||
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
|
||||
if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
|
||||
onHomeKeyPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ActivityStack {
|
||||
private static final Deque< Activity > ACTIVITY_STACK = new ArrayDeque<>();
|
||||
|
||||
public static synchronized void addActivity( Activity activity) {
|
||||
if(activity != null){
|
||||
ACTIVITY_STACK.offer(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized Activity currentActivity() {
|
||||
return ACTIVITY_STACK.peekLast();
|
||||
}
|
||||
|
||||
public static synchronized void finishCurrentActivity() {
|
||||
Activity activity = ACTIVITY_STACK.pop();
|
||||
if (!activity.isFinishing()) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void finishActivity( Activity activity) {
|
||||
ACTIVITY_STACK.remove(activity);
|
||||
if (!activity.isFinishing()) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void finishActivity( Class<? extends Activity > cls) {
|
||||
Iterator< Activity > iterator = ACTIVITY_STACK.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Activity next = iterator.next();
|
||||
if(next.getClass().equals(cls)){
|
||||
iterator.remove();
|
||||
if(!next.isFinishing()){
|
||||
next.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void finishActivityExcept( Class<?> cls) {
|
||||
Iterator< Activity > iterator = ACTIVITY_STACK.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Activity next = iterator.next();
|
||||
if (!next.getClass().equals(cls)) {
|
||||
iterator.remove();
|
||||
if(!next.isFinishing()){
|
||||
next.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void finishAllActivity() {
|
||||
Iterator< Activity > iterator = ACTIVITY_STACK.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
iterator.remove();
|
||||
Activity next = iterator.next();
|
||||
if(!next.isFinishing()){
|
||||
next.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized boolean isActivityExist( Class<? extends Activity > cls){
|
||||
Iterator< Activity > iterator = ACTIVITY_STACK.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Activity next = iterator.next();
|
||||
if(next.getClass().equals(cls)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public class ArrayUtils {
|
||||
|
||||
/**
|
||||
* 加强版的asList会检查传入是否为null,以保证不会抛出异常 并且返回的arraylist改为{@link ArrayList}
|
||||
*
|
||||
* @param <T>
|
||||
* @param array
|
||||
* @return
|
||||
*/
|
||||
public static <T> ArrayList<T> asList( T... array) {
|
||||
if (array == null) {
|
||||
return new ArrayList<T>(0);
|
||||
}
|
||||
ArrayList<T> list = new ArrayList<T>( Arrays.asList(array));
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T> List<T> asReadOnlyList( T... array) {
|
||||
return new ReadOnlyArrayList<T>(array);
|
||||
}
|
||||
|
||||
public static boolean contains( Object[] array, Object value) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
for ( Object object : array) {
|
||||
if (object == null) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
} else if (object.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在已排序数组中查询是否存在某值
|
||||
*
|
||||
* @param array
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean contains(int[] array, int value) {
|
||||
return Arrays.binarySearch(array, value) >= 0 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with <tt>false</tt> (if necessary) so the copy has the
|
||||
* specified length. For all indices that are valid in both the original array and the copy, the two arrays will
|
||||
* contain identical values. For any indices that are valid in the copy but not the original, the copy will contain
|
||||
* <tt>false</tt>. Such indices will exist if and only if the specified length is greater than that of the original
|
||||
* array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with false elements to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static boolean[] copyOf(boolean[] original, int newLength) {
|
||||
boolean[] copy = new boolean[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>(byte)0</tt>.
|
||||
* Such indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static byte[] copyOf(byte[] original, int newLength) {
|
||||
byte[] copy = new byte[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with null characters (if necessary) so the copy has the
|
||||
* specified length. For all indices that are valid in both the original array and the copy, the two arrays will
|
||||
* contain identical values. For any indices that are valid in the copy but not the original, the copy will contain
|
||||
* <tt>'\\u000'</tt>. Such indices will exist if and only if the specified length is greater than that of the
|
||||
* original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with null characters to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static char[] copyOf(char[] original, int newLength) {
|
||||
char[] copy = new char[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>0d</tt>. Such
|
||||
* indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static double[] copyOf(double[] original, int newLength) {
|
||||
double[] copy = new double[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>0f</tt>. Such
|
||||
* indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static float[] copyOf(float[] original, int newLength) {
|
||||
float[] copy = new float[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>0</tt>. Such
|
||||
* indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static int[] copyOf(int[] original, int newLength) {
|
||||
int[] copy = new int[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>0L</tt>. Such
|
||||
* indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static long[] copyOf(long[] original, int newLength) {
|
||||
long[] copy = new long[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>(short)0</tt>.
|
||||
* Such indices will exist if and only if the specified length is greater than that of the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with zeros to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static short[] copyOf(short[] original, int newLength) {
|
||||
short[] copy = new short[newLength];
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with nulls (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>null</tt>.
|
||||
* Such indices will exist if and only if the specified length is greater than that of the original array. The
|
||||
* resulting array is of exactly the same class as the original array.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with nulls to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
*/
|
||||
public static <T> T[] copyOf(T[] original, int newLength) {
|
||||
return (T[]) copyOf(original, newLength, original.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jdk1.6拷贝过来,android中没有这些方法。<br />
|
||||
* Copies the specified array, truncating or padding with nulls (if necessary) so the copy has the specified length.
|
||||
* For all indices that are valid in both the original array and the copy, the two arrays will contain identical
|
||||
* values. For any indices that are valid in the copy but not the original, the copy will contain <tt>null</tt>.
|
||||
* Such indices will exist if and only if the specified length is greater than that of the original array. The
|
||||
* resulting array is of the class <tt>newType</tt>.
|
||||
*
|
||||
* @param original the array to be copied
|
||||
* @param newLength the length of the copy to be returned
|
||||
* @param newType the class of the copy to be returned
|
||||
* @return a copy of the original array, truncated or padded with nulls to obtain the specified length
|
||||
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
|
||||
* @throws NullPointerException if <tt>original</tt> is null
|
||||
* @throws ArrayStoreException if an element copied from <tt>original</tt> is not of a runtime type that can be
|
||||
* stored in an array of class <tt>newType</tt>
|
||||
*/
|
||||
public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
|
||||
T[] copy = ( Object ) newType == ( Object ) Object[].class ? (T[]) new Object[newLength] : (T[]) Array.newInstance(
|
||||
newType.getComponentType(), newLength);
|
||||
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组中查询某值所在位置
|
||||
*
|
||||
* @param array
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static int indexOf(int[] array, int value) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i] == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException(value + "is not in " + Arrays.toString(array));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组中查询某值所在位置
|
||||
*
|
||||
* @param <T>
|
||||
* @param array
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static <T> int indexOf(T[] array, T value) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i].equals(value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException(value.toString() + "is not in " + Arrays.toString(array));
|
||||
}
|
||||
|
||||
private static class ReadOnlyArrayList<E> extends AbstractList<E> implements List<E>, Serializable, RandomAccess {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final E[] a;
|
||||
|
||||
ReadOnlyArrayList(E[] storage) {
|
||||
a = storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains( Object object) {
|
||||
if (a == null) {
|
||||
return false;
|
||||
}
|
||||
if (object != null) {
|
||||
for (E element : a) {
|
||||
if (object.equals(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (E element : a) {
|
||||
if (element == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int location) {
|
||||
try {
|
||||
return a[location];
|
||||
} catch ( ArrayIndexOutOfBoundsException e) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} catch ( NullPointerException e) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf( Object object) {
|
||||
if (a == null) {
|
||||
return -1;
|
||||
}
|
||||
if (object != null) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (object.equals(a[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] == null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf( Object object) {
|
||||
if (a == null) {
|
||||
return -1;
|
||||
}
|
||||
if (object != null) {
|
||||
for (int i = a.length - 1; i >= 0; i--) {
|
||||
if (object.equals(a[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = a.length - 1; i >= 0; i--) {
|
||||
if (a[i] == null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int location, E object) {
|
||||
if (a == null) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
try {
|
||||
E result = a[location];
|
||||
a[location] = object;
|
||||
return result;
|
||||
} catch ( ArrayIndexOutOfBoundsException e) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} catch ( ArrayStoreException e) {
|
||||
throw new ClassCastException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return a == null ? 0 : a.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
if (a == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
return a.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] contents) {
|
||||
if (a == null) {
|
||||
return contents;
|
||||
}
|
||||
int size = size();
|
||||
if (size > contents.length) {
|
||||
Class<?> ct = contents.getClass().getComponentType();
|
||||
contents = (T[]) Array.newInstance(ct, size);
|
||||
}
|
||||
System.arraycopy(a, 0, contents, 0, size);
|
||||
if (size < contents.length) {
|
||||
contents[size] = null;
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array
|
||||
* @return
|
||||
*/
|
||||
public static <T> boolean isEmpty( Collection<T> array) {
|
||||
if (array == null || array.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array
|
||||
* @return
|
||||
*/
|
||||
public static <T> boolean isEmpty(T[] array) {
|
||||
if (array == null || array.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并2个array
|
||||
*
|
||||
* @param head
|
||||
* @param tail
|
||||
* @return
|
||||
*/
|
||||
public static <T> T[] join(T[] head, T[] tail) {
|
||||
if (head == null) {
|
||||
return tail;
|
||||
}
|
||||
if (tail == null) {
|
||||
return head;
|
||||
}
|
||||
Class<?> type = head.getClass().getComponentType();
|
||||
T[] result = (T[]) Array.newInstance(type, head.length + tail.length);
|
||||
|
||||
System.arraycopy(head, 0, result, 0, head.length);
|
||||
System.arraycopy(tail, 0, result, head.length, tail.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,673 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.opengl.GLES10;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
/**
|
||||
* @author wangzhiyuan
|
||||
* @since 2017/8/30
|
||||
*/
|
||||
|
||||
public class BitmapHelper {
|
||||
private static final String TAG = "BitmapHelper";
|
||||
|
||||
static int ONE_KB = 1024;
|
||||
static int ONE_MB = ONE_KB * 1024;
|
||||
|
||||
static int SIZE_DEFAULT = 2048;
|
||||
static int SIZE_LIMIT = 2048;
|
||||
|
||||
/**
|
||||
* 根据原图添加圆角
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap createRoundCornerImage( Bitmap source, float corner ) {
|
||||
final Paint paint = new Paint();
|
||||
paint.setAntiAlias( true );
|
||||
Bitmap target = Bitmap.createBitmap( source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888 );
|
||||
Canvas canvas = new Canvas( target );
|
||||
RectF rect = new RectF( 0, 0, source.getWidth(), source.getHeight() );
|
||||
canvas.drawRoundRect( rect, corner, corner, paint );
|
||||
paint.setXfermode( new PorterDuffXfermode( PorterDuff.Mode.SRC_IN ) );
|
||||
canvas.drawBitmap( source, 0, 0, paint );
|
||||
return target;
|
||||
}
|
||||
|
||||
public static byte[] bitmapToBytes( Bitmap bitmap ) {
|
||||
if ( bitmap == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, 100, bos );
|
||||
result = bos.toByteArray();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently( bos );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use quality compression to compress bitmap's size to be smaller than a max size, and convert it to bytes thereafter.
|
||||
* Note that this method will not report compressing ratio related data.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param maxSize unit in kb
|
||||
* @return bytes after compressing bitmap to a size smaller than a specific max size.
|
||||
*/
|
||||
public static byte[] bitmapToBytes( Bitmap bitmap, int maxSize ) {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
if ( bitmap == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int maxSizeOfBytes = maxSize * ONE_KB;
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
int fullSize = 0;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||||
if ( quality == 100 ) {
|
||||
fullSize = bos.size();
|
||||
}
|
||||
Log.i( TAG, "quality<---->size, " + quality + "<---->" + bos.size() / 1024 );
|
||||
}
|
||||
while ( bos.size() > maxSizeOfBytes && ( quality -= ( fullSize > ONE_MB ) ? 10 : 5 ) >= 0 );
|
||||
|
||||
result = bos.toByteArray();
|
||||
|
||||
final long end = System.currentTimeMillis();
|
||||
Log.i( TAG,
|
||||
"bitmap to bytes costs " + ( end - start ) + "ms, \n" +
|
||||
"bitmap full size is " + ( fullSize / 1024 ) + "kb, \n" +
|
||||
"bitmap final size is " + ( bos.size() / 1024 ) + "kb, \n" +
|
||||
"bitmap quality is " + quality );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently( bos );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use quality compression to compress bitmap to be smaller than a specific max size.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param maxSize a specific max size which's unit is kb.
|
||||
* @return a compressed bitmap smaller than the max size.
|
||||
*/
|
||||
public static Bitmap compressBitmap( Bitmap bitmap, int maxSize, final OnCompressListener listener ) {
|
||||
if ( bitmap == null || bitmap.isRecycled() ) {
|
||||
return null;
|
||||
}
|
||||
listener.onBeforeCompress();
|
||||
ByteArrayOutputStream bos = null;
|
||||
Bitmap target = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||||
}
|
||||
while ( bos.size() / 1024 > maxSize && ( quality -= 5 ) >= 0 );
|
||||
|
||||
byte[] result = bos.toByteArray();
|
||||
target = bytesToBitmap( result );
|
||||
if ( listener != null ) {
|
||||
listener.onCompressSuccess( result );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
target = null;
|
||||
if ( listener != null ) {
|
||||
listener.onCompressFailed( "压缩失败" );
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeSilently( bos );
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap compressBitmap( Bitmap bitmap, int maxSize ) {
|
||||
if ( bitmap == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
Bitmap target = null;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
|
||||
do {
|
||||
bos.reset();
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||||
}
|
||||
while ( bos.size() / 1024 > maxSize && ( quality -= 5 ) >= 0 );
|
||||
|
||||
byte[] result = bos.toByteArray();
|
||||
target = bytesToBitmap( result );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
target = null;
|
||||
} finally {
|
||||
IOUtils.closeSilently( bos );
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an immutable bitmap from the specified byte array.
|
||||
*
|
||||
* @param b byte array of compressed image data
|
||||
* @return an immutable bitmap or null in case of exception.
|
||||
*/
|
||||
public static Bitmap bytesToBitmap( byte[] b ) {
|
||||
if ( b != null && b.length != 0 ) {
|
||||
return BitmapFactory.decodeByteArray( b, 0, b.length );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an immutable bitmap from the specified byte array.
|
||||
*
|
||||
* @param b byte array of compressed image data
|
||||
* @param options Options that control downsampling and whether the
|
||||
* image should be completely decoded, or just is size returned.
|
||||
* @return an immutable bitmap or null in case of exception.
|
||||
*/
|
||||
public static Bitmap bytesToBitmap( byte[] b, BitmapFactory.Options options ) {
|
||||
if ( b.length != 0 ) {
|
||||
return BitmapFactory.decodeByteArray( b, 0, b.length, options );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get max supported image size which will differ from different devices.
|
||||
*
|
||||
* @return max size related to the device.
|
||||
*/
|
||||
public static int getMaxSupportedImageSize() {
|
||||
int textureLimit = getMaxTextureSize();
|
||||
if ( textureLimit == 0 ) {
|
||||
return SIZE_DEFAULT;
|
||||
} else {
|
||||
return Math.min( textureLimit, SIZE_LIMIT );
|
||||
}
|
||||
}
|
||||
|
||||
public static int getMaxTextureSize2() {
|
||||
// The OpenGL texture size is the maximum size that can be drawn in an ImageView
|
||||
int[] maxSize = new int[1];
|
||||
GLES10.glGetIntegerv( GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0 );
|
||||
return maxSize[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a bitmap's input stream to find a proper inSampleSize according to device's max supported size.
|
||||
*
|
||||
* @param is bitmap's data source
|
||||
* @param close whether to close input stream after work is done.
|
||||
* @return a proper inSampleSize
|
||||
*/
|
||||
public static int findProperInSampleSize( InputStream is, boolean close ) {
|
||||
// Just decode image size into options
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
||||
try {
|
||||
BitmapFactory.decodeStream( is, null, options );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if ( close ) IOUtils.closeSilently( is );
|
||||
}
|
||||
|
||||
int maxSize = getMaxSupportedImageSize();
|
||||
int sampleSize = 1;
|
||||
|
||||
while ( options.outHeight / sampleSize > maxSize || options.outWidth / sampleSize > maxSize ) {
|
||||
sampleSize = sampleSize << 1;
|
||||
}
|
||||
|
||||
Log.i( TAG, "sample size is " + sampleSize );
|
||||
return sampleSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a picture's degree from a file.
|
||||
*
|
||||
* @param file data source of a picture
|
||||
* @return degrees range from 0 to 360
|
||||
*/
|
||||
public static int readPictureDegree( File file ) {
|
||||
return readPictureDegree( file.getAbsolutePath() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a picture's degree from a file, we use {@link ExifInterface} instead of {@link android.media.ExifInterface}
|
||||
* to avoid some unexpected bugs.
|
||||
*
|
||||
* @param filePath file's absolute path which we can read data source of a picture from.
|
||||
* @return degrees range from 0 to 360
|
||||
*/
|
||||
public static int readPictureDegree( String filePath ) {
|
||||
int degree = 0;
|
||||
|
||||
try {
|
||||
ExifInterface exifInterface = new ExifInterface( filePath );
|
||||
int orientation = exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL );
|
||||
switch ( orientation ) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
degree = 90;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
degree = 180;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
degree = 270;
|
||||
break;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.i( TAG, "ExifInterface, degree is " + degree );
|
||||
|
||||
return degree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate an bitmap to a specific angle.
|
||||
*
|
||||
* @param angle target angle
|
||||
* @param bitmap data source
|
||||
* @return Returns an immutable bitmap from subset of the source bitmap,
|
||||
* transformed by the optional matrix. The new bitmap may be the
|
||||
* same object as source, or a copy may have been made. It is
|
||||
* initialized with the same density as the original bitmap.
|
||||
* <p>
|
||||
* If the source bitmap is immutable and the requested subset is the
|
||||
* same as the source bitmap itself, then the source bitmap is
|
||||
* returned and no new bitmap is created.
|
||||
*/
|
||||
public static Bitmap rotateBitmap( int angle, Bitmap bitmap ) {
|
||||
if ( bitmap == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
int width = bitmap.getWidth();
|
||||
int height = bitmap.getHeight();
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.preRotate( angle );
|
||||
return Bitmap.createBitmap( bitmap, 0, 0, width, height, matrix, true );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get picture's absolute path according to its uri.
|
||||
*
|
||||
* @param context context
|
||||
* @param uri picture's uri
|
||||
* @return absolute path of uri.
|
||||
*/
|
||||
public static String getRealPathFromUri( Context context, Uri uri ) {
|
||||
int sdkVersion = Build.VERSION.SDK_INT;
|
||||
if ( sdkVersion >= 19 ) {
|
||||
return getRealPathFromUriAboveApi19( context, uri );
|
||||
} else {
|
||||
return getRealPathFromUriBelowAPI19( context, uri );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default {@link BitmapFactory.Options} .
|
||||
* Note this options use rgb_565 and a proper inSampleSize in order to save memory.
|
||||
*
|
||||
* @param is data source of picture
|
||||
* @param close whether to close data source
|
||||
* @return options containing rgb_565 config and a proper inSampleSize.
|
||||
*/
|
||||
public static BitmapFactory.Options newDefaultOptions( InputStream is, boolean close ) {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
options.inSampleSize = BitmapHelper.findProperInSampleSize( is, close );
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save picture to local file.
|
||||
*
|
||||
* @param bitmap data source
|
||||
* @param file local file to store picture.
|
||||
*/
|
||||
public static void savePicture( Bitmap bitmap, File file ) {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
if ( bitmap == null || file == null ) {
|
||||
Log.i( TAG, "保存失败, bitmap or file is null." );
|
||||
return;
|
||||
}
|
||||
if ( file.getParentFile() != null && !file.getParentFile().exists() ) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
try {
|
||||
final FileOutputStream fos = new FileOutputStream( file );
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, 100, fos );
|
||||
fos.flush();
|
||||
fos.close();
|
||||
|
||||
if ( file.exists() ) {
|
||||
Log.i( TAG, "保存成功" );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Log.i( TAG, "saving picture costs " + ( System.currentTimeMillis() - start ) + "ms" );
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配api19以下(不包括api19),根据uri获取图片的绝对路径
|
||||
*
|
||||
* @param context 上下文对象
|
||||
* @param uri 图片的Uri
|
||||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||||
*/
|
||||
private static String getRealPathFromUriBelowAPI19( Context context, Uri uri ) {
|
||||
return getDataColumn( context, uri, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配api19及以上,根据uri获取图片的绝对路径
|
||||
*
|
||||
* @param context 上下文对象
|
||||
* @param uri 图片的Uri
|
||||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||||
*/
|
||||
@SuppressLint( "NewApi" )
|
||||
private static String getRealPathFromUriAboveApi19( Context context, Uri uri ) {
|
||||
String filePath = null;
|
||||
|
||||
try {
|
||||
// 如果是document类型的 uri, 则通过document id来进行处理
|
||||
if ( DocumentsContract.isDocumentUri( context, uri ) ) {
|
||||
String documentId = DocumentsContract.getDocumentId( uri );
|
||||
if ( isMediaDocument( uri ) ) {
|
||||
// 使用':'分割
|
||||
String id = documentId.split( ":" )[1];
|
||||
String selection = MediaStore.Images.Media._ID + "=?";
|
||||
String[] selectionArgs = {id};
|
||||
filePath = getDataColumn( context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs );
|
||||
} else if ( isDownloadsDocument( uri ) ) {
|
||||
Uri contentUri = ContentUris.withAppendedId( Uri.parse( "content://downloads/public_downloads" ), Long.valueOf( documentId ) );
|
||||
filePath = getDataColumn( context, contentUri, null, null );
|
||||
}
|
||||
} else if ( "content".equalsIgnoreCase( uri.getScheme() ) ) {
|
||||
filePath = getDataColumn( context, uri, null, null );
|
||||
} else if ( "file".equals( uri.getScheme() ) ) {
|
||||
filePath = uri.getPath();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库表中的 _data 列,即返回Uri对应的文件路径
|
||||
*/
|
||||
private static String getDataColumn( Context context, Uri uri, String selection, String[] selectionArgs ) {
|
||||
String path = null;
|
||||
String[] projection = new String[]{MediaStore.Images.Media.DATA};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query( uri, projection, selection, selectionArgs, null );
|
||||
|
||||
if ( cursor != null && cursor.moveToFirst() ) {
|
||||
int columnIndex = cursor.getColumnIndexOrThrow( projection[0] );
|
||||
path = cursor.getString( columnIndex );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
if ( cursor != null ) {
|
||||
cursor.close();
|
||||
cursor = null;
|
||||
}
|
||||
} finally {
|
||||
if ( cursor != null ) {
|
||||
cursor.close();
|
||||
cursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri the Uri to check
|
||||
* @return Whether the Uri authority is MediaProvider
|
||||
*/
|
||||
private static boolean isMediaDocument( Uri uri ) {
|
||||
return "com.android.providers.media.documents".equals( uri.getAuthority() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri the Uri to check
|
||||
* @return Whether the Uri authority is DownloadsProvider
|
||||
*/
|
||||
private static boolean isDownloadsDocument( Uri uri ) {
|
||||
return "com.android.providers.downloads.documents".equals( uri.getAuthority() );
|
||||
}
|
||||
|
||||
public static int getMaxTextureSize() {
|
||||
try {
|
||||
// Safe minimum default size
|
||||
final int IMAGE_MAX_BITMAP_DIMENSION = SIZE_DEFAULT;
|
||||
|
||||
// Get EGL Display
|
||||
EGL10 egl = ( EGL10 ) EGLContext.getEGL();
|
||||
EGLDisplay display = egl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY );
|
||||
|
||||
// Initialise
|
||||
int[] version = new int[2];
|
||||
egl.eglInitialize( display, version );
|
||||
|
||||
// Query total number of configurations
|
||||
int[] totalConfigurations = new int[1];
|
||||
egl.eglGetConfigs( display, null, 0, totalConfigurations );
|
||||
|
||||
// Query actual list configurations
|
||||
EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
|
||||
egl.eglGetConfigs( display, configurationsList, totalConfigurations[0], totalConfigurations );
|
||||
|
||||
int[] textureSize = new int[1];
|
||||
int maximumTextureSize = 0;
|
||||
|
||||
// Iterate through all the configurations to located the maximum texture size
|
||||
for ( int i = 0; i < totalConfigurations[0]; i++ ) {
|
||||
// Only need to check for width since opengl textures are always squared
|
||||
egl.eglGetConfigAttrib( display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize );
|
||||
|
||||
// Keep trackCustomEvent of the maximum texture size
|
||||
if ( maximumTextureSize < textureSize[0] )
|
||||
maximumTextureSize = textureSize[0];
|
||||
}
|
||||
|
||||
// Release
|
||||
egl.eglTerminate( display );
|
||||
|
||||
// Return largest texture size found, or default
|
||||
return Math.max( maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static String bitmapToBase64( Bitmap bitmap ) {
|
||||
String result = null;
|
||||
try {
|
||||
if ( bitmap != null ) {
|
||||
result = Base64.encodeToString( bitmapToBytes( bitmap ), Base64.DEFAULT );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Bitmap base64ToBitmap( String base64Data ) {
|
||||
byte[] bytes = Base64.decode( base64Data, Base64.DEFAULT );
|
||||
return BitmapFactory.decodeByteArray( bytes, 0, bytes.length );
|
||||
}
|
||||
|
||||
/**
|
||||
* 在系统返回的intent中获取图片信息,并转化为uri
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public static Uri convertUri( Context context, Intent data ) {
|
||||
if ( data == null || data.getData() == null ) {
|
||||
return null;
|
||||
}
|
||||
Uri localUri = data.getData();
|
||||
String scheme = localUri.getScheme();
|
||||
String imagePath = "";
|
||||
if ( "content".equals( scheme ) ) {
|
||||
String[] filePathColumns = {MediaStore.Images.Media.DATA};
|
||||
Cursor c = context.getContentResolver().query( localUri, filePathColumns, null, null, null );
|
||||
if ( c != null ) {
|
||||
c.moveToFirst();
|
||||
int columnIndex = c.getColumnIndex( filePathColumns[0] );
|
||||
imagePath = c.getString( columnIndex );
|
||||
c.close();
|
||||
}
|
||||
} else if ( "file".equals( scheme ) ) {//小米4选择云相册中的图片是根据此方法获得路径
|
||||
imagePath = localUri.getPath();
|
||||
}
|
||||
if ( TextUtils.isEmpty( imagePath ) ) {
|
||||
return localUri;
|
||||
}
|
||||
Uri uri = Uri.fromFile( new File( imagePath ) );
|
||||
return uri != null ? uri : localUri;
|
||||
}
|
||||
|
||||
public static Bitmap colorToBitmap( Context context, int colorResId ) {// drawable 转换成bitmap
|
||||
Bitmap.Config config = Bitmap.Config.ARGB_8888;// 取drawable的颜色格式
|
||||
Bitmap bitmap = Bitmap.createBitmap( 1, 1, config );// 建立对应bitmap
|
||||
bitmap.eraseColor( context.getResources().getColor( colorResId ) );
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static String getAlphaHexValue( float alpha ) {
|
||||
String color = Integer.toHexString( ( int ) alpha * 255 );
|
||||
return TextUtils.isEmpty( color ) ? color : color.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 抓取本地视频缩略图(操作可能耗时,尽量异步进行)
|
||||
*
|
||||
* @param filePath
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap getVideoThumbnail( String filePath ) {
|
||||
Bitmap b = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
retriever.setDataSource( filePath );
|
||||
b = retriever.getFrameAtTime();
|
||||
} catch ( IllegalArgumentException e ) {
|
||||
e.printStackTrace();
|
||||
} catch ( RuntimeException e ) {
|
||||
e.printStackTrace();
|
||||
|
||||
} finally {
|
||||
try {
|
||||
retriever.release();
|
||||
} catch ( RuntimeException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public interface OnCompressListener {
|
||||
|
||||
void onCompressSuccess( byte[] data );
|
||||
|
||||
void onCompressFailed( String msg );
|
||||
|
||||
void onBeforeCompress();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CheckUtils {
|
||||
|
||||
/**
|
||||
* 检查任意Object是否为空
|
||||
* <hr>
|
||||
* shallow check : 不会检查容器内部的元素是否为空
|
||||
*/
|
||||
public static boolean isEmpty( Object obj) {
|
||||
|
||||
if (obj == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof Collection<?> ) {
|
||||
// 检查各种Collection是否为空(List,Queue,Set)
|
||||
return (( Collection<?> ) obj).isEmpty();
|
||||
} else if (obj instanceof Map<?, ?> ) {
|
||||
// 检查各种Map
|
||||
return (( Map<?, ?> ) obj).isEmpty();
|
||||
} else if (obj instanceof CharSequence ) {
|
||||
// 检查各种CharSequence
|
||||
return (( CharSequence ) obj).length() == 0;
|
||||
} else if (obj.getClass().isArray()) {
|
||||
// 检查各种base array
|
||||
// return Array.getLength(obj) == 0;
|
||||
if (obj instanceof Object[]) {
|
||||
return (( Object[]) obj).length == 0;
|
||||
} else if (obj instanceof int[]) {
|
||||
return ((int[]) obj).length == 0;
|
||||
} else if (obj instanceof long[]) {
|
||||
return ((long[]) obj).length == 0;
|
||||
} else if (obj instanceof short[]) {
|
||||
return ((short[]) obj).length == 0;
|
||||
} else if (obj instanceof double[]) {
|
||||
return ((double[]) obj).length == 0;
|
||||
} else if (obj instanceof float[]) {
|
||||
return ((float[]) obj).length == 0;
|
||||
} else if (obj instanceof boolean[]) {
|
||||
return ((boolean[]) obj).length == 0;
|
||||
} else if (obj instanceof char[]) {
|
||||
return ((char[]) obj).length == 0;
|
||||
} else if (obj instanceof byte[]) {
|
||||
return ((byte[]) obj).length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isExist( Object obj) {
|
||||
return !isEmpty(obj);
|
||||
}
|
||||
|
||||
public static boolean isContainsEmpty( Object... objs) {
|
||||
if (isEmpty(objs)) {
|
||||
return true;
|
||||
}
|
||||
for ( Object obj : objs) {
|
||||
if (isEmpty(obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为奇数
|
||||
*/
|
||||
public static boolean isOdd(int i) {
|
||||
return i % 2 != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为偶数
|
||||
*/
|
||||
public static boolean isEven(int i) {
|
||||
return i % 2 == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查枚举组中是否包含指定枚举
|
||||
*/
|
||||
public static boolean isContainsEnum( @Nullable Enum<?>[] group, Enum<?> child) {
|
||||
|
||||
if (isEmpty(group)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( Enum<?> enums : group) {
|
||||
if (enums == child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速点击事件
|
||||
*/
|
||||
private static long lastClickTime;
|
||||
public static boolean isFastDoubleClick() {
|
||||
long time = System.currentTimeMillis();
|
||||
long timeD = time - lastClickTime;
|
||||
long delayTime = 500L;
|
||||
if (0L < timeD && timeD < delayTime) {
|
||||
return true;
|
||||
} else {
|
||||
lastClickTime = time;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络是否可用
|
||||
*/
|
||||
public static boolean isNetworkConnected( Context context) {
|
||||
if ( context == null ) {
|
||||
return false;
|
||||
}
|
||||
ConnectivityManager cm = ( ConnectivityManager ) context.getSystemService( Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo network = null;
|
||||
if (cm != null) {
|
||||
network = cm.getActiveNetworkInfo();
|
||||
}
|
||||
return network != null && network.isAvailable() && network.isConnected();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查gps开关是否已打开
|
||||
*/
|
||||
public static boolean isGpsOpenStatus( Context context) {
|
||||
if ( context == null ) {
|
||||
return false;
|
||||
}
|
||||
String gps = Settings.System.getString(context.getContentResolver(), Settings.System.LOCATION_PROVIDERS_ALLOWED);
|
||||
return !( TextUtils.isEmpty(gps) || !gps.contains("gps"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否模拟位置
|
||||
*/
|
||||
public static boolean isOPenMockLocation( Context context) {
|
||||
if ( context == null ) {
|
||||
return false;
|
||||
}
|
||||
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0;
|
||||
}
|
||||
|
||||
/**当前点击点是否在视图中*/
|
||||
public static boolean isInsideView( MotionEvent event, View view) {
|
||||
if (view != null && event != null) {
|
||||
float eventX = event.getRawX();
|
||||
float eventY = event.getRawY();
|
||||
|
||||
int[] contentArray = new int[2];
|
||||
|
||||
Rect contentRect = new Rect();
|
||||
view.getLocationOnScreen(contentArray);
|
||||
view.getDrawingRect(contentRect);
|
||||
contentRect.offsetTo(contentArray[0], contentArray[1]);
|
||||
|
||||
return contentRect.contains((int) eventX, (int) eventY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断扫描内容是否为url格式
|
||||
*/
|
||||
public static boolean isUrl( String url) {
|
||||
if ( TextUtils.isEmpty(url)) {
|
||||
return false;
|
||||
}
|
||||
String regex = "http(s)?://.*";
|
||||
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = pattern.matcher(url);
|
||||
return m.matches();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Enumeration;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CommonUtils {
|
||||
|
||||
private static String mMacSerial = null;
|
||||
private static String mCPUSerial = null;
|
||||
private static boolean isMacSerialNoObtained = false;
|
||||
private static boolean isCPUSerialNoObtained = false;
|
||||
private static final Pattern VERSION_NAME_PATTERN = Pattern.compile( "(\\d+\\.\\d+\\.\\d+)\\-*.*" );
|
||||
|
||||
|
||||
public static String getAndroidID( Context context ) {
|
||||
if ( context == null ) {
|
||||
return "";
|
||||
}
|
||||
return Settings.Secure.getString( context.getContentResolver(), "android_id" );
|
||||
}
|
||||
|
||||
public static String getCPUSerialno() {
|
||||
if ( !TextUtils.isEmpty( mCPUSerial ) ) {
|
||||
return mCPUSerial;
|
||||
} else if ( isCPUSerialNoObtained ) {
|
||||
mCPUSerial = "";
|
||||
return mCPUSerial;
|
||||
} else {
|
||||
String str = "";
|
||||
|
||||
InputStreamReader ir = null;
|
||||
LineNumberReader input = null;
|
||||
try {
|
||||
isCPUSerialNoObtained = true;
|
||||
Process ex = Runtime.getRuntime().exec( "cat /proc/cpuinfo" );
|
||||
if ( ex == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ir = new InputStreamReader( ex.getInputStream() );
|
||||
input = new LineNumberReader( ir );
|
||||
|
||||
while ( null != str ) {
|
||||
str = input.readLine();
|
||||
if ( str != null ) {
|
||||
mCPUSerial = str.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch ( IOException var4 ) {
|
||||
var4.printStackTrace();
|
||||
} finally {
|
||||
if ( ir != null ) {
|
||||
try {
|
||||
ir.close();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ( input != null ) {
|
||||
try {
|
||||
input.close();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mCPUSerial;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getVersionCode( Context context ) {
|
||||
|
||||
if ( context == null ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
String pkgName = context.getPackageName();
|
||||
|
||||
try {
|
||||
PackageInfo e = context.getPackageManager().getPackageInfo( pkgName, 0 );
|
||||
if ( e != null ) {
|
||||
return e.versionCode;
|
||||
}
|
||||
} catch ( Exception var2 ) {
|
||||
var2.printStackTrace();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
public static String getMacSerialno() {
|
||||
if ( !TextUtils.isEmpty( mMacSerial ) ) {
|
||||
return mMacSerial;
|
||||
} else if ( isMacSerialNoObtained ) {
|
||||
mMacSerial = "";
|
||||
return mMacSerial;
|
||||
} else {
|
||||
String str = "";
|
||||
|
||||
InputStreamReader ir = null;
|
||||
LineNumberReader input = null;
|
||||
try {
|
||||
isMacSerialNoObtained = true;
|
||||
Process ex = Runtime.getRuntime().exec( "cat /sys/class/net/wlan0/address" );
|
||||
if ( ex == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ir = new InputStreamReader( ex.getInputStream() );
|
||||
input = new LineNumberReader( ir );
|
||||
|
||||
while ( null != str ) {
|
||||
str = input.readLine();
|
||||
if ( str != null ) {
|
||||
mMacSerial = str.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch ( IOException var4 ) {
|
||||
var4.printStackTrace();
|
||||
} finally {
|
||||
if ( ir != null ) {
|
||||
try {
|
||||
ir.close();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ( input != null ) {
|
||||
try {
|
||||
input.close();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mMacSerial;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络类型
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getNetworkType( Context context ) {
|
||||
|
||||
String name = "UNKNOWN";
|
||||
|
||||
try {
|
||||
|
||||
ConnectivityManager connMgr = ( ConnectivityManager ) context.getSystemService( Context.CONNECTIVITY_SERVICE );
|
||||
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
|
||||
if ( networkInfo != null ) {
|
||||
if ( ConnectivityManager.TYPE_WIFI == networkInfo.getType() ) {
|
||||
return "WIFI";
|
||||
}
|
||||
}
|
||||
|
||||
TelephonyManager tm = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE );
|
||||
if ( tm == null ) {
|
||||
return name;
|
||||
}
|
||||
|
||||
int type = tm.getNetworkType();
|
||||
switch ( type ) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||
name = "2G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
name = "3G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
name = "4G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
|
||||
name = "UNKNOWN";
|
||||
break;
|
||||
default:
|
||||
name = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到手机的IMEI号
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getIMEI( Context context ) {
|
||||
try {
|
||||
TelephonyManager telephonyManager = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE );
|
||||
if ( telephonyManager != null &&
|
||||
ContextCompat.checkSelfPermission( context, Manifest.permission.READ_PHONE_STATE ) == PackageManager.PERMISSION_GRANTED ) {
|
||||
return telephonyManager.getDeviceId();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到手机的IMSI号
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getIMSI( Context context ) {
|
||||
|
||||
try {
|
||||
TelephonyManager telephonyManager = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE );
|
||||
if ( telephonyManager != null &&
|
||||
ActivityCompat.checkSelfPermission( context, Manifest.permission.READ_PHONE_STATE ) == PackageManager.PERMISSION_GRANTED ) {
|
||||
return telephonyManager.getSubscriberId();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String checkSimState( Context context ) {
|
||||
|
||||
String mString = "";
|
||||
|
||||
if ( context == null ) {
|
||||
return mString;
|
||||
}
|
||||
|
||||
TelephonyManager telephonyManager = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE );
|
||||
int simState = 0;
|
||||
if ( telephonyManager != null ) {
|
||||
simState = telephonyManager.getSimState();
|
||||
}
|
||||
|
||||
switch ( simState ) {
|
||||
|
||||
case TelephonyManager.SIM_STATE_ABSENT:
|
||||
mString = "无卡";
|
||||
// do something
|
||||
break;
|
||||
|
||||
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
|
||||
mString = "需要NetworkPIN解锁";
|
||||
// do something
|
||||
|
||||
break;
|
||||
|
||||
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
|
||||
mString = "需要PIN解锁";
|
||||
// do something
|
||||
break;
|
||||
|
||||
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
|
||||
mString = "需要PUN解锁";
|
||||
// do something
|
||||
break;
|
||||
|
||||
case TelephonyManager.SIM_STATE_READY:
|
||||
mString = "良好";
|
||||
// do something
|
||||
break;
|
||||
|
||||
case TelephonyManager.SIM_STATE_UNKNOWN:
|
||||
mString = "未知状态";
|
||||
// do something
|
||||
break;
|
||||
}
|
||||
return mString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取路由器Mac
|
||||
*/
|
||||
public static String getRouterMac( Context context ) {
|
||||
|
||||
if ( context == null ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
WifiManager wifi = ( WifiManager ) context.getApplicationContext().getSystemService( Context.WIFI_SERVICE );
|
||||
if ( wifi != null && wifi.getConnectionInfo() != null ) {
|
||||
return wifi.getConnectionInfo().getBSSID();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取wifi名字
|
||||
*/
|
||||
public static String getWifiName( Context context ) {
|
||||
if ( context == null ) {
|
||||
return "";
|
||||
}
|
||||
WifiManager wifi = ( WifiManager ) context.getApplicationContext().getSystemService( Context.WIFI_SERVICE );
|
||||
if ( wifi != null && wifi.getConnectionInfo() != null ) {
|
||||
return wifi.getConnectionInfo().getSSID();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public static String getMobileIP( Context ctx ) {
|
||||
|
||||
if ( ctx == null ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
ConnectivityManager mConnectivityManager = ( ConnectivityManager ) ctx.getSystemService( Context.CONNECTIVITY_SERVICE );// 获取系统的连接服务
|
||||
// 实例化mActiveNetInfo对象
|
||||
NetworkInfo mActiveNetInfo = null;// 获取网络连接的信息
|
||||
if ( mConnectivityManager != null ) {
|
||||
mActiveNetInfo = mConnectivityManager.getActiveNetworkInfo();
|
||||
}
|
||||
if ( mActiveNetInfo == null ) {
|
||||
return "";
|
||||
} else {
|
||||
return getIp( mActiveNetInfo );
|
||||
}
|
||||
}
|
||||
|
||||
// 显示IP信息
|
||||
private static String getIp( NetworkInfo mActiveNetInfo ) {
|
||||
|
||||
if ( mActiveNetInfo == null ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 如果是WIFI网络
|
||||
if ( mActiveNetInfo.getType() == ConnectivityManager.TYPE_WIFI ) {
|
||||
return getLocalIPAddress();
|
||||
}
|
||||
// 如果是手机网络
|
||||
else if ( mActiveNetInfo.getType() == ConnectivityManager.TYPE_MOBILE ) {
|
||||
return getLocalIPAddress();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取本地IP函数
|
||||
private static String getLocalIPAddress() {
|
||||
try {
|
||||
Enumeration< NetworkInterface > mEnumeration = NetworkInterface.getNetworkInterfaces();
|
||||
if ( mEnumeration != null ) {
|
||||
while ( mEnumeration.hasMoreElements() ) {
|
||||
NetworkInterface intf = mEnumeration.nextElement();
|
||||
if ( intf != null && intf.getInetAddresses() != null ) {
|
||||
Enumeration< InetAddress > enumIPAddr = intf.getInetAddresses();
|
||||
while ( enumIPAddr.hasMoreElements() ) {
|
||||
InetAddress inetAddress = enumIPAddr.nextElement();
|
||||
// 如果不是回环地址
|
||||
if ( inetAddress != null && !inetAddress.isLoopbackAddress() ) {
|
||||
// 直接返回本地IP地址
|
||||
return inetAddress.getHostAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( SocketException ex ) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getVersionName( Context context ) {
|
||||
return getVersionName( context, true );
|
||||
}
|
||||
|
||||
public static String getVersionName( Context context, boolean fullVersionName ) {
|
||||
String appVersion = "";
|
||||
|
||||
try {
|
||||
String packageName = context.getApplicationInfo().packageName;
|
||||
appVersion = context.getPackageManager().getPackageInfo( packageName, 0 ).versionName;
|
||||
if ( !fullVersionName && appVersion != null && appVersion.length() > 0 ) {
|
||||
Matcher matcher = VERSION_NAME_PATTERN.matcher( appVersion );
|
||||
if ( matcher.matches() ) {
|
||||
appVersion = matcher.group( 1 );
|
||||
}
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return appVersion;
|
||||
}
|
||||
|
||||
public static String getAppName( Context context ) {
|
||||
if ( context == null ) {
|
||||
return "";
|
||||
}
|
||||
PackageManager pm = context.getPackageManager();
|
||||
return context.getApplicationInfo().loadLabel( pm ).toString();
|
||||
|
||||
}
|
||||
|
||||
public static String getModel() {
|
||||
String temp = Build.MODEL;
|
||||
return TextUtils.isEmpty( temp ) ? "" : temp;
|
||||
}
|
||||
|
||||
@TargetApi( Build.VERSION_CODES.JELLY_BEAN )
|
||||
public static long getLeftMemory( Context context ) {
|
||||
|
||||
if ( context == null ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( Build.VERSION.SDK_INT >= 16 ) {
|
||||
ActivityManager mActivityManager = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
|
||||
mActivityManager.getMemoryInfo( mi );
|
||||
return ( mi.totalMem - mi.availMem ) / 1000;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public static String encode( String string ) {
|
||||
try {
|
||||
return URLEncoder.encode( string, "UTF-8" );
|
||||
} catch ( UnsupportedEncodingException e ) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String decode( String string ) {
|
||||
try {
|
||||
return URLDecoder.decode( string, "UTF-8" );
|
||||
} catch ( UnsupportedEncodingException e ) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getProcessName( Context context, int pid ) {
|
||||
try {
|
||||
ActivityManager manager = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
|
||||
for ( ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses() ) {
|
||||
if ( processInfo.pid == pid ) {
|
||||
return processInfo.processName;
|
||||
}
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static int getStatusBarHeight( Context context ) {
|
||||
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int statusBarHeight = 0;
|
||||
try {
|
||||
Class c = Class.forName( "com.android.internal.R$dimen" );
|
||||
Object obj = c.newInstance();
|
||||
Field field = c.getField( "status_bar_height" );
|
||||
int x = Integer.parseInt( field.get( obj ).toString() );
|
||||
statusBarHeight = context.getResources().getDimensionPixelSize( x );
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
|
||||
if ( statusBarHeight > 0 ) {
|
||||
return statusBarHeight;
|
||||
}
|
||||
|
||||
try {
|
||||
int resourceId = context.getResources().getIdentifier( "status_bar_height", "dimen", "android" );
|
||||
if ( resourceId > 0 ) {
|
||||
statusBarHeight = context.getResources().getDimensionPixelSize( resourceId );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
|
||||
}
|
||||
|
||||
return statusBarHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个应用的版本名称
|
||||
*
|
||||
* @param context 应用上下文
|
||||
* @param packageName 包名,如果为空,将获取 context 本身的版本名称
|
||||
* @return
|
||||
*/
|
||||
public static String getVersionName( @NonNull Context context, @Nullable String packageName ) {
|
||||
try {
|
||||
packageName = TextUtils.isEmpty( packageName ) ? context.getPackageName() : packageName;
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packInfo = packageManager.getPackageInfo( packageName, 0 );
|
||||
return packInfo.versionName;
|
||||
} catch ( Exception e ) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个应用的版本号
|
||||
*
|
||||
* @param context 应用上下文
|
||||
* @param packageName 包名,如果为空,将获取 context 本身的版本号
|
||||
* @return
|
||||
*/
|
||||
public static int getVersionCode( @NonNull Context context, @Nullable String packageName ) {
|
||||
try {
|
||||
packageName = TextUtils.isEmpty( packageName ) ? context.getPackageName() : packageName;
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packInfo = packageManager.getPackageInfo( packageName, 0 );
|
||||
return packInfo.versionCode;
|
||||
} catch ( Exception e ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
|
||||
/**
|
||||
* Schedule a countdown until a time in the future, with
|
||||
* regular notifications on intervals along the way.
|
||||
*
|
||||
* Example of showing a 30 second countdown in a text field:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* new CountDownTimer(30000, 1000) {
|
||||
*
|
||||
* public void onTick(long millisUntilFinished) {
|
||||
* mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
|
||||
* }
|
||||
*
|
||||
* public void onFinish() {
|
||||
* mTextField.setText("done!");
|
||||
* }
|
||||
* }.start();
|
||||
* </pre>
|
||||
*
|
||||
* The calls to {@link #onTick(long)} are synchronized to this object so that
|
||||
* one call to {@link #onTick(long)} won't ever occur before the previous
|
||||
* callback is complete. This is only relevant when the implementation of
|
||||
* {@link #onTick(long)} takes an amount of time to execute that is significant
|
||||
* compared to the countdown interval.
|
||||
*/
|
||||
public abstract class CountDownTimer {
|
||||
|
||||
/**
|
||||
* Millis since epoch when alarm should stop.
|
||||
*/
|
||||
private final long mMillisInFuture;
|
||||
|
||||
/**
|
||||
* The interval in millis that the user receives callbacks
|
||||
*/
|
||||
private final long mCountdownInterval;
|
||||
|
||||
private long mStopTimeInFuture;
|
||||
|
||||
/**
|
||||
* boolean representing if the timer was cancelled
|
||||
*/
|
||||
private boolean mCancelled = false;
|
||||
|
||||
/**
|
||||
* @param millisInFuture The number of millis in the future from the call
|
||||
* to {@link #start()} until the countdown is done and {@link #onFinish()}
|
||||
* is called.
|
||||
* @param countDownInterval The interval along the way to receive
|
||||
* {@link #onTick(long)} callbacks.
|
||||
*/
|
||||
public CountDownTimer(long millisInFuture, long countDownInterval) {
|
||||
mMillisInFuture = millisInFuture;
|
||||
mCountdownInterval = countDownInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the countdown.
|
||||
*/
|
||||
public synchronized final void cancel() {
|
||||
mCancelled = true;
|
||||
mHandler.removeMessages(MSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the countdown.
|
||||
*/
|
||||
public synchronized final CountDownTimer start() {
|
||||
mCancelled = false;
|
||||
if (mMillisInFuture <= 0) {
|
||||
onFinish();
|
||||
return this;
|
||||
}
|
||||
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback fired on regular interval.
|
||||
* @param millisUntilFinished The amount of time until finished.
|
||||
*/
|
||||
public abstract void onTick(long millisUntilFinished);
|
||||
|
||||
/**
|
||||
* Callback fired when the time is up.
|
||||
*/
|
||||
public abstract void onFinish();
|
||||
|
||||
|
||||
private static final int MSG = 1;
|
||||
|
||||
|
||||
// handles counting down
|
||||
private Handler mHandler = new Handler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage( Message msg) {
|
||||
|
||||
synchronized (CountDownTimer.this) {
|
||||
if (mCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
|
||||
|
||||
if (millisLeft <= 0) {
|
||||
onFinish();
|
||||
} else if (millisLeft < mCountdownInterval) {
|
||||
// no tick, just delay until done
|
||||
sendMessageDelayed(obtainMessage(MSG), millisLeft);
|
||||
} else {
|
||||
long lastTickStart = SystemClock.elapsedRealtime();
|
||||
onTick(millisLeft);
|
||||
|
||||
// take into account user's onTick taking time to execute
|
||||
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
|
||||
|
||||
// special case: user's onTick took more than interval to
|
||||
// complete, skip to next interval
|
||||
while (delay < 0) delay += mCountdownInterval;
|
||||
|
||||
sendMessageDelayed(obtainMessage(MSG), delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DateTimeUtils {
|
||||
|
||||
public static final int DATETIME_FIELD_REFERSH = 10; // 刷新时间(分钟),
|
||||
//
|
||||
public static final long ONE_SECOND = 1000L;
|
||||
public static final long ONE_MINUTE = ONE_SECOND * 60L;
|
||||
public static final long ONE_HOUR = ONE_MINUTE * 60L;
|
||||
public static final long ONE_DAY = ONE_HOUR * 24L;
|
||||
public static final long ONE_MONTH = ONE_DAY * 24L;
|
||||
public static final long ONE_YEAR = ONE_MONTH * 24L;
|
||||
// 下面的pattern在print和parse时都可以使用
|
||||
public static final String MM_Yue_dd_Ri = "MM月dd日";
|
||||
public static final String MM_Yue_dd_Ri_HH_mm = "MM月dd日 HH:mm";
|
||||
public static final String M_Yue_d_Ri = "M月d日";
|
||||
public static final String d_Ri = "d日";
|
||||
public static final String yyyyMMdd = "yyyyMMdd";
|
||||
public static final String yyyy_MM_dd = "yyyy-MM-dd";
|
||||
public static final String yyyy_MM = "yyyy-MM";
|
||||
public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
|
||||
public static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
|
||||
public static final String HH_mm = "HH:mm";
|
||||
public static final String yyyy_Nian_MM_Yue_dd_Ri = "yyyy年MM月dd日";
|
||||
public static final String yyyy_Nian_MM_Yue = "yyyy年MM月";
|
||||
public static final String MM_yy = "MM/yy";
|
||||
public static final String dd_MM = "dd/MM";
|
||||
public static final String MM_dd = "MM-dd";
|
||||
private static final String pattern2 = "MM 月 dd";
|
||||
// 下面的pattern是print时用,parse时不应使用(只有时间,没有日期)
|
||||
public static final String HH_mm_ss = "HH:mm:ss";
|
||||
private static final String[] PATTERNS = {yyyy_MM_dd_HH_mm_ss, yyyy_MM_dd_HH_mm, yyyy_MM_dd, yyyyMMdd};
|
||||
|
||||
|
||||
public static Calendar cleanCalendarTime( Calendar c) {
|
||||
c.set( Calendar.HOUR_OF_DAY, 0);
|
||||
c.set( Calendar.MINUTE, 0);
|
||||
c.set( Calendar.SECOND, 0);
|
||||
c.set( Calendar.MILLISECOND, 0);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定日期表示格式转换成Calendar的格式
|
||||
*
|
||||
* @param src
|
||||
* @param fallback 若无法转换,返回一个默认值
|
||||
* @return
|
||||
*/
|
||||
public static <T> Calendar getCalendar( T src, Calendar fallback) {
|
||||
if (src != null) {
|
||||
try {
|
||||
return getCalendar(src);
|
||||
} catch ( Exception e) {
|
||||
}
|
||||
}
|
||||
return ( Calendar ) fallback.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得日期类型
|
||||
*
|
||||
* @param src 任何可以表示时间的类型,目前支持Calendar,Date,long,String
|
||||
* @return Calendar类型表示的时间
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static <T> Calendar getCalendar( T src) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setLenient(false);
|
||||
if (src == null) {
|
||||
return null;
|
||||
} else if (src instanceof Calendar ) {
|
||||
calendar.setTimeInMillis((( Calendar ) src).getTimeInMillis());
|
||||
} else if (src instanceof Date ) {
|
||||
calendar.setTime(( Date ) src);
|
||||
} else if (src instanceof Long ) {
|
||||
calendar.setTimeInMillis(( Long ) src);
|
||||
} else if (src instanceof String ) {
|
||||
String nSrc = ( String ) src;
|
||||
if ( TextUtils.isEmpty(nSrc)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// 直接匹配的时候不能匹配到月份或日期不是2位数的情况
|
||||
if ( Pattern.compile("\\d{4}年\\d{1,2}月\\d{1,2}日").matcher(nSrc).find()) {
|
||||
nSrc = fixDateString(nSrc);
|
||||
return getCalendarByPattern(nSrc, yyyy_MM_dd);
|
||||
}
|
||||
return getCalendarByPatterns(nSrc, PATTERNS);
|
||||
} catch ( Exception e) {
|
||||
try {
|
||||
calendar.setTimeInMillis( Long.valueOf(nSrc));
|
||||
} catch ( NumberFormatException e1) {
|
||||
throw new IllegalArgumentException(e1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return calendar;
|
||||
}
|
||||
|
||||
/**
|
||||
* YYYY年MM月DD日 --> YYYY-MM-DD
|
||||
*/
|
||||
private static String fixDateString( String date) {
|
||||
if ( TextUtils.isEmpty(date)) {
|
||||
return date;
|
||||
}
|
||||
|
||||
String[] dateArray = date.split("[年月日]");
|
||||
if (dateArray.length == 1) {
|
||||
dateArray = date.split("-");
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (dateArray[i].length() == 1) {
|
||||
dateArray[i] = "0" + dateArray[i];
|
||||
}
|
||||
}
|
||||
return dateArray[0] + "-" + dateArray[1] + "-" + dateArray[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配pattern获得时间,若无法解析抛出异常
|
||||
*
|
||||
* @param dateTimeStr
|
||||
* @param patternStr
|
||||
* @return
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static Calendar getCalendarByPattern( String dateTimeStr, String patternStr) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(patternStr, Locale.US);
|
||||
sdf.setLenient(false);
|
||||
Date d = sdf.parse(dateTimeStr);
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setLenient(false);
|
||||
c.setTimeInMillis(d.getTime());
|
||||
return c;
|
||||
} catch ( Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配pattern数组中的所有pattern解析时间格式,若没有可以解析的方式则抛出异常
|
||||
*
|
||||
* @param dateTimeStr
|
||||
* @param patternStr
|
||||
* @return
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static Calendar getCalendarByPatterns( String dateTimeStr, String[] patternStr) {
|
||||
for ( String string : patternStr) {
|
||||
try {
|
||||
return getCalendarByPattern(dateTimeStr, string);
|
||||
} catch ( Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有服务器时间
|
||||
*/
|
||||
public static boolean hasServerTime;
|
||||
/**
|
||||
* 本地时间和服务器时间的间隔 time server local gap millis
|
||||
*/
|
||||
public static long tslgapm;
|
||||
/**
|
||||
* 本地时间和服务器时间的间隔 time server string
|
||||
*/
|
||||
public static String tss;
|
||||
|
||||
/**
|
||||
* 获取与服务器时间矫正过的当前时间
|
||||
*/
|
||||
public static Calendar getCurrentDateTime() {
|
||||
Calendar now = Calendar.getInstance();
|
||||
now.setLenient(false);
|
||||
if (hasServerTime) {
|
||||
now.setTimeInMillis(now.getTimeInMillis() + tslgapm);
|
||||
}
|
||||
return now;
|
||||
}
|
||||
|
||||
public static Calendar getCurrentDate() {
|
||||
return cleanCalendarTime(getCurrentDateTime());
|
||||
}
|
||||
|
||||
public static long getCurTimeInMillis(){
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* login时server的日期
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Calendar getLoginServerDate() {
|
||||
return getCalendar(tss);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得基准日期增加间隔天
|
||||
*/
|
||||
public static Calendar getDateAdd( Calendar start, int interval) {
|
||||
if (start == null) {
|
||||
return null;
|
||||
}
|
||||
Calendar c = ( Calendar ) start.clone();
|
||||
c.add( Calendar.DATE, interval);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得时间间隔
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
* @param unit 时间间隔单位{@link DateTimeUtils#ONE_SECOND},{@link DateTimeUtils#ONE_MINUTE},
|
||||
* {@link DateTimeUtils#ONE_HOUR}, {@link DateTimeUtils#ONE_DAY}
|
||||
* @return
|
||||
*/
|
||||
public static long getIntervalTimes( Calendar from, Calendar to, long unit) {
|
||||
if (from == null || to == null) {
|
||||
return 0;
|
||||
}
|
||||
return Math.abs(from.getTimeInMillis() - to.getTimeInMillis()) / unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得日期间隔 忽略小时
|
||||
*
|
||||
* @param startdate
|
||||
* @param enddate
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static int getIntervalDays( String startdate, String enddate, String pattern) {
|
||||
int betweenDays = 0;
|
||||
if (startdate == null || enddate == null) {
|
||||
return betweenDays;
|
||||
}
|
||||
|
||||
Calendar d1 = getCalendarByPattern(startdate, pattern);
|
||||
Calendar d2 = getCalendarByPattern(enddate, pattern);
|
||||
|
||||
return getIntervalDays(d1, d2);
|
||||
}
|
||||
|
||||
public static <T> int getIntervalDays(T from, T to) {
|
||||
Calendar startdate = getCalendar(from);
|
||||
Calendar enddate = getCalendar(to);
|
||||
cleanCalendarTime(startdate);
|
||||
cleanCalendarTime(enddate);
|
||||
return (int) getIntervalTimes(startdate, enddate, ONE_DAY);
|
||||
}
|
||||
|
||||
private static String[] weekdays = {"", "周日", "周一", "周二", "周三", "周四", "周五", "周六",};
|
||||
private static String[] weekdays1 = {"", "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六",};
|
||||
|
||||
/**
|
||||
* calendar --> 周一~周日
|
||||
*/
|
||||
public static String getWeekDayFromCalendar( Calendar cal) {
|
||||
if (cal == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return weekdays[cal.get( Calendar.DAY_OF_WEEK)];
|
||||
}
|
||||
|
||||
/**
|
||||
* calendar --> 星期日~星期六
|
||||
*/
|
||||
public static String getWeekDayFromCalendar1( Calendar cal) {
|
||||
if (cal == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return weekdays1[cal.get( Calendar.DAY_OF_WEEK)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是闰年 这个方法不要改动!
|
||||
*
|
||||
* @param date(2009-10-13 || 2009年10月13日 || 2009)
|
||||
* @return true 是 false 不是
|
||||
*/
|
||||
public static boolean isLeapyear( String date) {
|
||||
Calendar calendar = getCalendar(date);
|
||||
if (calendar != null) {
|
||||
int year = calendar.get( Calendar.YEAR);
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否到刷新时间
|
||||
public static boolean isRefersh(long beforeTime) {
|
||||
return isRefersh(DATETIME_FIELD_REFERSH * 1000 * 60, beforeTime);
|
||||
}
|
||||
|
||||
// 是否到刷新时间
|
||||
public static boolean isRefersh(long gap, long beforeTime) {
|
||||
return new Date().getTime() - beforeTime >= gap;
|
||||
}
|
||||
|
||||
public static String printCalendarByPattern( Calendar c, String patternStr) {
|
||||
if (null == c || null == patternStr) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(patternStr, Locale.US);
|
||||
sdf.setLenient(false);
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 只通过年月日比较两个Calendar
|
||||
*
|
||||
* @return c1 < c2 = -1 ; c1 > c2 = 1 ; c1 == c2 = 0
|
||||
*/
|
||||
public static int compareCalendarIgnoreTime( Calendar c1, Calendar c2) {
|
||||
if (c1.get( Calendar.YEAR) > c2.get( Calendar.YEAR)) {
|
||||
return 1;
|
||||
} else if (c1.get( Calendar.YEAR) < c2.get( Calendar.YEAR)) {
|
||||
return -1;
|
||||
} else {
|
||||
if (c1.get( Calendar.MONTH) > c2.get( Calendar.MONTH)) {
|
||||
return 1;
|
||||
} else if (c1.get( Calendar.MONTH) < c2.get( Calendar.MONTH)) {
|
||||
return -1;
|
||||
} else {
|
||||
if (c1.get( Calendar.DAY_OF_MONTH) > c2.get( Calendar.DAY_OF_MONTH)) {
|
||||
return 1;
|
||||
} else if (c1.get( Calendar.DAY_OF_MONTH) < c2.get( Calendar.DAY_OF_MONTH)) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setTimeWithHHmm( Calendar src, String HH_mm) {
|
||||
if ( TextUtils.isEmpty(HH_mm) || null == src) {
|
||||
return;
|
||||
}
|
||||
String s[] = HH_mm.split(":");
|
||||
if (s.length != 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
cleanCalendarTime(src);
|
||||
src.set( Calendar.HOUR_OF_DAY, Integer.valueOf(s[0]));
|
||||
src.set( Calendar.MINUTE, Integer.valueOf(s[1]));
|
||||
} catch ( NumberFormatException e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int getDayDiff(long time1, long time2) {
|
||||
Date dateA = new Date(time1);
|
||||
Date dateB = new Date(time2);
|
||||
Calendar calDateA = Calendar.getInstance();
|
||||
calDateA.setTime(dateA);
|
||||
Calendar calDateB = Calendar.getInstance();
|
||||
calDateB.setTime(dateB);
|
||||
|
||||
if (calDateA.get( Calendar.YEAR) == calDateB.get( Calendar.YEAR)
|
||||
&& calDateA.get( Calendar.MONTH) == calDateB.get( Calendar.MONTH)) {
|
||||
return calDateB.get( Calendar.DAY_OF_MONTH) - calDateA.get( Calendar.DAY_OF_MONTH);
|
||||
} else if (calDateA.get( Calendar.YEAR) == calDateB.get( Calendar.YEAR) && ((calDateB.get( Calendar.MONTH) - calDateA.get( Calendar.MONTH)) == 1
|
||||
|| (calDateB.get( Calendar.MONTH) - calDateA.get( Calendar.MONTH)) == -11)) {//处理跨年情况
|
||||
return calDateB.get( Calendar.DAY_OF_MONTH) + (getCurrentMonthLastDay() - calDateA.get( Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getCurrentMonthLastDay() {
|
||||
Calendar a = Calendar.getInstance();
|
||||
a.set( Calendar.DATE, 1);
|
||||
a.roll( Calendar.DATE, -1);
|
||||
int maxDate = a.get( Calendar.DATE);
|
||||
return maxDate;
|
||||
}
|
||||
|
||||
public static String convertToChineseWeekNumber( int number) {
|
||||
switch (number) {
|
||||
case 1:
|
||||
return "一";
|
||||
case 2:
|
||||
return "二";
|
||||
case 3:
|
||||
return "三";
|
||||
case 4:
|
||||
return "四";
|
||||
case 5:
|
||||
return "五";
|
||||
case 6:
|
||||
return "六";
|
||||
case 0:
|
||||
return "日";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分钟数
|
||||
*/
|
||||
private static int getMinutes( String str, int blankCount) {
|
||||
int ret = 0;
|
||||
if (str.split(" ").length < (blankCount + 1)) {
|
||||
return ret;
|
||||
}
|
||||
String hh_mm = str.split(" ")[blankCount];
|
||||
|
||||
String s = "";
|
||||
if (!TextUtils.isEmpty(hh_mm) && hh_mm.length() >= 4) {
|
||||
s = hh_mm.substring(3);
|
||||
}
|
||||
try {
|
||||
ret = Integer.parseInt(s);
|
||||
} catch ( NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 06月07 格式的日期
|
||||
* @param timestamp 时间戳
|
||||
* @return
|
||||
*/
|
||||
public static String getTimeText( long timestamp) {
|
||||
SimpleDateFormat format = new SimpleDateFormat(yyyy_Nian_MM_Yue_dd_Ri, Locale.US);
|
||||
String strStart = format.format(new Date(timestamp));
|
||||
return strStart;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
|
||||
import com.mogo.utils.storage.SharedPrefsMgr;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public final class DeviceIdUtils {
|
||||
|
||||
public static final String KEY_DEVICE_ID = "deviceId";
|
||||
|
||||
private DeviceIdUtils() {}
|
||||
|
||||
private static void saveDeviceId( Context context, String deviceId){
|
||||
SharedPrefsMgr.getInstance(context).putString(KEY_DEVICE_ID, deviceId);
|
||||
}
|
||||
|
||||
public static String getDeviceId( Context context) {
|
||||
if(context == null){
|
||||
throw new NullPointerException("context must not be null.");
|
||||
}
|
||||
|
||||
final Context appContext = context.getApplicationContext();
|
||||
String deviceId = SharedPrefsMgr.getInstance( context ).getString( KEY_DEVICE_ID );
|
||||
|
||||
if ( TextUtils.isEmpty( deviceId )) {
|
||||
deviceId = getDeviceIdInternal(appContext);
|
||||
if (!TextUtils.isEmpty(deviceId)) {
|
||||
saveDeviceId(appContext,deviceId);
|
||||
} else {
|
||||
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
|
||||
if ( ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE ) == PackageManager.PERMISSION_GRANTED ) {
|
||||
deviceId = (( TelephonyManager ) appContext.getSystemService( Context.TELEPHONY_SERVICE)).getSimSerialNumber();
|
||||
}
|
||||
}else{
|
||||
deviceId = (( TelephonyManager ) appContext.getSystemService( Context.TELEPHONY_SERVICE)).getSimSerialNumber();
|
||||
}
|
||||
if (!TextUtils.isEmpty(deviceId)) {
|
||||
saveDeviceId(appContext,deviceId);
|
||||
} else {
|
||||
deviceId = getDeviceSerial();
|
||||
if (!TextUtils.isEmpty(deviceId) && !deviceId.equalsIgnoreCase("unknown")) {
|
||||
saveDeviceId(appContext,deviceId);
|
||||
} else {
|
||||
deviceId = getAndroidId(appContext);
|
||||
if (!TextUtils.isEmpty(deviceId)) {
|
||||
saveDeviceId(appContext,deviceId);
|
||||
} else {
|
||||
deviceId = String.valueOf( System.currentTimeMillis());
|
||||
saveDeviceId(appContext,deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
private static String getDeviceIdInternal( Context context) {
|
||||
String id = "";
|
||||
|
||||
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
|
||||
if ( ContextCompat.checkSelfPermission( context, Manifest.permission.READ_PHONE_STATE ) != PackageManager.PERMISSION_GRANTED ) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
TelephonyManager telephonymanager = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE);
|
||||
if (telephonymanager != null) {
|
||||
id = telephonymanager.getDeviceId();
|
||||
if ( TextUtils.isEmpty(id))
|
||||
id = "";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private static String getAndroidId( Context context) {
|
||||
String s = "";
|
||||
s = Settings.Secure.getString(context.getContentResolver(), "android_id");
|
||||
if ( TextUtils.isEmpty(s))
|
||||
s = "";
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String getDeviceSerial() {
|
||||
String serial = "unknown";
|
||||
try {
|
||||
Class clazz = Class.forName("android.os.Build");
|
||||
Class paraTypes = Class.forName("java.lang.String");
|
||||
Method method = clazz.getDeclaredMethod("getString", paraTypes);
|
||||
if (!method.isAccessible()) {
|
||||
method.setAccessible(true);
|
||||
}
|
||||
serial = ( String ) method.invoke(new Build(), "ro.serialno");
|
||||
} catch ( ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch ( NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch ( InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch ( IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
|
||||
public class FileUtils {
|
||||
public static boolean createFileDir( String fileDir ) {
|
||||
|
||||
if ( TextUtils.isEmpty( fileDir ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
File dir = new File( fileDir );
|
||||
return dir.exists() || dir.mkdir();
|
||||
} catch ( Exception e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean createFileDir( File dir ) {
|
||||
if ( dir == null ) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return dir.exists() || dir.mkdir();
|
||||
} catch ( Exception e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeToFile( String fileDir, String fileName, String content ) {
|
||||
if ( fileDir == null || fileName == null || content == null ) {
|
||||
return;
|
||||
}
|
||||
if ( !createFileDir( fileDir ) ) {
|
||||
return;
|
||||
}
|
||||
FileOutputStream fos = null;
|
||||
OutputStreamWriter osw = null;
|
||||
try {
|
||||
fos = new FileOutputStream( fileDir + fileName, true );
|
||||
osw = new OutputStreamWriter( fos );
|
||||
osw.write( content );
|
||||
osw.flush();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( fos );
|
||||
IOUtils.closeSilently( osw );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a text file into a String, optionally limiting the length.
|
||||
*/
|
||||
public static String readTextFile( File file ) {
|
||||
InputStream is = null;
|
||||
BufferedInputStream bis = null;
|
||||
ByteArrayOutputStream bos = null;
|
||||
String text = null;
|
||||
try {
|
||||
is = new FileInputStream( file );
|
||||
bis = new BufferedInputStream( is );
|
||||
bos = new ByteArrayOutputStream();
|
||||
int len;
|
||||
byte[] data = new byte[1024];
|
||||
do {
|
||||
len = bis.read( data );
|
||||
if ( len > 0 ) bos.write( data, 0, len );
|
||||
} while ( len == data.length );
|
||||
text = bos.toString();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( is );
|
||||
IOUtils.closeSilently( bis );
|
||||
IOUtils.closeSilently( bos );
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static String fileToBase64( File file ) {
|
||||
String base64 = null;
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream( file );
|
||||
byte[] bytes = new byte[in.available()];
|
||||
int length = in.read( bytes );
|
||||
base64 = Base64.encodeToString( bytes, 0, length, Base64.DEFAULT );
|
||||
} catch ( FileNotFoundException e ) {
|
||||
e.printStackTrace();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( in );
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes string to file. Basically same as "echo -n $string > $filename"
|
||||
*/
|
||||
public static void stringToFile( String filename, String string ) {
|
||||
FileWriter out = null;
|
||||
try {
|
||||
out = new FileWriter( filename );
|
||||
out.write( string );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( out );
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream stringToStream( String content ) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new ByteArrayInputStream( content.getBytes() );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public static String streamToString( InputStream is ) throws IOException {
|
||||
String content = null;
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
int i = -1;
|
||||
while ( ( i = is.read() ) != -1 ) {
|
||||
bos.write( i );
|
||||
}
|
||||
content = bos.toString();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public static String getStringFromFile( Context context, String fileName ) {
|
||||
FileInputStream fis = null;
|
||||
ByteArrayOutputStream os = null;
|
||||
String content = null;
|
||||
try {
|
||||
fis = context.openFileInput( fileName );
|
||||
os = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = -1;
|
||||
while ( ( length = fis.read( buffer ) ) != -1 ) {
|
||||
os.write( buffer, 0, length );
|
||||
}
|
||||
content = os.toString();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( fis );
|
||||
IOUtils.closeSilently( os );
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public static InputStream getStreamFromFile( Context context, String fileName ) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = context.openFileInput( fileName );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return fis;
|
||||
}
|
||||
|
||||
public static void saveStringToFile( Context context, String content, String fileName ) {
|
||||
try {
|
||||
FileOutputStream fos = context.openFileOutput( fileName, Context.MODE_PRIVATE );
|
||||
fos.write( content.getBytes() );
|
||||
IOUtils.closeSilently( fos );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将scheme为file的uri转成FileProvider 提供的content uri
|
||||
*/
|
||||
public static Uri convertFileUriToFileProviderUri( Context context, Uri uri ) {
|
||||
if ( uri == null ) return null;
|
||||
if ( ContentResolver.SCHEME_FILE.equals( uri.getScheme() ) ) {
|
||||
return getUriForFile( context, new File( uri.getPath() ) );
|
||||
}
|
||||
return uri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个用于拍照图片输出路径的Uri (FileProvider)
|
||||
*/
|
||||
public static Uri getUriForFile( Context context, File file ) {
|
||||
return FileProvider.getUriForFile( context, getFileProviderName( context ), file );
|
||||
}
|
||||
|
||||
public static String getFileProviderName( Context context ) {
|
||||
return context.getPackageName() + ".fileprovider";
|
||||
}
|
||||
|
||||
/**
|
||||
* 把Uri 解析出文件绝对路径
|
||||
*/
|
||||
public static String parseOwnUri( Context context, Uri uri ) {
|
||||
if ( uri == null ) return null;
|
||||
String path;
|
||||
if ( TextUtils.equals( uri.getAuthority(), getFileProviderName( context ) ) ) {
|
||||
path = new File( uri.getPath() ).getAbsolutePath();
|
||||
} else {
|
||||
path = uri.getPath();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static String getFileStreamPath( Context context, String name ) {
|
||||
String absFileName = null;
|
||||
try {
|
||||
File file = context.getFileStreamPath( name );
|
||||
if ( file != null && file.exists() ) {
|
||||
absFileName = file.getAbsolutePath();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return absFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class IOUtils {
|
||||
|
||||
public static byte[] inputToBytes( InputStream is) {
|
||||
if(is == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = null;
|
||||
byte[] result = null;
|
||||
|
||||
try{
|
||||
bos = new ByteArrayOutputStream();
|
||||
byte[] buff = new byte[100];
|
||||
int rc = 0;
|
||||
while ((rc = is.read(buff, 0, 100)) > 0) {
|
||||
bos.write(buff, 0, rc);
|
||||
}
|
||||
|
||||
result = bos.toByteArray();
|
||||
}catch ( Exception e){
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
}finally {
|
||||
closeSilently(bos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void closeSilently(@Nullable Closeable c) {
|
||||
if (c == null) return;
|
||||
try {
|
||||
c.close();
|
||||
c = null;
|
||||
} catch ( Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class IntentUtils {
|
||||
|
||||
/**
|
||||
* urlDecode的时候会把'+'转换成' '
|
||||
*
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public static TreeMap< String, String > splitParams2( Uri uri) {
|
||||
if (uri == null) {
|
||||
return new TreeMap< String, String >();
|
||||
}
|
||||
Set< String > keys = getQueryParameterNames(uri);
|
||||
TreeMap< String, String > map = new TreeMap< String, String >();
|
||||
|
||||
for ( String key : keys) {
|
||||
map.put(key, getQueryParameter(uri, key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* urlDecode时 <br />
|
||||
* 4.0版本以后 '+' ->' ' <br />
|
||||
* 2.3版本之前 '+' -> '+'<br />
|
||||
*
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public static HashMap< String, String > splitParams1( Uri uri) {
|
||||
if (uri == null) {
|
||||
return new HashMap< String, String >();
|
||||
}
|
||||
Set< String > keys = getQueryParameterNames(uri);
|
||||
HashMap< String, String > map = new HashMap< String, String >(keys.size());
|
||||
|
||||
for ( String key : keys) {
|
||||
map.put(key, uri.getQueryParameter(key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the query string for the first value with the given key.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Warning:</strong> this decoded the '+' character as ' '.
|
||||
*
|
||||
* @param key which will be encoded
|
||||
* @throws UnsupportedOperationException if this isn't a hierarchical URI
|
||||
* @throws NullPointerException if key is null
|
||||
* @return the decoded value or null if no parameter is found
|
||||
*/
|
||||
public static String getQueryParameter( Uri uri, String key) {
|
||||
if (uri.isOpaque()) {
|
||||
throw new UnsupportedOperationException("This isn't a hierarchical URI.");
|
||||
}
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
final String query = uri.getEncodedQuery();
|
||||
if (query == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String encodedKey = Uri.encode(key, null);
|
||||
final int length = query.length();
|
||||
int start = 0;
|
||||
do {
|
||||
int nextAmpersand = query.indexOf('&', start);
|
||||
int end = nextAmpersand != -1 ? nextAmpersand : length;
|
||||
|
||||
int separator = query.indexOf('=', start);
|
||||
if (separator > end || separator == -1) {
|
||||
separator = end;
|
||||
}
|
||||
|
||||
if (separator - start == encodedKey.length()
|
||||
&& query.regionMatches(start, encodedKey, 0, encodedKey.length())) {
|
||||
if (separator == end) {
|
||||
return "";
|
||||
} else {
|
||||
String encodedValue = query.substring(separator + 1, end);
|
||||
return UriCodec.decode(encodedValue, true, UriCodec.UTF_8, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Move start to end of name.
|
||||
if (nextAmpersand != -1) {
|
||||
start = nextAmpersand + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Set< String > getQueryParameterNames( Uri uri) {
|
||||
if (uri.isOpaque()) {
|
||||
throw new UnsupportedOperationException("This isn't a hierarchical URI.");
|
||||
}
|
||||
|
||||
String query = uri.getEncodedQuery();
|
||||
if (query == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set< String > names = new LinkedHashSet< String >();
|
||||
int start = 0;
|
||||
do {
|
||||
int next = query.indexOf('&', start);
|
||||
int end = next == -1 ? query.length() : next;
|
||||
|
||||
int separator = query.indexOf('=', start);
|
||||
if (separator > end || separator == -1) {
|
||||
separator = end;
|
||||
}
|
||||
|
||||
String name = query.substring(start, separator);
|
||||
names.add( Uri.decode(name));
|
||||
|
||||
// Move start to end of name.
|
||||
start = end + 1;
|
||||
} while (start < query.length());
|
||||
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes and decodes {@code application/x-www-form-urlencoded} content. Subclasses define exactly which characters
|
||||
* are legal.
|
||||
*
|
||||
* <p>
|
||||
* By default, UTF-8 is used to encode escaped characters. A single input character like "\u0080" may be encoded to
|
||||
* multiple octets like %C2%80.
|
||||
*/
|
||||
abstract static class UriCodec {
|
||||
|
||||
/**
|
||||
* Returns true if {@code c} does not need to be escaped.
|
||||
*/
|
||||
protected abstract boolean isRetained(char c);
|
||||
|
||||
/**
|
||||
* Throws if {@code s} is invalid according to this encoder.
|
||||
*/
|
||||
public final String validate( String uri, int start, int end, String name) throws URISyntaxException {
|
||||
for (int i = start; i < end;) {
|
||||
char ch = uri.charAt(i);
|
||||
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || isRetained(ch)) {
|
||||
i++;
|
||||
} else if (ch == '%') {
|
||||
if (i + 2 >= end) {
|
||||
throw new URISyntaxException(uri, "Incomplete % sequence in " + name, i);
|
||||
}
|
||||
int d1 = hexToInt(uri.charAt(i + 1));
|
||||
int d2 = hexToInt(uri.charAt(i + 2));
|
||||
if (d1 == -1 || d2 == -1) {
|
||||
throw new URISyntaxException(uri, "Invalid % sequence: " + uri.substring(i, i + 3) + " in "
|
||||
+ name, i);
|
||||
}
|
||||
i += 3;
|
||||
} else {
|
||||
throw new URISyntaxException(uri, "Illegal character in " + name, i);
|
||||
}
|
||||
}
|
||||
return uri.substring(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if {@code s} contains characters that are not letters, digits or in {@code legal}.
|
||||
*/
|
||||
public static void validateSimple( String s, String legal) throws URISyntaxException {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
if (!(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || legal.indexOf(ch) > -1)) {
|
||||
throw new URISyntaxException(s, "Illegal character", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes {@code s} and appends the orderList to {@code builder}.
|
||||
*
|
||||
* @param isPartiallyEncoded true to fix input that has already been partially or fully encoded. For example,
|
||||
* input of "hello%20world" is unchanged with isPartiallyEncoded=true but would be double-escaped to
|
||||
* "hello%2520world" otherwise.
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private void appendEncoded( StringBuilder builder, String s, Charset charset, boolean isPartiallyEncoded)
|
||||
throws UnsupportedEncodingException {
|
||||
if (s == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
int escapeStart = -1;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || isRetained(c) || c == '%'
|
||||
&& isPartiallyEncoded) {
|
||||
if (escapeStart != -1) {
|
||||
appendHex(builder, s.substring(escapeStart, i), charset);
|
||||
escapeStart = -1;
|
||||
}
|
||||
if (c == '%' && isPartiallyEncoded) {
|
||||
// this is an encoded 3-character sequence like "%20"
|
||||
builder.append(s, i, i + 3);
|
||||
i += 2;
|
||||
} else if (c == ' ') {
|
||||
builder.append('+');
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
} else if (escapeStart == -1) {
|
||||
escapeStart = i;
|
||||
}
|
||||
}
|
||||
if (escapeStart != -1) {
|
||||
appendHex(builder, s.substring(escapeStart, s.length()), charset);
|
||||
}
|
||||
}
|
||||
|
||||
public final String encode( String s, Charset charset) throws UnsupportedEncodingException {
|
||||
// Guess a bit larger for encoded form
|
||||
StringBuilder builder = new StringBuilder(s.length() + 16);
|
||||
appendEncoded(builder, s, charset, false);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
public final void appendEncoded( StringBuilder builder, String s) throws UnsupportedEncodingException {
|
||||
appendEncoded(builder, s, UTF_8, false);
|
||||
}
|
||||
|
||||
public final void appendPartiallyEncoded( StringBuilder builder, String s) throws UnsupportedEncodingException {
|
||||
appendEncoded(builder, s, UTF_8, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param convertPlus true to convert '+' to ' '.
|
||||
* @param throwOnFailure true to throw an IllegalArgumentException on invalid escape sequences; false to replace
|
||||
* them with the replacement character (U+fffd).
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static String decode( String s, boolean convertPlus, Charset charset, boolean throwOnFailure) {
|
||||
if (s.indexOf('%') == -1 && (!convertPlus || s.indexOf('+') == -1)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder(s.length());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();;
|
||||
try {
|
||||
for (int i = 0; i < s.length();) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '%') {
|
||||
do {
|
||||
int d1, d2;
|
||||
if (i + 2 < s.length() && (d1 = hexToInt(s.charAt(i + 1))) != -1
|
||||
&& (d2 = hexToInt(s.charAt(i + 2))) != -1) {
|
||||
out.write((byte) ((d1 << 4) + d2));
|
||||
} else if (throwOnFailure) {
|
||||
throw new IllegalArgumentException("Invalid % sequence at " + i + ": " + s);
|
||||
} else {
|
||||
byte[] replacement = "\ufffd".getBytes(charset.name());
|
||||
out.write(replacement, 0, replacement.length);
|
||||
}
|
||||
i += 3;
|
||||
} while (i < s.length() && s.charAt(i) == '%');
|
||||
result.append(new String(out.toByteArray(), charset.name()));
|
||||
out.reset();
|
||||
} else {
|
||||
if (convertPlus && c == '+') {
|
||||
c = ' ';
|
||||
}
|
||||
result.append(c);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} catch ( UnsupportedEncodingException e) {
|
||||
Log.e("IntentUtils",e.getMessage());
|
||||
}finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch ( IOException e) {
|
||||
Log.e("IntentUtils",e.getMessage());
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link Character#digit}, but without support for non-ASCII characters.
|
||||
*/
|
||||
private static int hexToInt(char c) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
return 10 + c - 'a';
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
return 10 + c - 'A';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static String decode( String s) throws UnsupportedEncodingException {
|
||||
return decode(s, false, UTF_8, true);
|
||||
}
|
||||
|
||||
private static void appendHex( StringBuilder builder, String s, Charset charset)
|
||||
throws UnsupportedEncodingException {
|
||||
for (byte b : s.getBytes(charset.name())) {
|
||||
appendHex(builder, b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendHex( StringBuilder sb, byte b) {
|
||||
sb.append('%');
|
||||
sb.append(byteToHexString(b, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* The digits for every supported radix.
|
||||
*/
|
||||
private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z' };
|
||||
|
||||
private static final char[] UPPER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z' };
|
||||
|
||||
public static String byteToHexString( byte b, boolean upperCase) {
|
||||
char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
|
||||
char[] buf = new char[2]; // We always want two digits.
|
||||
buf[0] = digits[b >> 4 & 0xf];
|
||||
buf[1] = digits[b & 0xf];
|
||||
return new String(buf, 0, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by congtaowang on 2018/11/20.
|
||||
*/
|
||||
public class MapUtils {
|
||||
|
||||
public static void putNotAllowNull( final Map< String, Object > target, final String key, final Object value ) {
|
||||
if ( target != null && key != null && value != null ) {
|
||||
target.put( key, value );
|
||||
}
|
||||
}
|
||||
|
||||
public static void putAllNotAllowNull( final Map< String, Object > target, final Map< String, Object > source ) {
|
||||
if ( target != null && source != null && !source.isEmpty() ) {
|
||||
final Set< String > keys = source.keySet();
|
||||
for ( String key : keys ) {
|
||||
putNotAllowNull( target, key, source.get( key ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* 创建日期:2012-10-9
|
||||
*/
|
||||
package com.mogo.utils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MatcherUtils {
|
||||
/**
|
||||
* 匹配:Email地址
|
||||
*/
|
||||
public static final String REGEX_EMAIL = "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";
|
||||
/**
|
||||
* 匹配:手机号码
|
||||
*/
|
||||
public static final String REGEX_MOBILE_NUMBER = "^[1][3-9]\\d{9}$";
|
||||
|
||||
/**
|
||||
* 正则表达式中使用的特殊的计算符号,如:'$', '*', ...
|
||||
*/
|
||||
public static final char[] PATTERN_REGEX_SPECIAL_CHARACTERS = { '$', // 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$。
|
||||
'(', ')', // 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
|
||||
'*', // 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
|
||||
'+', // 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
|
||||
'.', // 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
|
||||
'[', // 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
|
||||
'?', // 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
|
||||
'\\', // 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
|
||||
'^', // 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
|
||||
'{', // 标记限定符表达式的开始。要匹配 {,请使用 \{。
|
||||
'|', // 指明两项之间的一个选择。要匹配 |,请使用 \|。
|
||||
};
|
||||
|
||||
/** 英文标点符号 */
|
||||
private static final int TYPE_PUNCT = 1;
|
||||
/** 数字 */
|
||||
private static final int TYPE_DIGIT = 2;
|
||||
/** 小写字母字符 */
|
||||
private static final int TYPE_LOWER_LETTER = 3;
|
||||
/** 大写字母字符 */
|
||||
private static final int TYPE_UPPER_LETTER = 4;
|
||||
/** 汉字字符串包括了中文标点符号 */
|
||||
private static final int TYPE_CJK = 5;
|
||||
/** 汉字字符串剔除了中文标点符号 */
|
||||
private static final int TYPE_NO_PUNCTUATION_CJK = 6;
|
||||
/** 是否是空白字符 */
|
||||
private static final int TYPE_WHITESPACE = 7;
|
||||
/** 不是字母 数字 英文标点符号 */
|
||||
private static final int TYPE_NOT_PUNCT_DIGIT_LETTER = 8;
|
||||
|
||||
private static boolean isMatchesChar(int type, char ch) {
|
||||
switch (type) {
|
||||
case TYPE_PUNCT:
|
||||
return isPunct(ch);
|
||||
case TYPE_DIGIT:
|
||||
return Character.isDigit(ch);
|
||||
case TYPE_LOWER_LETTER:
|
||||
return isLowerLetter(ch);
|
||||
case TYPE_UPPER_LETTER:
|
||||
return isUpperLetter(ch);
|
||||
case TYPE_CJK:
|
||||
return isCJK(ch);
|
||||
case TYPE_NO_PUNCTUATION_CJK:
|
||||
return isNoPunctuationCJK(ch);
|
||||
case TYPE_WHITESPACE:
|
||||
return Character.isWhitespace(ch);
|
||||
case TYPE_NOT_PUNCT_DIGIT_LETTER:
|
||||
return !( Character.isDigit(ch) || isLowerLetter(ch) || isUpperLetter(ch) || isPunct(ch));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMatches(int type, String input) {
|
||||
if (input != null && input.length() > 0) {
|
||||
for (int i = input.length() - 1; i >= 0; i--) {
|
||||
if (!isMatchesChar(type, input.charAt(i))) {
|
||||
return false;
|
||||
} else if (i == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isMatchesInclude(int type, String input) {
|
||||
if (input != null && input.length() > 0) {
|
||||
for (int i = input.length() - 1; i >= 0; i--) {
|
||||
if (isMatchesChar(type, input.charAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配正则表达式
|
||||
*
|
||||
* @param regex
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMatches( String regex, String input) {
|
||||
return input == null ? false : Pattern.compile(regex).matcher(input).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配正则表达式(忽略大小写)
|
||||
*
|
||||
* @param regex
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMatchesIgnoreCase( String regex, String input) {
|
||||
return input == null ? false : Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(input).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是正则表达式中使用的特殊的计算符号,如:'$', '*', ...
|
||||
*
|
||||
* @param ch
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPatternRegexSpecialCharacter(char ch) {
|
||||
for (int i = PATTERN_REGEX_SPECIAL_CHARACTERS.length - 1; i >= 0; i--) {
|
||||
if (ch == PATTERN_REGEX_SPECIAL_CHARACTERS[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是标点符号,(POSIX 字符类(仅 US-ASCII) \p{Punct} 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)
|
||||
*
|
||||
* @param ch
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPunct(char ch) {
|
||||
return (ch >= 0x21 && ch <= 0x2F) // !"#$%&'()*+,-./
|
||||
|| (ch >= 0x3A && ch <= 0x40) // :;<=>?@
|
||||
|| (ch >= 0x5B && ch <= 0x60) // [\]^_`
|
||||
|| (ch >= 0x7B && ch <= 0x7E);// {|}~
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是标点符号字符串 中文标点识别不了
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPunct( String input) {
|
||||
return isMatches(TYPE_PUNCT, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含标点符号字符串
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludePunct( String input) {
|
||||
return isMatchesInclude(TYPE_PUNCT, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含非字母,数字以及Punct规定的字符串
|
||||
*
|
||||
* @param input
|
||||
* @return 含有则返回true,否则 返回false
|
||||
*/
|
||||
public static boolean isIncludeInvalidChar( String input) {
|
||||
return isMatchesInclude(TYPE_NOT_PUNCT_DIGIT_LETTER, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是数字字符串
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDigit( String input) {
|
||||
return isMatches(TYPE_DIGIT, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含数字字符串
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludeDigit( String input) {
|
||||
return isMatchesInclude(TYPE_DIGIT, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是小写字母字符([a-z])
|
||||
*
|
||||
* @param ch
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLowerLetter(char ch) {
|
||||
return ch >= 0x61 && ch <= 0x7A;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是小写字母字符串([a-z])
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLowerLetter( String input) {
|
||||
return isMatches(TYPE_LOWER_LETTER, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含小写字母字符串([a-z])
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludeLowerLetter( String input) {
|
||||
return isMatchesInclude(TYPE_LOWER_LETTER, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是大写字母字符([A-Z])
|
||||
*
|
||||
* @param ch
|
||||
* @return
|
||||
*/
|
||||
public static boolean isUpperLetter(char ch) {
|
||||
return ch >= 0x41 && ch <= 0x5A;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是大写字母字符串([A-Z])
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static boolean isUpperLetter( String input) {
|
||||
return isMatches(TYPE_UPPER_LETTER, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含大写字母字符串([A-Z])
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludeUpperLetter( String input) {
|
||||
return isMatchesInclude(TYPE_UPPER_LETTER, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是字母字符串([A-Za-z])
|
||||
*
|
||||
* @param ch
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLetter(char ch) {
|
||||
return isLowerLetter(ch) || isUpperLetter(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是汉字字符(广义上的汉字字符,很多都无法用输入法输出的汉字)
|
||||
*
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCJK(char c) {
|
||||
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
|
||||
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS // CJK统一汉字 \\u4E00-\\u9fAF
|
||||
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A // CJK统一汉字扩展-A \\u3400-\\u4dBF
|
||||
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS // CJK兼容汉字 \\uF900-\\uFAFF
|
||||
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION // CJK符号和标点 \\u3000-\\u303F
|
||||
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION // 广义标点 \\u2000-\\u206F
|
||||
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { // 半形及全形字符 \\uFF00-\\uFFEF
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是汉字字符(不包含标点)
|
||||
*
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNoPunctuationCJK(char c) {
|
||||
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
|
||||
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS // CJK统一汉字 \\u4E00-\\u9fAF
|
||||
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A // CJK统一汉字扩展-A \\u3400-\\u4dBF
|
||||
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS) { // CJK兼容汉字 \\uF900-\\uFAFF
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是汉字字符(不包含标点)
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNoPunctuationCJK( String input) {
|
||||
return isMatches(TYPE_NO_PUNCTUATION_CJK, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是汉字字符串(广义上的汉字字符,很多都无法用输入法输出的汉字)
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCJK( String input) {
|
||||
return isMatches(TYPE_CJK, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含汉字字符串(广义上的汉字字符,很多都无法用输入法输出的汉字)
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludeCJK( String input) {
|
||||
return isMatchesInclude(TYPE_CJK, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是空白字符
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWhitespace( String input) {
|
||||
return isMatches(TYPE_WHITESPACE, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含空白字符
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isIncludeWhitespace( String input) {
|
||||
return isMatchesInclude(TYPE_WHITESPACE, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否符合密码规则
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static boolean isFetionPassword( String input) {
|
||||
// 密码必须含有字母和数字,符号可选,但是必须符合Punct标准,否则返回false
|
||||
// 首先判断是否含有无效字符,含有,则返回false
|
||||
if (isIncludeInvalidChar(input)) {
|
||||
return false;
|
||||
}
|
||||
// 长度不符合要求,返回 false
|
||||
if (input.length() < 6 || input.length() > 16) {
|
||||
return false;
|
||||
}
|
||||
int tmpValue = 0;
|
||||
if (isMatches("[A-Za-z]{1,15}", input)) {
|
||||
tmpValue++;
|
||||
}
|
||||
if (isMatches("[0-9]{1,15}", input)) {
|
||||
tmpValue++;
|
||||
}
|
||||
if (tmpValue >= 2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1个或者多个0-9组成的数字
|
||||
*
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNumeric( String str) {
|
||||
Pattern pattern = Pattern.compile("[0-9]+");
|
||||
Matcher isNum = pattern.matcher(str);
|
||||
if (!isNum.matches()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
|
||||
public class ProcessUtils {
|
||||
|
||||
public static boolean isMainProcess( Context context ) {
|
||||
try {
|
||||
ActivityManager activityManager = ( ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE ) );
|
||||
if ( activityManager == null ) {
|
||||
return false;
|
||||
}
|
||||
List< RunningAppProcessInfo > raps = activityManager.getRunningAppProcesses();
|
||||
if ( raps == null || raps.size() <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
int pid = Process.myPid();
|
||||
String packageName = context.getPackageName();
|
||||
for ( RunningAppProcessInfo info : raps ) {
|
||||
if ( packageName.equals( info.processName ) ) {
|
||||
return pid == info.pid;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getPackageName() {
|
||||
String packageName = null;
|
||||
BufferedReader reader = null;
|
||||
|
||||
try {
|
||||
reader = new BufferedReader( new InputStreamReader( new FileInputStream( "/proc/" + Process.myPid() + "/cmdline" ) ) );
|
||||
packageName = reader.readLine().trim();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
packageName = String.valueOf( Process.myPid() );
|
||||
} finally {
|
||||
if ( reader != null ) try {
|
||||
reader.close();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取进程号对应的进程名
|
||||
*
|
||||
* @param pid 进程号
|
||||
* @return 进程名
|
||||
*/
|
||||
private static String getProcessName( int pid ) {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader( new FileReader( "/proc/" + pid + "/cmdline" ) );
|
||||
String processName = reader.readLine();
|
||||
if ( !TextUtils.isEmpty( processName ) ) {
|
||||
processName = processName.trim();
|
||||
}
|
||||
return processName;
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeSilently( reader );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ReflectUtils {
|
||||
|
||||
public static Object getField( Class clazz, Object target, String name) throws Exception {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(target);
|
||||
}
|
||||
|
||||
public static void setField( Class clazz, Object target, String name, Object value) throws Exception {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
}
|
||||
|
||||
public static void setFieldNoException( Class clazz, Object target, String name, Object value) {
|
||||
try {
|
||||
ReflectUtils.setField(clazz, target, name, value);
|
||||
} catch ( Exception e) {
|
||||
Log.e("ReflectUtil",e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object invoke( Class clazz, Object target, String name, Object... args)
|
||||
throws Exception {
|
||||
Class[] parameterTypes = null;
|
||||
if (args != null) {
|
||||
parameterTypes = new Class[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
parameterTypes[i] = args[i].getClass();
|
||||
}
|
||||
}
|
||||
|
||||
Method method = clazz.getDeclaredMethod(name, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object invoke( Class clazz, Object target, String name, Class[] parameterTypes, Object... args)
|
||||
throws Exception {
|
||||
Method method = clazz.getDeclaredMethod(name, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T invokeConstructor( Class<T> clazz, Class[] parameterTypes, Object... args)
|
||||
throws Exception {
|
||||
Constructor constructor = clazz.getDeclaredConstructor(parameterTypes);
|
||||
constructor.setAccessible(true);
|
||||
return (T) constructor.newInstance(args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T invokeConstructor( Class<T> clazz)
|
||||
throws Exception {
|
||||
Constructor constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return (T) constructor.newInstance();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
public class ResourcesHelper {
|
||||
|
||||
public static Resources getResources( Context context){
|
||||
return context.getResources();
|
||||
}
|
||||
|
||||
public static int getColor( Context context, int rid) {
|
||||
return getResources(context).getColor(rid);
|
||||
}
|
||||
|
||||
public static ColorStateList getColorStateList( Context context, int rid) {
|
||||
return getResources(context).getColorStateList(rid);
|
||||
}
|
||||
|
||||
public static String getString( Context context, int rid) {
|
||||
return getResources(context).getString(rid);
|
||||
}
|
||||
|
||||
public static String getString( Context context, int rid, int param1, int param2) {
|
||||
return getResources(context).getString(rid, param1, param2);
|
||||
}
|
||||
|
||||
public static String getString( Context context, int rid, String str) {
|
||||
return getResources(context).getString(rid, str);
|
||||
}
|
||||
|
||||
public static String[] getStringArray( Context context, int rid) {
|
||||
return getResources(context).getStringArray(rid);
|
||||
}
|
||||
|
||||
public static Drawable getDrawable( Context context, int rid) {
|
||||
return getResources(context).getDrawable(rid);
|
||||
}
|
||||
|
||||
public static float getDimension( Context context, int rid) {
|
||||
return getResources(context).getDimension(rid);
|
||||
}
|
||||
|
||||
public static DisplayMetrics getDisplayMetrics( Context context) {
|
||||
return getResources(context).getDisplayMetrics();
|
||||
}
|
||||
|
||||
public static int getDisplayMetrics( Context context, int x) {
|
||||
return getResources(context).getDimensionPixelSize(x);
|
||||
}
|
||||
|
||||
public static int getDimensionPixelSize( Context context, int x) {
|
||||
return getResources(context).getDimensionPixelSize(x);
|
||||
}
|
||||
|
||||
public static int getInteger( Context context, int rid) {
|
||||
return getResources(context).getInteger(rid);
|
||||
}
|
||||
|
||||
public static XmlResourceParser getXml( Context context, int rid) {
|
||||
return getResources(context).getXml(rid);
|
||||
}
|
||||
|
||||
public static Configuration getConfiguration( Context context) {
|
||||
return getResources(context).getConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
/**
|
||||
* Created by congtaowang on 2018/12/20.
|
||||
*/
|
||||
public class SoftKeyboardUtils {
|
||||
|
||||
public static void show( Context context ) {
|
||||
try {
|
||||
InputMethodManager imm = ( InputMethodManager ) context.getSystemService( Context.INPUT_METHOD_SERVICE );
|
||||
if ( imm != null ) {
|
||||
imm.toggleSoftInput( 0, InputMethodManager.HIDE_NOT_ALWAYS );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void hidden( Context context, EditText editText ) {
|
||||
try {
|
||||
InputMethodManager imm = ( InputMethodManager ) context.getSystemService( Context.INPUT_METHOD_SERVICE );
|
||||
if ( imm != null ) {
|
||||
imm.hideSoftInputFromWindow( editText.getWindowToken(), 0 );
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ThreadPoolService {
|
||||
|
||||
private static final ExecutorService SERVICE = Executors.newScheduledThreadPool( 1 );
|
||||
|
||||
private ThreadPoolService() {
|
||||
}
|
||||
|
||||
public static void execute( Runnable task ) {
|
||||
SERVICE.execute( task );
|
||||
}
|
||||
}
|
||||
176
foudations/mogo-utils/src/main/java/com/mogo/utils/TipToast.java
Normal file
@@ -0,0 +1,176 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
/**
|
||||
* 2016/1/1 by congtaowang
|
||||
*
|
||||
* @Version 1.0
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* Init TipToast in your Application
|
||||
*/
|
||||
public final class TipToast {
|
||||
|
||||
private static final String TAG = "TipToast";
|
||||
|
||||
private static Toast sToast = null;
|
||||
private static final Object sSyncObject = new Object();
|
||||
private static Handler sHandler = null;
|
||||
private static Context sContext;
|
||||
private static ToastViewGenerator sGenerator;
|
||||
|
||||
public static void init( Context context, ToastViewGenerator generator ) {
|
||||
TipToast.sContext = context;
|
||||
sHandler = new Handler( context.getMainLooper() );
|
||||
sGenerator = generator;
|
||||
}
|
||||
|
||||
public static void recycle() {
|
||||
sContext = null;
|
||||
sHandler = null;
|
||||
if ( sToast != null ) {
|
||||
sToast.cancel();
|
||||
sToast = null;
|
||||
}
|
||||
sGenerator = null;
|
||||
}
|
||||
|
||||
private static void tip( final String message, int duration ) {
|
||||
if ( !checkParams() ) {
|
||||
return;
|
||||
}
|
||||
if ( TextUtils.isEmpty( message ) ) {
|
||||
return;
|
||||
}
|
||||
new ToastThread( new StringToastRunnable( sContext, message, duration ) ).start();
|
||||
}
|
||||
|
||||
private static void tip( final int msgId, int duration ) {
|
||||
if ( !checkParams() ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if ( TextUtils.isEmpty( ResourcesHelper.getString( sContext, msgId ) ) ) {
|
||||
return;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
return;
|
||||
}
|
||||
tip( ResourcesHelper.getString( sContext, msgId ), duration );
|
||||
}
|
||||
|
||||
private static boolean checkParams() {
|
||||
if ( sContext == null ) {
|
||||
Logger.e( TAG, "context can't be null." );
|
||||
return false;
|
||||
}
|
||||
if ( sHandler == null ) {
|
||||
Logger.e( TAG, "sHandler can't be null." );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void tip( final String message ) {
|
||||
tip( message, Toast.LENGTH_SHORT );
|
||||
}
|
||||
|
||||
public static void tip( final int msgId ) {
|
||||
tip( msgId, Toast.LENGTH_SHORT );
|
||||
}
|
||||
|
||||
public static void longTip( String message ) {
|
||||
tip( message, Toast.LENGTH_LONG );
|
||||
}
|
||||
|
||||
public static void longTip( int msgId ) {
|
||||
tip( msgId, Toast.LENGTH_LONG );
|
||||
}
|
||||
|
||||
public static void shortTip( String message ) {
|
||||
tip( message, Toast.LENGTH_SHORT );
|
||||
}
|
||||
|
||||
public static void shortTip( int msgId ) {
|
||||
tip( msgId, Toast.LENGTH_SHORT );
|
||||
}
|
||||
|
||||
static class ToastThread extends Thread {
|
||||
public ToastThread( Runnable runnable ) {
|
||||
super( runnable );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class StringToastRunnable implements Runnable {
|
||||
|
||||
Context context;
|
||||
String msg;
|
||||
int duration;
|
||||
|
||||
public StringToastRunnable( Context context, String msg, int duration ) {
|
||||
this.context = context;
|
||||
this.msg = msg;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if ( sHandler == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
sHandler.post( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized ( sSyncObject ) {
|
||||
|
||||
if ( context == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( sToast != null ) {
|
||||
sToast.cancel();
|
||||
}
|
||||
|
||||
if ( sGenerator == null ) {
|
||||
sToast = Toast.makeText( context, msg, duration );
|
||||
}
|
||||
|
||||
if ( sGenerator == null ) {
|
||||
sToast = Toast.makeText( context, msg, duration );
|
||||
} else {
|
||||
sToast = new Toast( context );
|
||||
final View view = sGenerator.make( context, msg );
|
||||
if ( view != null ) {
|
||||
sToast.setView( view );
|
||||
sToast.setDuration( duration );
|
||||
} else {
|
||||
sToast = Toast.makeText( context, msg, duration );
|
||||
}
|
||||
}
|
||||
if ( sToast != null ) {
|
||||
sToast.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
public interface ToastViewGenerator {
|
||||
View make( Context context, String message );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
public class UiThreadHandler {
|
||||
|
||||
private static Handler sUiHandler = new Handler( Looper.getMainLooper() );
|
||||
|
||||
private static Object sToken = new Object();
|
||||
|
||||
public UiThreadHandler() {
|
||||
}
|
||||
|
||||
public static boolean post( Runnable r ) {
|
||||
return sUiHandler != null && sUiHandler.post( r );
|
||||
}
|
||||
|
||||
public static boolean postDelayed( Runnable r, long delayMillis ) {
|
||||
return sUiHandler != null && sUiHandler.postDelayed( r, delayMillis );
|
||||
}
|
||||
|
||||
public static Handler getsUiHandler() {
|
||||
return sUiHandler;
|
||||
}
|
||||
|
||||
public static boolean postOnceDelayed( Runnable r, long delayMillis ) {
|
||||
if ( sUiHandler == null ) {
|
||||
return false;
|
||||
} else {
|
||||
sUiHandler.removeCallbacks( r, sToken );
|
||||
return sUiHandler.postDelayed( r, delayMillis );
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeCallbacks( Runnable runnable ) {
|
||||
if ( sUiHandler != null ) {
|
||||
sUiHandler.removeCallbacks( runnable );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2019-06-11
|
||||
* <p>
|
||||
* 验证格式工具类
|
||||
*/
|
||||
public class ValidateUtils {
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.mogo.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class WindowUtils {
|
||||
|
||||
public static int getStatusBarHeight( Context context ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
} else {
|
||||
int result = 0;
|
||||
int resourceId = context.getResources().getIdentifier( "status_bar_height", "dimen", "android" );
|
||||
if ( resourceId > 0 ) {
|
||||
result = context.getResources().getDimensionPixelSize( resourceId );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
|
||||
*/
|
||||
public static int dip2px( Context context, float dpValue ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return ( int ) ( dpValue * scale + 0.5f );
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
|
||||
*/
|
||||
public static int px2dip( Context context, float pxValue ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return ( int ) ( pxValue / scale + 0.5f );
|
||||
}
|
||||
|
||||
|
||||
public static String getScreenPixels( Context context ) {
|
||||
if ( context == null ) {
|
||||
return "";
|
||||
}
|
||||
return getScreenWidth( context ) + "*" + getScreenHeight( context );
|
||||
}
|
||||
|
||||
public static int getScreenWidth( Context context ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenHeight( Context context ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
public static int getScreenDpi( Context context ) {
|
||||
if ( context == null ) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getDisplayMetrics().densityDpi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Defines common decoding methods for byte array decoders.
|
||||
*
|
||||
* @version $Id: BinaryDecoder.java 1379145 2012-08-30 21:02:52Z tn $
|
||||
*/
|
||||
public interface BinaryDecoder extends Decoder {
|
||||
|
||||
/**
|
||||
* Decodes a byte array and returns the results as a byte array.
|
||||
*
|
||||
* @param source
|
||||
* A byte array which has been encoded with the appropriate encoder
|
||||
* @return a byte array that contains decoded content
|
||||
* @throws DecoderException
|
||||
* A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
|
||||
*/
|
||||
byte[] decode( byte[] source ) throws DecoderException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Defines common encoding methods for byte array encoders.
|
||||
*
|
||||
* @version $Id: BinaryEncoder.java 1379145 2012-08-30 21:02:52Z tn $
|
||||
*/
|
||||
public interface BinaryEncoder extends Encoder {
|
||||
|
||||
/**
|
||||
* Encodes a byte array and return the encoded data as a byte array.
|
||||
*
|
||||
* @param source
|
||||
* Data to be encoded
|
||||
* @return A byte array containing the encoded data
|
||||
* @throws EncoderException
|
||||
* thrown if the Encoder encounters a failure condition during the encoding process.
|
||||
*/
|
||||
byte[] encode( byte[] source ) throws EncoderException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Character encoding names required of every implementation of the Java platform.
|
||||
*
|
||||
* From the Java documentation <a
|
||||
* href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>:
|
||||
* <p>
|
||||
* <cite>Every implementation of the Java platform is required to support the following character encodings. Consult the
|
||||
* release documentation for your implementation to see if any other encodings are supported. Consult the release
|
||||
* documentation for your implementation to see if any other encodings are supported.</cite>
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>US-ASCII</code><br>
|
||||
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</li>
|
||||
* <li><code>ISO-8859-1</code><br>
|
||||
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</li>
|
||||
* <li><code>UTF-8</code><br>
|
||||
* Eight-bit Unicode Transformation Format.</li>
|
||||
* <li><code>UTF-16BE</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, big-endian byte order.</li>
|
||||
* <li><code>UTF-16LE</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, little-endian byte order.</li>
|
||||
* <li><code>UTF-16</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
|
||||
* accepted on input, big-endian used on output.)</li>
|
||||
* </ul>
|
||||
*
|
||||
* This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not
|
||||
* foreseen that [codec] would be made to depend on [lang].
|
||||
*
|
||||
* <p>
|
||||
* This class is immutable and thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @since 1.4
|
||||
* @version $Id: CharEncoding.java 1563226 2014-01-31 19:38:06Z ggregory $
|
||||
*/
|
||||
public class CharEncoding {
|
||||
/**
|
||||
* CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String ISO_8859_1 = "ISO-8859-1";
|
||||
|
||||
/**
|
||||
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String US_ASCII = "US-ASCII";
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
|
||||
* (either order accepted on input, big-endian used on output)
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String UTF_16 = "UTF-16";
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String UTF_16BE = "UTF-16BE";
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String UTF_16LE = "UTF-16LE";
|
||||
|
||||
/**
|
||||
* Eight-bit Unicode Transformation Format.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
*/
|
||||
public static final String UTF_8 = "UTF-8";
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Operations on {@link CharSequence} that are <code>null</code> safe.
|
||||
* </p>
|
||||
* <p>
|
||||
* Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
|
||||
* </p>
|
||||
*
|
||||
* @see CharSequence
|
||||
* @since 1.10
|
||||
*/
|
||||
public class CharSequenceUtils {
|
||||
|
||||
/**
|
||||
* Green implementation of regionMatches.
|
||||
*
|
||||
* @param cs
|
||||
* the <code>CharSequence</code> to be processed
|
||||
* @param ignoreCase
|
||||
* whether or not to be case insensitive
|
||||
* @param thisStart
|
||||
* the index to start on the <code>cs</code> CharSequence
|
||||
* @param substring
|
||||
* the <code>CharSequence</code> to be looked for
|
||||
* @param start
|
||||
* the index to start on the <code>substring</code> CharSequence
|
||||
* @param length
|
||||
* character length of the region
|
||||
* @return whether the region matched
|
||||
*/
|
||||
static boolean regionMatches( final CharSequence cs, final boolean ignoreCase, final int thisStart,
|
||||
final CharSequence substring, final int start, final int length) {
|
||||
if (cs instanceof String && substring instanceof String ) {
|
||||
return (( String ) cs).regionMatches(ignoreCase, thisStart, ( String ) substring, start, length);
|
||||
}
|
||||
int index1 = thisStart;
|
||||
int index2 = start;
|
||||
int tmpLen = length;
|
||||
|
||||
while (tmpLen-- > 0) {
|
||||
char c1 = cs.charAt(index1++);
|
||||
char c2 = substring.charAt(index2++);
|
||||
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ignoreCase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The same check as in String.regionMatches():
|
||||
if ( Character.toUpperCase(c1) != Character.toUpperCase(c2) &&
|
||||
Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Charsets required of every implementation of the Java platform.
|
||||
*
|
||||
* From the Java documentation <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard
|
||||
* charsets</a>:
|
||||
* <p>
|
||||
* <cite>Every implementation of the Java platform is required to support the following character encodings. Consult the
|
||||
* release documentation for your implementation to see if any other encodings are supported. Consult the release
|
||||
* documentation for your implementation to see if any other encodings are supported. </cite>
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>US-ASCII</code><br>
|
||||
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</li>
|
||||
* <li><code>ISO-8859-1</code><br>
|
||||
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</li>
|
||||
* <li><code>UTF-8</code><br>
|
||||
* Eight-bit Unicode Transformation Format.</li>
|
||||
* <li><code>UTF-16BE</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, big-endian byte order.</li>
|
||||
* <li><code>UTF-16LE</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, little-endian byte order.</li>
|
||||
* <li><code>UTF-16</code><br>
|
||||
* Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
|
||||
* accepted on input, big-endian used on output.)</li>
|
||||
* </ul>
|
||||
*
|
||||
* This perhaps would best belong in the Commons Lang project. Even if a similar class is defined in Commons Lang, it is
|
||||
* not foreseen that Commons Codec would be made to depend on Commons Lang.
|
||||
*
|
||||
* <p>
|
||||
* This class is immutable and thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @since 1.7
|
||||
* @version $Id: CharEncoding.java 1173287 2011-09-20 18:16:19Z ggregory $
|
||||
*/
|
||||
public class Charsets {
|
||||
|
||||
//
|
||||
// This class should only contain Charset instances for required encodings. This guarantees that it will load
|
||||
// correctly and without delay on all Java platforms.
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the given Charset or the default Charset if the given Charset is null.
|
||||
*
|
||||
* @param charset
|
||||
* A charset or null.
|
||||
* @return the given Charset or the default Charset if the given Charset is null
|
||||
*/
|
||||
public static Charset toCharset( final Charset charset) {
|
||||
return charset == null ? Charset.defaultCharset() : charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Charset for the named charset. If the name is null, return the default Charset.
|
||||
*
|
||||
* @param charset
|
||||
* The name of the requested charset, may be null.
|
||||
* @return a Charset for the named charset
|
||||
* @throws java.nio.charset.UnsupportedCharsetException
|
||||
* If the named charset is unavailable
|
||||
*/
|
||||
public static Charset toCharset( final String charset) {
|
||||
return charset == null ? Charset.defaultCharset() : Charset.forName(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset ISO_8859_1 = Charset.forName(CharEncoding.ISO_8859_1);
|
||||
|
||||
/**
|
||||
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset US_ASCII = Charset.forName(CharEncoding.US_ASCII);
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
|
||||
* (either order accepted on input, big-endian used on output)
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset UTF_16 = Charset.forName(CharEncoding.UTF_16);
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset UTF_16BE = Charset.forName(CharEncoding.UTF_16BE);
|
||||
|
||||
/**
|
||||
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset UTF_16LE = Charset.forName(CharEncoding.UTF_16LE);
|
||||
|
||||
/**
|
||||
* Eight-bit Unicode Transformation Format.
|
||||
* <p>
|
||||
* Every implementation of the Java platform is required to support this character encoding.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Charset UTF_8 = Charset.forName(CharEncoding.UTF_8);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Provides the highest level of abstraction for Decoders.
|
||||
* <p>
|
||||
* This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface.
|
||||
* Allows a user to pass a generic Object to any Decoder implementation in the codec package.
|
||||
* <p>
|
||||
* One of the two interfaces at the center of the codec package.
|
||||
*
|
||||
* @version $Id: Decoder.java 1379145 2012-08-30 21:02:52Z tn $
|
||||
*/
|
||||
public interface Decoder {
|
||||
|
||||
/**
|
||||
* Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will
|
||||
* try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a
|
||||
* {@link ClassCastException} occurs this decode method will throw a DecoderException.
|
||||
*
|
||||
* @param source
|
||||
* the object to decode
|
||||
* @return a 'decoded" object
|
||||
* @throws DecoderException
|
||||
* a decoder exception can be thrown for any number of reasons. Some good candidates are that the
|
||||
* parameter passed to this method is null, a param cannot be cast to the appropriate type for a
|
||||
* specific encoder.
|
||||
*/
|
||||
Object decode( Object source ) throws DecoderException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder}
|
||||
* encounters a decoding specific exception such as invalid data, or characters outside of the expected range.
|
||||
*
|
||||
* @version $Id: DecoderException.java 1619948 2014-08-22 22:53:55Z ggregory $
|
||||
*/
|
||||
public class DecoderException extends Exception {
|
||||
|
||||
/**
|
||||
* Declares the Serial Version Uid.
|
||||
*
|
||||
* @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with <code>null</code> as its detail message. The cause is not initialized, and may
|
||||
* subsequently be initialized by a call to {@link #initCause}.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public DecoderException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
|
||||
* be initialized by a call to {@link #initCause}.
|
||||
*
|
||||
* @param message
|
||||
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
|
||||
*/
|
||||
public DecoderException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
* <p>
|
||||
* Note that the detail message associated with <code>cause</code> is not automatically incorporated into this
|
||||
* exception's detail message.
|
||||
*
|
||||
* @param message
|
||||
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
|
||||
* @param cause
|
||||
* The cause which is saved for later retrieval by the {@link #getCause()} method. A <code>null</code>
|
||||
* value is permitted, and indicates that the cause is nonexistent or unknown.
|
||||
* @since 1.4
|
||||
*/
|
||||
public DecoderException( final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
|
||||
* null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
|
||||
* This constructor is useful for exceptions that are little more than wrappers for other throwables.
|
||||
*
|
||||
* @param cause
|
||||
* The cause which is saved for later retrieval by the {@link #getCause()} method. A <code>null</code>
|
||||
* value is permitted, and indicates that the cause is nonexistent or unknown.
|
||||
* @since 1.4
|
||||
*/
|
||||
public DecoderException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,817 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Operations to simplify common {@link MessageDigest} tasks.
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @version $Id: DigestUtils.java 1634433 2014-10-27 01:10:47Z ggregory $
|
||||
*/
|
||||
public class DigestUtils {
|
||||
|
||||
private static final int STREAM_BUFFER_LENGTH = 1024;
|
||||
|
||||
/**
|
||||
* Read through an InputStream and returns the digest for the data
|
||||
*
|
||||
* @param digest
|
||||
* The MessageDigest to use (e.g. MD5)
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return the digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
*/
|
||||
private static byte[] digest( final MessageDigest digest, final InputStream data) throws IOException {
|
||||
return updateDigest(digest, data).digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>MessageDigest</code> for the given <code>algorithm</code>.
|
||||
*
|
||||
* @param algorithm
|
||||
* the name of the algorithm requested. See <a
|
||||
* href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"
|
||||
* >Appendix A in the Java Cryptography Architecture Reference Guide</a> for information about standard
|
||||
* algorithm names.
|
||||
* @return A digest instance.
|
||||
* @see MessageDigest#getInstance(String)
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught.
|
||||
*/
|
||||
public static MessageDigest getDigest( final String algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an MD2 MessageDigest.
|
||||
*
|
||||
* @return An MD2 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because MD2 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#MD2
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MessageDigest getMd2Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.MD2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an MD5 MessageDigest.
|
||||
*
|
||||
* @return An MD5 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because MD5 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#MD5
|
||||
*/
|
||||
public static MessageDigest getMd5Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.MD5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SHA-1 digest.
|
||||
*
|
||||
* @return An SHA-1 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-1 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#SHA_1
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MessageDigest getSha1Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.SHA_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SHA-256 digest.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @return An SHA-256 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-256 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#SHA_256
|
||||
*/
|
||||
public static MessageDigest getSha256Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.SHA_256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SHA-384 digest.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @return An SHA-384 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-384 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#SHA_384
|
||||
*/
|
||||
public static MessageDigest getSha384Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.SHA_384);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SHA-512 digest.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @return An SHA-512 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-512 is a
|
||||
* built-in algorithm
|
||||
* @see MessageDigestAlgorithms#SHA_512
|
||||
*/
|
||||
public static MessageDigest getSha512Digest() {
|
||||
return getDigest(MessageDigestAlgorithms.SHA_512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SHA-1 digest.
|
||||
*
|
||||
* @return An SHA-1 digest instance.
|
||||
* @throws IllegalArgumentException
|
||||
* when a {@link NoSuchAlgorithmException} is caught
|
||||
* @deprecated Use {@link #getSha1Digest()}
|
||||
*/
|
||||
@Deprecated
|
||||
public static MessageDigest getShaDigest() {
|
||||
return getSha1Digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD2 digest
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] md2(final byte[] data) {
|
||||
return getMd2Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD2 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] md2(final InputStream data) throws IOException {
|
||||
return digest(getMd2Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return MD2 digest
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] md2(final String data) {
|
||||
return md2(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD2 digest as a hex string
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String md2Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(md2(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD2 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String md2Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(md2(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD2 digest as a hex string
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String md2Hex( final String data) {
|
||||
return Hex.encodeHexString(md2(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD5 digest
|
||||
*/
|
||||
public static byte[] md5(final byte[] data) {
|
||||
return getMd5Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD5 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] md5(final InputStream data) throws IOException {
|
||||
return digest(getMd5Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return MD5 digest
|
||||
*/
|
||||
public static byte[] md5(final String data) {
|
||||
return md5(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD5 digest as a hex string
|
||||
*/
|
||||
public static String md5Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(md5(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD5 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String md5Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(md5(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 digest and returns the value as a 32 character hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return MD5 digest as a hex string
|
||||
*/
|
||||
public static String md5Hex( final String data) {
|
||||
return Hex.encodeHexString(md5(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest
|
||||
* @deprecated Use {@link #sha1(byte[])}
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] sha(final byte[] data) {
|
||||
return sha1(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
* @deprecated Use {@link #sha1(InputStream)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] sha(final InputStream data) throws IOException {
|
||||
return sha1(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest
|
||||
* @deprecated Use {@link #sha1(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] sha(final String data) {
|
||||
return sha1(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] sha1(final byte[] data) {
|
||||
return getSha1Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] sha1(final InputStream data) throws IOException {
|
||||
return digest(getSha1Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return SHA-1 digest
|
||||
*/
|
||||
public static byte[] sha1(final String data) {
|
||||
return sha1(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String sha1Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(sha1(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String sha1Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(sha1(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String sha1Hex( final String data) {
|
||||
return Hex.encodeHexString(sha1(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-256 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha256(final byte[] data) {
|
||||
return getSha256Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-256 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha256(final InputStream data) throws IOException {
|
||||
return digest(getSha256Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return SHA-256 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha256(final String data) {
|
||||
return sha256(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-256 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha256Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(sha256(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-256 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha256Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(sha256(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-256 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha256Hex( final String data) {
|
||||
return Hex.encodeHexString(sha256(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-384 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha384(final byte[] data) {
|
||||
return getSha384Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-384 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha384(final InputStream data) throws IOException {
|
||||
return digest(getSha384Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return SHA-384 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha384(final String data) {
|
||||
return sha384(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-384 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha384Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(sha384(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-384 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha384Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(sha384(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-384 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha384Hex( final String data) {
|
||||
return Hex.encodeHexString(sha384(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-512 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha512(final byte[] data) {
|
||||
return getSha512Digest().digest(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-512 digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha512(final InputStream data) throws IOException {
|
||||
return digest(getSha512Digest(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return SHA-512 digest
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] sha512(final String data) {
|
||||
return sha512(StringUtils.getBytesUtf8(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-512 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha512Hex( final byte[] data) {
|
||||
return Hex.encodeHexString(sha512(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-512 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha512Hex( final InputStream data) throws IOException {
|
||||
return Hex.encodeHexString(sha512(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 digest and returns the value as a hex string.
|
||||
* <p>
|
||||
* Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-512 digest as a hex string
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String sha512Hex( final String data) {
|
||||
return Hex.encodeHexString(sha512(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @deprecated Use {@link #sha1Hex(byte[])}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String shaHex( final byte[] data) {
|
||||
return sha1Hex(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.4
|
||||
* @deprecated Use {@link #sha1Hex(InputStream)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String shaHex( final InputStream data) throws IOException {
|
||||
return sha1Hex(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 digest and returns the value as a hex string.
|
||||
*
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return SHA-1 digest as a hex string
|
||||
* @deprecated Use {@link #sha1Hex(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String shaHex( final String data) {
|
||||
return sha1Hex(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the given {@link MessageDigest}.
|
||||
*
|
||||
* @param messageDigest
|
||||
* the {@link MessageDigest} to update
|
||||
* @param valueToDigest
|
||||
* the value to update the {@link MessageDigest} with
|
||||
* @return the updated {@link MessageDigest}
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MessageDigest updateDigest( final MessageDigest messageDigest, final byte[] valueToDigest) {
|
||||
messageDigest.update(valueToDigest);
|
||||
return messageDigest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads through an InputStream and updates the digest for the data
|
||||
*
|
||||
* @param digest
|
||||
* The MessageDigest to use (e.g. MD5)
|
||||
* @param data
|
||||
* Data to digest
|
||||
* @return the digest
|
||||
* @throws IOException
|
||||
* On error reading from the stream
|
||||
* @since 1.8
|
||||
*/
|
||||
public static MessageDigest updateDigest( final MessageDigest digest, final InputStream data) throws IOException {
|
||||
final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
|
||||
int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
||||
|
||||
while (read > -1) {
|
||||
digest.update(buffer, 0, read);
|
||||
read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
|
||||
}
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the given {@link MessageDigest}.
|
||||
*
|
||||
* @param messageDigest
|
||||
* the {@link MessageDigest} to update
|
||||
* @param valueToDigest
|
||||
* the value to update the {@link MessageDigest} with;
|
||||
* converted to bytes using {@link StringUtils#getBytesUtf8(String)}
|
||||
* @return the updated {@link MessageDigest}
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MessageDigest updateDigest( final MessageDigest messageDigest, final String valueToDigest) {
|
||||
messageDigest.update(StringUtils.getBytesUtf8(valueToDigest));
|
||||
return messageDigest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Provides the highest level of abstraction for Encoders.
|
||||
* <p>
|
||||
* This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this
|
||||
* common generic interface which allows a user to pass a generic Object to any Encoder implementation
|
||||
* in the codec package.
|
||||
*
|
||||
* @version $Id: Encoder.java 1379145 2012-08-30 21:02:52Z tn $
|
||||
*/
|
||||
public interface Encoder {
|
||||
|
||||
/**
|
||||
* Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be
|
||||
* <code>byte[]</code> or <code>String</code>s depending on the implementation used.
|
||||
*
|
||||
* @param source
|
||||
* An object to encode
|
||||
* @return An "encoded" Object
|
||||
* @throws EncoderException
|
||||
* An encoder exception is thrown if the encoder experiences a failure condition during the encoding
|
||||
* process.
|
||||
*/
|
||||
Object encode( Object source ) throws EncoderException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Thrown when there is a failure condition during the encoding process. This exception is thrown when an
|
||||
* {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum,
|
||||
* characters outside of the expected range.
|
||||
*
|
||||
* @version $Id: EncoderException.java 1619948 2014-08-22 22:53:55Z ggregory $
|
||||
*/
|
||||
public class EncoderException extends Exception {
|
||||
|
||||
/**
|
||||
* Declares the Serial Version Uid.
|
||||
*
|
||||
* @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with <code>null</code> as its detail message. The cause is not initialized, and may
|
||||
* subsequently be initialized by a call to {@link #initCause}.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public EncoderException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
|
||||
* be initialized by a call to {@link #initCause}.
|
||||
*
|
||||
* @param message
|
||||
* a useful message relating to the encoder specific error.
|
||||
*/
|
||||
public EncoderException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* <p>
|
||||
* Note that the detail message associated with <code>cause</code> is not automatically incorporated into this
|
||||
* exception's detail message.
|
||||
* </p>
|
||||
*
|
||||
* @param message
|
||||
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
|
||||
* @param cause
|
||||
* The cause which is saved for later retrieval by the {@link #getCause()} method. A <code>null</code>
|
||||
* value is permitted, and indicates that the cause is nonexistent or unknown.
|
||||
* @since 1.4
|
||||
*/
|
||||
public EncoderException( final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
|
||||
* null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
|
||||
* This constructor is useful for exceptions that are little more than wrappers for other throwables.
|
||||
*
|
||||
* @param cause
|
||||
* The cause which is saved for later retrieval by the {@link #getCause()} method. A <code>null</code>
|
||||
* value is permitted, and indicates that the cause is nonexistent or unknown.
|
||||
* @since 1.4
|
||||
*/
|
||||
public EncoderException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Converts hexadecimal Strings. The charset used for certain operation can be set, the default is set in
|
||||
* {@link #DEFAULT_CHARSET_NAME}
|
||||
*
|
||||
* This class is thread-safe.
|
||||
*
|
||||
* @since 1.1
|
||||
* @version $Id: Hex.java 1619948 2014-08-22 22:53:55Z ggregory $
|
||||
*/
|
||||
public class Hex implements BinaryEncoder, BinaryDecoder {
|
||||
|
||||
/**
|
||||
* Default charset name is {@link Charsets#UTF_8}
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Default charset name is {@link CharEncoding#UTF_8}
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final String DEFAULT_CHARSET_NAME = CharEncoding.UTF_8;
|
||||
|
||||
/**
|
||||
* Used to build output as Hex
|
||||
*/
|
||||
private static final char[] DIGITS_LOWER =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
/**
|
||||
* Used to build output as Hex
|
||||
*/
|
||||
private static final char[] DIGITS_UPPER =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
/**
|
||||
* Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
|
||||
* returned array will be half the length of the passed array, as it takes two characters to represent any given
|
||||
* byte. An exception is thrown if the passed char array has an odd number of elements.
|
||||
*
|
||||
* @param data
|
||||
* An array of characters containing hexadecimal digits
|
||||
* @return A byte array containing binary data decoded from the supplied char array.
|
||||
* @throws DecoderException
|
||||
* Thrown if an odd number or illegal of characters is supplied
|
||||
*/
|
||||
public static byte[] decodeHex(final char[] data) throws DecoderException {
|
||||
|
||||
final int len = data.length;
|
||||
|
||||
if ((len & 0x01) != 0) {
|
||||
throw new DecoderException("Odd number of characters.");
|
||||
}
|
||||
|
||||
final byte[] out = new byte[len >> 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; j < len; i++) {
|
||||
int f = toDigit(data[j], j) << 4;
|
||||
j++;
|
||||
f = f | toDigit(data[j], j);
|
||||
j++;
|
||||
out[i] = (byte) (f & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
|
||||
* The returned array will be double the length of the passed array, as it takes two characters to represent any
|
||||
* given byte.
|
||||
*
|
||||
* @param data
|
||||
* a byte[] to convert to Hex characters
|
||||
* @return A char[] containing hexadecimal characters
|
||||
*/
|
||||
public static char[] encodeHex(final byte[] data) {
|
||||
return encodeHex(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
|
||||
* The returned array will be double the length of the passed array, as it takes two characters to represent any
|
||||
* given byte.
|
||||
*
|
||||
* @param data
|
||||
* a byte[] to convert to Hex characters
|
||||
* @param toLowerCase
|
||||
* <code>true</code> converts to lowercase, <code>false</code> to uppercase
|
||||
* @return A char[] containing hexadecimal characters
|
||||
* @since 1.4
|
||||
*/
|
||||
public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
|
||||
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
|
||||
* The returned array will be double the length of the passed array, as it takes two characters to represent any
|
||||
* given byte.
|
||||
*
|
||||
* @param data
|
||||
* a byte[] to convert to Hex characters
|
||||
* @param toDigits
|
||||
* the output alphabet
|
||||
* @return A char[] containing hexadecimal characters
|
||||
* @since 1.4
|
||||
*/
|
||||
protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
|
||||
final int l = data.length;
|
||||
final char[] out = new char[l << 1];
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
|
||||
out[j++] = toDigits[0x0F & data[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
|
||||
* String will be double the length of the passed array, as it takes two characters to represent any given byte.
|
||||
*
|
||||
* @param data
|
||||
* a byte[] to convert to Hex characters
|
||||
* @return A String containing hexadecimal characters
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String encodeHexString( final byte[] data) {
|
||||
return new String(encodeHex(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hexadecimal character to an integer.
|
||||
*
|
||||
* @param ch
|
||||
* A character to convert to an integer digit
|
||||
* @param index
|
||||
* The index of the character in the source
|
||||
* @return An integer
|
||||
* @throws DecoderException
|
||||
* Thrown if ch is an illegal hex character
|
||||
*/
|
||||
protected static int toDigit(final char ch, final int index) throws DecoderException {
|
||||
final int digit = Character.digit(ch, 16);
|
||||
if (digit == -1) {
|
||||
throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
/**
|
||||
* Creates a new codec with the default charset name {@link #DEFAULT_CHARSET}
|
||||
*/
|
||||
public Hex() {
|
||||
// use default encoding
|
||||
this.charset = DEFAULT_CHARSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new codec with the given Charset.
|
||||
*
|
||||
* @param charset
|
||||
* the charset.
|
||||
* @since 1.7
|
||||
*/
|
||||
public Hex(final Charset charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new codec with the given charset name.
|
||||
*
|
||||
* @param charsetName
|
||||
* the charset name.
|
||||
* @throws java.nio.charset.UnsupportedCharsetException
|
||||
* If the named charset is unavailable
|
||||
* @since 1.4
|
||||
* @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
|
||||
*/
|
||||
public Hex(final String charsetName) {
|
||||
this( Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of character bytes representing hexadecimal values into an array of bytes of those same values.
|
||||
* The returned array will be half the length of the passed array, as it takes two characters to represent any given
|
||||
* byte. An exception is thrown if the passed char array has an odd number of elements.
|
||||
*
|
||||
* @param array
|
||||
* An array of character bytes containing hexadecimal digits
|
||||
* @return A byte array containing binary data decoded from the supplied byte array (representing characters).
|
||||
* @throws DecoderException
|
||||
* Thrown if an odd number of characters is supplied to this function
|
||||
* @see #decodeHex(char[])
|
||||
*/
|
||||
@Override
|
||||
public byte[] decode(final byte[] array) throws DecoderException {
|
||||
return decodeHex(new String(array, getCharset()).toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String or an array of character bytes representing hexadecimal values into an array of bytes of those
|
||||
* same values. The returned array will be half the length of the passed String or array, as it takes two characters
|
||||
* to represent any given byte. An exception is thrown if the passed char array has an odd number of elements.
|
||||
*
|
||||
* @param object
|
||||
* A String or, an array of character bytes containing hexadecimal digits
|
||||
* @return A byte array containing binary data decoded from the supplied byte array (representing characters).
|
||||
* @throws DecoderException
|
||||
* Thrown if an odd number of characters is supplied to this function or the object is not a String or
|
||||
* char[]
|
||||
* @see #decodeHex(char[])
|
||||
*/
|
||||
@Override
|
||||
public Object decode( final Object object) throws DecoderException {
|
||||
try {
|
||||
final char[] charArray = object instanceof String ? (( String ) object).toCharArray() : (char[]) object;
|
||||
return decodeHex(charArray);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new DecoderException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of bytes for the characters representing the hexadecimal values of each
|
||||
* byte in order. The returned array will be double the length of the passed array, as it takes two characters to
|
||||
* represent any given byte.
|
||||
* <p>
|
||||
* The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
|
||||
* {@link #getCharset()}.
|
||||
* </p>
|
||||
*
|
||||
* @param array
|
||||
* a byte[] to convert to Hex characters
|
||||
* @return A byte[] containing the bytes of the hexadecimal characters
|
||||
* @since 1.7 No longer throws IllegalStateException if the charsetName is invalid.
|
||||
* @see #encodeHex(byte[])
|
||||
*/
|
||||
@Override
|
||||
public byte[] encode(final byte[] array) {
|
||||
return encodeHexString(array).getBytes(this.getCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String or an array of bytes into an array of characters representing the hexadecimal values of each
|
||||
* byte in order. The returned array will be double the length of the passed String or array, as it takes two
|
||||
* characters to represent any given byte.
|
||||
* <p>
|
||||
* The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by
|
||||
* {@link #getCharset()}.
|
||||
* </p>
|
||||
*
|
||||
* @param object
|
||||
* a String, or byte[] to convert to Hex characters
|
||||
* @return A char[] containing hexadecimal characters
|
||||
* @throws EncoderException
|
||||
* Thrown if the given object is not a String or byte[]
|
||||
* @see #encodeHex(byte[])
|
||||
*/
|
||||
@Override
|
||||
public Object encode( final Object object) throws EncoderException {
|
||||
try {
|
||||
final byte[] byteArray = object instanceof String ?
|
||||
(( String ) object).getBytes(this.getCharset()) : (byte[]) object;
|
||||
return encodeHex(byteArray);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new EncoderException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the charset.
|
||||
*
|
||||
* @return the charset.
|
||||
* @since 1.7
|
||||
*/
|
||||
public Charset getCharset() {
|
||||
return this.charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the charset name.
|
||||
*
|
||||
* @return the charset name.
|
||||
* @since 1.4
|
||||
*/
|
||||
public String getCharsetName() {
|
||||
return this.charset.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object, which includes the charset name.
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "[charsetName=" + this.charset + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* Standard {@link MessageDigest} algorithm names from the <cite>Java Cryptography Architecture Standard Algorithm Name
|
||||
* Documentation</cite>.
|
||||
* <p>
|
||||
* This class is immutable and thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html">Java Cryptography
|
||||
* Architecture Standard Algorithm Name Documentation</a>
|
||||
* @since 1.7
|
||||
* @version $Id: MessageDigestAlgorithms.java 1585867 2014-04-09 00:12:36Z ggregory $
|
||||
*/
|
||||
public class MessageDigestAlgorithms {
|
||||
|
||||
private MessageDigestAlgorithms() {
|
||||
// cannot be instantiated.
|
||||
}
|
||||
|
||||
/**
|
||||
* The MD2 message digest algorithm defined in RFC 1319.
|
||||
*/
|
||||
public static final String MD2 = "MD2";
|
||||
|
||||
/**
|
||||
* The MD5 message digest algorithm defined in RFC 1321.
|
||||
*/
|
||||
public static final String MD5 = "MD5";
|
||||
|
||||
/**
|
||||
* The SHA-1 hash algorithm defined in the FIPS PUB 180-2.
|
||||
*/
|
||||
public static final String SHA_1 = "SHA-1";
|
||||
|
||||
/**
|
||||
* The SHA-256 hash algorithm defined in the FIPS PUB 180-2.
|
||||
*/
|
||||
public static final String SHA_256 = "SHA-256";
|
||||
|
||||
/**
|
||||
* The SHA-384 hash algorithm defined in the FIPS PUB 180-2.
|
||||
*/
|
||||
public static final String SHA_384 = "SHA-384";
|
||||
|
||||
/**
|
||||
* The SHA-512 hash algorithm defined in the FIPS PUB 180-2.
|
||||
*/
|
||||
public static final String SHA_512 = "SHA-512";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
/**
|
||||
* Defines common encoding methods for String encoders.
|
||||
*
|
||||
* @version $Id: StringEncoder.java 1379145 2012-08-30 21:02:52Z tn $
|
||||
*/
|
||||
public interface StringEncoder extends Encoder {
|
||||
|
||||
/**
|
||||
* Encodes a String and returns a String.
|
||||
*
|
||||
* @param source
|
||||
* the String to encode
|
||||
* @return the encoded String
|
||||
* @throws EncoderException
|
||||
* thrown if there is an error condition during the encoding process.
|
||||
*/
|
||||
String encode( String source ) throws EncoderException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mogo.utils.digest;
|
||||
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Converts String to and from bytes using the encodings required by the Java specification. These encodings are
|
||||
* specified in <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">
|
||||
* Standard charsets</a>.
|
||||
*
|
||||
* <p>This class is immutable and thread-safe.</p>
|
||||
*
|
||||
* @see CharEncoding
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @version $Id: StringUtils.java 1634456 2014-10-27 05:26:56Z ggregory $
|
||||
* @since 1.4
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Compares two CharSequences, returning <code>true</code> if they represent equal sequences of characters.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <code>null</code>s are handled without exceptions. Two <code>null</code> references are considered to be equal.
|
||||
* The comparison is case sensitive.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.equals(null, null) = true
|
||||
* StringUtils.equals(null, "abc") = false
|
||||
* StringUtils.equals("abc", null) = false
|
||||
* StringUtils.equals("abc", "abc") = true
|
||||
* StringUtils.equals("abc", "ABC") = false
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
|
||||
* </p>
|
||||
*
|
||||
* @see Object#equals(Object)
|
||||
* @param cs1
|
||||
* the first CharSequence, may be <code>null</code>
|
||||
* @param cs2
|
||||
* the second CharSequence, may be <code>null</code>
|
||||
* @return <code>true</code> if the CharSequences are equal (case-sensitive), or both <code>null</code>
|
||||
* @since 1.10
|
||||
*/
|
||||
public static boolean equals( final CharSequence cs1, final CharSequence cs2) {
|
||||
if (cs1 == cs2) {
|
||||
return true;
|
||||
}
|
||||
if (cs1 == null || cs2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (cs1 instanceof String && cs2 instanceof String ) {
|
||||
return cs1.equals(cs2);
|
||||
}
|
||||
return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link String#getBytes(Charset)}
|
||||
*
|
||||
* @param string
|
||||
* The string to encode (if null, return null).
|
||||
* @param charset
|
||||
* The {@link Charset} to encode the <code>String</code>
|
||||
* @return the encoded bytes
|
||||
*/
|
||||
private static byte[] getBytes( final String string, final Charset charset) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
return string.getBytes(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the ISO-8859-1 charset, storing the result into a new
|
||||
* byte array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesIso8859_1(final String string) {
|
||||
return getBytes(string, Charsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the named charset, storing the result into a new byte
|
||||
* array.
|
||||
* <p>
|
||||
* This method catches {@link UnsupportedEncodingException} and rethrows it as {@link IllegalStateException}, which
|
||||
* should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
|
||||
* </p>
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @param charsetName
|
||||
* The name of a required {@link Charset}
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws IllegalStateException
|
||||
* Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
|
||||
* required charset name.
|
||||
* @see CharEncoding
|
||||
* @see String#getBytes(String)
|
||||
*/
|
||||
public static byte[] getBytesUnchecked( final String string, final String charsetName) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return string.getBytes(charsetName);
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw StringUtils.newIllegalStateException(charsetName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the US-ASCII charset, storing the result into a new byte
|
||||
* array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesUsAscii(final String string) {
|
||||
return getBytes(string, Charsets.US_ASCII);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the UTF-16 charset, storing the result into a new byte
|
||||
* array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesUtf16(final String string) {
|
||||
return getBytes(string, Charsets.UTF_16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the UTF-16BE charset, storing the result into a new byte
|
||||
* array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesUtf16Be(final String string) {
|
||||
return getBytes(string, Charsets.UTF_16BE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the UTF-16LE charset, storing the result into a new byte
|
||||
* array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesUtf16Le(final String string) {
|
||||
return getBytes(string, Charsets.UTF_16LE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
|
||||
* array.
|
||||
*
|
||||
* @param string
|
||||
* the String to encode, may be <code>null</code>
|
||||
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
|
||||
* @see #getBytesUnchecked(String, String)
|
||||
*/
|
||||
public static byte[] getBytesUtf8(final String string) {
|
||||
return getBytes(string, Charsets.UTF_8);
|
||||
}
|
||||
|
||||
private static IllegalStateException newIllegalStateException( final String charsetName,
|
||||
final UnsupportedEncodingException e) {
|
||||
return new IllegalStateException(charsetName + ": " + e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the given charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @param charset
|
||||
* The {@link Charset} to encode the <code>String</code>
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the given charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
*/
|
||||
private static String newString( final byte[] bytes, final Charset charset) {
|
||||
return bytes == null ? null : new String(bytes, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the given charset.
|
||||
* <p>
|
||||
* This method catches {@link UnsupportedEncodingException} and re-throws it as {@link IllegalStateException}, which
|
||||
* should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
|
||||
* </p>
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters, may be <code>null</code>
|
||||
* @param charsetName
|
||||
* The name of a required {@link Charset}
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the given charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws IllegalStateException
|
||||
* Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
|
||||
* required charset name.
|
||||
* @see CharEncoding
|
||||
* @see String#String(byte[], String)
|
||||
*/
|
||||
public static String newString( final byte[] bytes, final String charsetName) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new String(bytes, charsetName);
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw StringUtils.newIllegalStateException(charsetName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the ISO-8859-1 charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters, may be <code>null</code>
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the ISO-8859-1 charset, or
|
||||
* <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringIso8859_1( final byte[] bytes) {
|
||||
return new String(bytes, Charsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the US-ASCII charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the US-ASCII charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringUsAscii( final byte[] bytes) {
|
||||
return new String(bytes, Charsets.US_ASCII);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-16 charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16 charset
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringUtf16( final byte[] bytes) {
|
||||
return new String(bytes, Charsets.UTF_16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-16BE charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16BE charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringUtf16Be( final byte[] bytes) {
|
||||
return new String(bytes, Charsets.UTF_16BE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-16LE charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16LE charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringUtf16Le( final byte[] bytes) {
|
||||
return new String(bytes, Charsets.UTF_16LE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-8 charset.
|
||||
*
|
||||
* @param bytes
|
||||
* The bytes to be decoded into characters
|
||||
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-8 charset,
|
||||
* or <code>null</code> if the input byte array was <code>null</code>.
|
||||
* @throws NullPointerException
|
||||
* Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
|
||||
* required by the Java platform specification.
|
||||
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
|
||||
*/
|
||||
public static String newStringUtf8( final byte[] bytes) {
|
||||
return newString(bytes, Charsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mogo.utils.glide;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.GlideBuilder;
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.load.Key;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.engine.cache.ExternalPreferredCacheDiskCacheFactory;
|
||||
import com.bumptech.glide.load.engine.cache.LruResourceCache;
|
||||
import com.bumptech.glide.load.engine.cache.MemoryCache;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
|
||||
/**
|
||||
* Created by congtaowang on 2018/12/17.
|
||||
*/
|
||||
@GlideModule
|
||||
public class BaseGlideModule extends AppGlideModule {
|
||||
|
||||
public static final int MEMORY_CACHE_SIZE = 5 * 1024 * 1024;
|
||||
public static final int DISK_CACHE_SIZE = 50 * 1024 * 1024;
|
||||
public static final String DISK_CACHE_NAME = "glide";
|
||||
|
||||
@Override
|
||||
public void applyOptions( Context context, GlideBuilder builder ) {
|
||||
super.applyOptions( context, builder );
|
||||
/**
|
||||
* 更改缓存最总文件夹名称
|
||||
*
|
||||
* 是在sdcard/Android/data/包名/cache/DISK_CACHE_NAME目录当中
|
||||
*/
|
||||
builder.setMemoryCache( new LruResourceCache( MEMORY_CACHE_SIZE ) );
|
||||
builder.setDiskCache( new ExternalPreferredCacheDiskCacheFactory( context, DISK_CACHE_NAME, DISK_CACHE_SIZE ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package com.mogo.utils.logger;
|
||||
|
||||
public enum LogLevel {
|
||||
|
||||
OFF( Integer.MAX_VALUE),
|
||||
|
||||
VERBOSE(1),
|
||||
|
||||
DEBUG(2),
|
||||
|
||||
INFO(3),
|
||||
|
||||
WARN(4),
|
||||
|
||||
ERROR(5);
|
||||
|
||||
public final int level;
|
||||
|
||||
private LogLevel(final int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
package com.mogo.utils.logger;
|
||||
|
||||
public final class Logger {
|
||||
private static final Printer sPrinter = new LoggerPrinter();
|
||||
|
||||
private Logger() {
|
||||
}
|
||||
|
||||
public static Settings init() {
|
||||
return sPrinter.init(LogLevel.DEBUG);
|
||||
}
|
||||
|
||||
public static Settings init(LogLevel logLevel) {
|
||||
return sPrinter.init(logLevel);
|
||||
}
|
||||
|
||||
public static void d( String tag, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.DEBUG)) sPrinter.d(tag, message, args);
|
||||
}
|
||||
|
||||
public static void e( String tag, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.ERROR)) sPrinter.e(tag, null, message, args);
|
||||
}
|
||||
|
||||
public static void e( String tag, Throwable throwable, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.ERROR)) sPrinter.e(tag, throwable, message, args);
|
||||
}
|
||||
|
||||
public static void i( String tag, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.INFO)) sPrinter.i(tag, message, args);
|
||||
}
|
||||
|
||||
public static void v( String tag, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.VERBOSE)) sPrinter.v(tag, message, args);
|
||||
}
|
||||
|
||||
public static void w( String tag, String message, Object... args) {
|
||||
if(isLoggable(LogLevel.WARN)) sPrinter.w(tag, message, args);
|
||||
}
|
||||
|
||||
public static void easyLog( String tag, String message) {
|
||||
if(isLoggable(LogLevel.DEBUG)) sPrinter.d(tag, message);
|
||||
}
|
||||
|
||||
public static void json( String tag, String json) {
|
||||
if(isLoggable(LogLevel.DEBUG)) sPrinter.json(tag, json);
|
||||
}
|
||||
|
||||
public static void xml( String tag, String xml) {
|
||||
if(isLoggable(LogLevel.DEBUG)) sPrinter.xml(tag, xml);
|
||||
}
|
||||
|
||||
private static boolean isLoggable(LogLevel logLevel){
|
||||
return sPrinter.getSettings().getLogLevel().level <= logLevel.level;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
|
||||
package com.mogo.utils.logger;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
final class LoggerPrinter implements Printer {
|
||||
private static final String TAG = "LoggerPrinter";
|
||||
|
||||
private static final int CHUNK_SIZE = 4000;
|
||||
private static final int JSON_INDENT = 4;
|
||||
private static final int MIN_STACK_OFFSET = 3;
|
||||
private static final char TOP_LEFT_CORNER = '╔';
|
||||
private static final char BOTTOM_LEFT_CORNER = '╚';
|
||||
private static final char MIDDLE_CORNER = '╟';
|
||||
private static final char HORIZONTAL_DOUBLE_LINE = '║';
|
||||
private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════";
|
||||
private static final String SINGLE_DIVIDER = "────────────────────────────────────────────";
|
||||
private static final String TOP_BORDER = "╔════════════════════════════════════════════════════════════════════════════════════════";
|
||||
private static final String BOTTOM_BORDER = "╚════════════════════════════════════════════════════════════════════════════════════════";
|
||||
private static final String MIDDLE_BORDER = "╟────────────────────────────────────────────────────────────────────────────────────────";
|
||||
|
||||
private final Settings mSettings = new Settings();
|
||||
|
||||
LoggerPrinter() {
|
||||
}
|
||||
|
||||
public Settings init(LogLevel logLevel) {
|
||||
return mSettings.setLogLevel(logLevel);
|
||||
}
|
||||
|
||||
public Settings getSettings() {
|
||||
return mSettings;
|
||||
}
|
||||
|
||||
public void d( String tag, String message, Object... args) {
|
||||
this.log(tag, LogLevel.DEBUG, message, args);
|
||||
}
|
||||
|
||||
public void e( String tag, String message, Object... args) {
|
||||
this.e(tag, null, message, args);
|
||||
}
|
||||
|
||||
public void e( String tag, Throwable throwable, String message, Object... args) {
|
||||
if (throwable != null && message != null) {
|
||||
message = message + " : " + throwable.toString();
|
||||
}
|
||||
|
||||
if (throwable != null && message == null) {
|
||||
message = throwable.toString();
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
message = "No message/exception is set";
|
||||
}
|
||||
|
||||
this.log(tag, LogLevel.ERROR, message, args);
|
||||
}
|
||||
|
||||
public void w( String tag, String message, Object... args) {
|
||||
this.log(tag, LogLevel.WARN, message, args);
|
||||
}
|
||||
|
||||
public void i( String tag, String message, Object... args) {
|
||||
this.log(tag, LogLevel.INFO, message, args);
|
||||
}
|
||||
|
||||
public void v( String tag, String message, Object... args) {
|
||||
this.log(tag, LogLevel.VERBOSE, message, args);
|
||||
}
|
||||
|
||||
public void json( String tag, String json) {
|
||||
if ( TextUtils.isEmpty(json)) {
|
||||
this.d(tag, "Empty/Null json content");
|
||||
} else {
|
||||
try {
|
||||
String message;
|
||||
if (json.startsWith("{")) {
|
||||
JSONObject e1 = new JSONObject(json);
|
||||
message = e1.toString(4);
|
||||
this.d(tag, message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (json.startsWith("[")) {
|
||||
JSONArray e = new JSONArray(json);
|
||||
message = e.toString(4);
|
||||
this.d(tag, message);
|
||||
}
|
||||
} catch ( JSONException var4) {
|
||||
this.e(tag, var4.getCause().getMessage() + "\n" + json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void xml( String tag, String xml) {
|
||||
if ( TextUtils.isEmpty(xml)) {
|
||||
this.d(tag, "Empty/Null xml content");
|
||||
} else {
|
||||
try {
|
||||
StreamSource e = new StreamSource(new StringReader(xml));
|
||||
StreamResult xmlOutput = new StreamResult(new StringWriter());
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
transformer.setOutputProperty("indent", "yes");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
transformer.transform(e, xmlOutput);
|
||||
this.d(tag, xmlOutput.getWriter().toString().replaceFirst(">", ">\n"));
|
||||
} catch ( TransformerException var5) {
|
||||
this.e(tag, var5.getCause().getMessage() + "\n" + xml);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void normalLog( String tag, String message) {
|
||||
if (!TextUtils.isEmpty(message)) {
|
||||
this.logChunk(LogLevel.DEBUG, tag, message);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void log( String tag, LogLevel logLevel, String msg, Object... args) {
|
||||
String message = this.createMessage(msg, args);
|
||||
int methodCount = this.getMethodCount();
|
||||
this.logTopBorder(logLevel, tag);
|
||||
this.logHeaderContent(logLevel, tag, methodCount);
|
||||
byte[] bytes = message.getBytes();
|
||||
int length = bytes.length;
|
||||
if (length <= 4000) {
|
||||
if (methodCount > 0) {
|
||||
this.logDivider(logLevel, tag);
|
||||
}
|
||||
|
||||
this.logContent(logLevel, tag, message);
|
||||
this.logBottomBorder(logLevel, tag);
|
||||
} else {
|
||||
if (methodCount > 0) {
|
||||
this.logDivider(logLevel, tag);
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i += 4000) {
|
||||
int count = Math.min(length - i, 4000);
|
||||
this.logContent(logLevel, tag, new String(bytes, i, count));
|
||||
}
|
||||
|
||||
this.logBottomBorder(logLevel, tag);
|
||||
}
|
||||
}
|
||||
|
||||
private void logTopBorder(LogLevel logLevel, String tag) {
|
||||
this.logChunk(logLevel, tag, "╔════════════════════════════════════════════════════════════════════════════════════════");
|
||||
}
|
||||
|
||||
private void logHeaderContent( LogLevel logLevel, String tag, int methodCount) {
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
if (mSettings.isShowThreadInfo()) {
|
||||
this.logChunk(logLevel, tag, "║ Thread: " + Thread.currentThread().getName());
|
||||
this.logDivider(logLevel, tag);
|
||||
}
|
||||
|
||||
String level = "";
|
||||
int stackOffset = this.getStackOffset(trace) + mSettings.getMethodOffset();
|
||||
if (methodCount + stackOffset > trace.length) {
|
||||
methodCount = trace.length - stackOffset - 1;
|
||||
}
|
||||
|
||||
for (int i = methodCount; i > 0; --i) {
|
||||
int stackIndex = i + stackOffset;
|
||||
if (stackIndex < trace.length) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("║ ").append(level).append(this.getSimpleClassName(trace[stackIndex].getClassName())).append(".").append(trace[stackIndex].getMethodName()).append(" ").append(" (").append(trace[stackIndex].getFileName()).append(":").append(trace[stackIndex].getLineNumber()).append(")");
|
||||
level = level + " ";
|
||||
this.logChunk(logLevel, tag, builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void logBottomBorder(LogLevel logLevel, String tag) {
|
||||
this.logChunk(logLevel, tag, "╚════════════════════════════════════════════════════════════════════════════════════════");
|
||||
}
|
||||
|
||||
private void logDivider(LogLevel logLevel, String tag) {
|
||||
this.logChunk(logLevel, tag, "╟────────────────────────────────────────────────────────────────────────────────────────");
|
||||
}
|
||||
|
||||
private void logContent( LogLevel logLevel, String tag, String chunk) {
|
||||
String[] lines = chunk.split( System.getProperty("line.separator"));
|
||||
|
||||
for ( String line : lines) {
|
||||
this.logChunk(logLevel, tag, "║ " + line);
|
||||
}
|
||||
}
|
||||
|
||||
private void logChunk( LogLevel logLevel, String tag, String chunk) {
|
||||
String finalTag = this.checkTag(tag);
|
||||
switch (logLevel) {
|
||||
case VERBOSE:
|
||||
Log.v(finalTag, chunk);
|
||||
break;
|
||||
case INFO:
|
||||
Log.i(finalTag, chunk);
|
||||
break;
|
||||
case DEBUG:
|
||||
Log.d(finalTag, chunk);
|
||||
break;
|
||||
case WARN:
|
||||
Log.w(finalTag, chunk);
|
||||
break;
|
||||
case ERROR:
|
||||
Log.e(finalTag, chunk);
|
||||
break;
|
||||
case OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getSimpleClassName( String name) {
|
||||
int lastIndex = name.lastIndexOf(".");
|
||||
return name.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
private String checkTag( String tag) {
|
||||
return TextUtils.isEmpty(tag) ? TAG : tag;
|
||||
}
|
||||
|
||||
private String createMessage( String message, Object... args) {
|
||||
return (args == null || args.length == 0) ? message : String.format(message, args);
|
||||
}
|
||||
|
||||
private int getMethodCount() {
|
||||
return mSettings.getMethodCount();
|
||||
}
|
||||
|
||||
private int getStackOffset( StackTraceElement[] trace) {
|
||||
for (int i = 3; i < trace.length; ++i) {
|
||||
StackTraceElement e = trace[i];
|
||||
String name = e.getClassName();
|
||||
if (!name.equals(LoggerPrinter.class.getName()) && !name.equals(Logger.class.getName())) {
|
||||
--i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
package com.mogo.utils.logger;
|
||||
|
||||
public interface Printer {
|
||||
Settings init( LogLevel logLevel );
|
||||
|
||||
Settings getSettings();
|
||||
|
||||
void d( String tag, String message, Object... args );
|
||||
|
||||
void e( String tag, String message, Object... args );
|
||||
|
||||
void e( String tag, Throwable throwable, String message, Object... args );
|
||||
|
||||
void w( String tag, String message, Object... args );
|
||||
|
||||
void i( String tag, String message, Object... args );
|
||||
|
||||
void v( String tag, String message, Object... args );
|
||||
|
||||
void json( String tag, String json );
|
||||
|
||||
void xml( String tag, String xml );
|
||||
|
||||
void normalLog( String tag, String message );
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
package com.mogo.utils.logger;
|
||||
|
||||
public final class Settings {
|
||||
private int methodCount = 2;
|
||||
private boolean showThreadInfo = true;
|
||||
private int methodOffset = 0;
|
||||
private LogLevel logLevel = LogLevel.DEBUG;
|
||||
|
||||
public Settings() {
|
||||
}
|
||||
|
||||
public Settings hideThreadInfo() {
|
||||
this.showThreadInfo = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings setMethodCount(int methodCount) {
|
||||
if(methodCount < 0) {
|
||||
methodCount = 0;
|
||||
}
|
||||
|
||||
this.methodCount = methodCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings setLogLevel(LogLevel logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings setMethodOffset(int offset) {
|
||||
this.methodOffset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMethodCount() {
|
||||
return this.methodCount;
|
||||
}
|
||||
|
||||
public boolean isShowThreadInfo() {
|
||||
return this.showThreadInfo;
|
||||
}
|
||||
|
||||
public LogLevel getLogLevel() {
|
||||
return this.logLevel;
|
||||
}
|
||||
|
||||
public int getMethodOffset() {
|
||||
return this.methodOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public abstract class BaseParams {
|
||||
|
||||
private static final String TAG = "BaseParams";
|
||||
|
||||
protected ConcurrentHashMap< String, Object > urlParams;
|
||||
|
||||
protected BaseParams() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
public Object get( String key ) {
|
||||
return this.urlParams != null && key != null ? this.urlParams.get( key ) : "";
|
||||
}
|
||||
|
||||
protected BaseParams( Map< String, Object > source ) {
|
||||
this.init();
|
||||
Iterator iterator = source.entrySet().iterator();
|
||||
|
||||
while ( iterator.hasNext() ) {
|
||||
Map.Entry entry = ( Map.Entry ) iterator.next();
|
||||
this.put( ( String ) entry.getKey(), entry.getValue() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected BaseParams( String key, Object value ) {
|
||||
this.init();
|
||||
this.put( key, value );
|
||||
}
|
||||
|
||||
protected BaseParams( Object... keysAndValues ) {
|
||||
this.init();
|
||||
int len = keysAndValues.length;
|
||||
if ( len % 2 != 0 ) {
|
||||
throw new IllegalArgumentException( "Supplied arguments must be even" );
|
||||
} else {
|
||||
for ( int i = 0; i < len; i += 2 ) {
|
||||
String key = String.valueOf( keysAndValues[i] );
|
||||
Object value = keysAndValues[i + 1];
|
||||
this.put( key, value );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkValue( final Object value ) {
|
||||
if ( value instanceof CharSequence ) {
|
||||
return !TextUtils.isEmpty( ( CharSequence ) value );
|
||||
}
|
||||
|
||||
if ( value == null || value.getClass() == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Class< ? > clazz = value.getClass();
|
||||
return clazz.isPrimitive() ||
|
||||
clazz.isAssignableFrom( Boolean.class ) ||
|
||||
clazz.isAssignableFrom( Character.class ) ||
|
||||
clazz.isAssignableFrom( Byte.class ) ||
|
||||
clazz.isAssignableFrom( Short.class ) ||
|
||||
clazz.isAssignableFrom( Integer.class ) ||
|
||||
clazz.isAssignableFrom( Long.class ) ||
|
||||
clazz.isAssignableFrom( Float.class ) ||
|
||||
clazz.isAssignableFrom( Double.class );
|
||||
}
|
||||
|
||||
private boolean checkKey( String key ) {
|
||||
return !TextUtils.isEmpty( key );
|
||||
}
|
||||
|
||||
public BaseParams put( String key, Object value ) {
|
||||
if ( checkKey( key ) && checkValue( value ) ) {
|
||||
urlParams.put( key, value );
|
||||
} else {
|
||||
Logger.e( TAG, "parameter key is illegal or parameter value is illegal" );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object remove( String key ) {
|
||||
return this.urlParams.remove( key );
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Iterator< Map.Entry< String, Object > > iterator = this.urlParams.entrySet().iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
Map.Entry< String, Object > entry = iterator.next();
|
||||
if ( result.length() > 0 ) {
|
||||
result.append( "&" );
|
||||
}
|
||||
|
||||
result.append( entry.getKey() );
|
||||
result.append( "=" );
|
||||
result.append( entry.getValue() );
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.urlParams = new ConcurrentHashMap< String, Object >();
|
||||
}
|
||||
|
||||
public List< BasicNameValuePair > getParamsList() {
|
||||
LinkedList< BasicNameValuePair > pairs = new LinkedList< BasicNameValuePair >();
|
||||
Iterator< Map.Entry< String, Object > > iterator = this.urlParams.entrySet().iterator();
|
||||
|
||||
while ( iterator.hasNext() ) {
|
||||
Map.Entry< String, Object > entry = iterator.next();
|
||||
pairs.add( new BasicNameValuePair( entry.getKey(), entry.getValue() ) );
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
public Map< String, Object > getOriginMap() {
|
||||
return urlParams;
|
||||
}
|
||||
|
||||
public String getParamString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Iterator< BasicNameValuePair > iterator = getParamsList().iterator();
|
||||
|
||||
while ( iterator.hasNext() ) {
|
||||
BasicNameValuePair parameter = iterator.next();
|
||||
String key = parameter.getName();
|
||||
Object value = parameter.getValue();
|
||||
if ( result.length() > 0 ) {
|
||||
result.append( "&" );
|
||||
}
|
||||
|
||||
result.append( key );
|
||||
result.append( "=" );
|
||||
result.append( value );
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static class BasicNameValuePair {
|
||||
private String name;
|
||||
private Object value;
|
||||
|
||||
public BasicNameValuePair( String name, Object value ) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName( String name ) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue( Object value ) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
|
||||
|
||||
public class CallerNotAliveException extends Exception {
|
||||
|
||||
public CallerNotAliveException( String message){
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Retention( RetentionPolicy.SOURCE)
|
||||
@Target( ElementType.ANNOTATION_TYPE)
|
||||
public @interface CallerRestrictTo {
|
||||
Class<?>[] value();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.content.ContextWrapper;
|
||||
import android.view.View;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Retention( RetentionPolicy.SOURCE )
|
||||
@Target( ElementType.PARAMETER )
|
||||
@CallerRestrictTo( {
|
||||
Activity.class,
|
||||
Fragment.class,
|
||||
androidx.fragment.app.Fragment.class,
|
||||
View.class,
|
||||
Dialog.class,
|
||||
PopupWindow.class,
|
||||
ContextWrapper.class,
|
||||
Object.class
|
||||
} )
|
||||
public @interface CallerType {
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpParams extends BaseParams {
|
||||
public HttpParams() {
|
||||
}
|
||||
|
||||
public HttpParams( Map< String, Object > source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public HttpParams( Object... keysAndValues) {
|
||||
super(keysAndValues);
|
||||
}
|
||||
|
||||
public HttpParams( String key, Object value) {
|
||||
super(key, value);
|
||||
}
|
||||
|
||||
public List<BasicNameValuePair> getParamList() {
|
||||
List<BasicNameValuePair> list = getParamsList();
|
||||
Collections.sort(list, new KVPairComparator());
|
||||
return list;
|
||||
}
|
||||
|
||||
public String getSortedParamsString() {
|
||||
List<BasicNameValuePair> list = getParamList();
|
||||
StringBuilder sb = new StringBuilder(NetConfig.instance().getSignaturePrefix());
|
||||
for (BasicNameValuePair basicNameValuePair : list) {
|
||||
sb.append(basicNameValuePair.getName());
|
||||
sb.append(basicNameValuePair.getValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Map< String, Object > getParamsMap() {
|
||||
List<BasicNameValuePair> list = getParamList();
|
||||
HashMap< String, Object > map = new HashMap< String, Object >();
|
||||
for (BasicNameValuePair basicNameValuePair : list) {
|
||||
map.put(basicNameValuePair.getName(), basicNameValuePair.getValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getSortedUrlParamsString() {
|
||||
List<BasicNameValuePair> list = getParamList();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (BasicNameValuePair basicNameValuePair : list) {
|
||||
String key = basicNameValuePair.getName();
|
||||
Object value = basicNameValuePair.getValue();
|
||||
if (sb.length() > 0)
|
||||
sb.append("&");
|
||||
sb.append(key);
|
||||
sb.append("=");
|
||||
sb.append(value);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private class KVPairComparator implements Comparator<BasicNameValuePair> {
|
||||
public int compare(BasicNameValuePair pairA, BasicNameValuePair pairB) {
|
||||
return pairA.getName().compareTo(pairB.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.collection.ArraySet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.internal.tls.OkHostnameVerifier;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is a configuration class provided for clients.For better extension and customization,client can set customized parameters of network
|
||||
* based on their own application. However you should set these parameters before you get the global instance
|
||||
* of {@link okhttp3.OkHttpClient} by {@link OkHttpFactory} for the first time.<p/>
|
||||
* <p>
|
||||
* Some of the parameters have default values, so there is not a must to use this class.<p/>
|
||||
*/
|
||||
|
||||
public final class NetConfig {
|
||||
private long readTimeout = NetConstants.READ_TIMEOUT;
|
||||
private long writeTimeout = NetConstants.WRITE_TIMEOUT;
|
||||
private long connectTimeout = NetConstants.CONNECT_TIMEOUT;
|
||||
|
||||
private final Set< Interceptor > interceptors = new ArraySet<>();
|
||||
private final Set< Interceptor > networkInterceptors = new ArraySet<>();
|
||||
private final HostnameVerifier allowAllHostnameVerifier = new HostnameVerifier() {
|
||||
@Override
|
||||
public boolean verify( String hostname, SSLSession session ) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private String signaturePrefix = "com.foundation.network";
|
||||
private HostnameVerifier hostnameVerifier = OkHostnameVerifier.INSTANCE;
|
||||
private Map< String, Object > publicParams;
|
||||
private boolean isLoggable;
|
||||
private Context appContext;
|
||||
|
||||
private SSLContext sslContext;
|
||||
|
||||
private NetConfig() {
|
||||
}
|
||||
|
||||
private static final class SingletonHolder {
|
||||
private static final NetConfig INSTANCE = new NetConfig();
|
||||
}
|
||||
|
||||
public static NetConfig instance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public synchronized long getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setReadTimeout( int readTimeout ) {
|
||||
this.readTimeout = readTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized long getWriteTimeout() {
|
||||
return writeTimeout;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setWriteTimeout( int writeTimeout ) {
|
||||
this.writeTimeout = writeTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized long getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setConnectTimeout( int connectTimeout ) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized HostnameVerifier getHostnameVerifier() {
|
||||
return hostnameVerifier;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setHostnameVerifier( HostnameVerifier hostnameVerifier ) {
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setSignaturePrefix( String prefix ) {
|
||||
this.signaturePrefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized String getSignaturePrefix() {
|
||||
return signaturePrefix;
|
||||
}
|
||||
|
||||
public synchronized Set< Interceptor > getInterceptors() {
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
public synchronized NetConfig addInterceptor( Interceptor interceptor ) {
|
||||
interceptors.add( interceptor );
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized Set< Interceptor > getNetworkInterceptors() {
|
||||
return networkInterceptors;
|
||||
}
|
||||
|
||||
public synchronized NetConfig addNetworkInterceptor( Interceptor networkInterceptor ) {
|
||||
networkInterceptors.add( networkInterceptor );
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setPublicParams( Map< String, Object > publicParams ) {
|
||||
this.publicParams = publicParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized Map< String, Object > getPublicParams() {
|
||||
return publicParams;
|
||||
}
|
||||
|
||||
public synchronized boolean isLoggable() {
|
||||
return isLoggable;
|
||||
}
|
||||
|
||||
public synchronized void setLoggable( boolean loggable ) {
|
||||
isLoggable = loggable;
|
||||
}
|
||||
|
||||
public synchronized NetConfig setAppContext( Context appContext ) {
|
||||
if ( appContext instanceof Application ) {
|
||||
this.appContext = appContext;
|
||||
} else {
|
||||
this.appContext = appContext.getApplicationContext();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized Context getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
public synchronized SSLContext getSslContext() {
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
public synchronized void setSslContext( SSLContext sslContext ) {
|
||||
this.sslContext = sslContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.utils.network;
|
||||
|
||||
|
||||
public class NetConstants {
|
||||
/** 无数据 */
|
||||
public final static int NO_DATA = -800;
|
||||
/** 数据返回正常 */
|
||||
public final static int OK = 0;
|
||||
|
||||
public static final long READ_TIMEOUT = 20_000L;
|
||||
public static final long WRITE_TIMEOUT = 20_000L;
|
||||
public static final long CONNECT_TIMEOUT = 15_000L;
|
||||
}
|
||||