Commit e52e272f by amateur

'1'

0 parents
Showing 110 changed files with 4340 additions and 0 deletions
*.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
local.properties
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="false" />
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
</component>
</project>
\ No newline at end of file \ No newline at end of file
<?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_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file \ No newline at end of file
/build
\ No newline at end of file \ No newline at end of file
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 29
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.polysoft.nafmii"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "API_HOST", "\"http://new.ynyc6666.com/shop/server/\""
buildConfigField "String", "WX_APPID", "\"1234567890\""
ndk {
abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
}
}
buildTypes {
release {
minifyEnabled true //是否混淆
zipAlignEnabled true //是否设置zip对齐优化
shrinkResources true // 移除无用的resource文件
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
pro { // 预生产
resValue "string", "app_name", "Nafmii-pro"
}
beta { // 测试
resValue "string", "app_name", "Nafmii-beta"
applicationIdSuffix "beta"
}
dev {
minifyEnabled false
resValue "string", "app_name", "Nafmii-dev"
applicationIdSuffix "dev"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
ndkVersion '20.0.5594570'
}
dependencies {
implementation 'androidx.wear:wear:1.0.0'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'ren.yale.android:cachewebviewlib:2.1.8'
implementation 'com.alibaba:fastjson:1.1.72.android'
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.7.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'me.jessyan:autosize:1.2.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
compileOnly 'com.google.android.wearable:wearable:2.6.0'
}
\ No newline at end of file \ No newline at end of file
# 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
-dontwarn dalvik.**
-dontwarn com.tencent.smtt.**
-keep class com.tencent.smtt.** {
*;
}
-keep class com.tencent.tbs.** {
*;
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii;
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.polysoft.nafmill", appContext.getPackageName());
}
}
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.polysoft.nafmii">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Nafmii.Fullscreen"
android:usesCleartextTraffic="true">
<activity android:name=".activity.InputUrlActivity"></activity>
<meta-data
android:name="design_width_in_dp"
android:value="360" />
<meta-data
android:name="design_height_in_dp"
android:value="750" />
<activity
android:name=".activity.MainActivity"
android:theme="@style/Nafmii.Fullscreen.NoTitleBar.Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activity.BaseActivity" />
<activity android:name=".activity.WebviewActivity" />
<activity
android:name=".activity.HomeActivity"
android:theme="@style/Nafmii.Fullscreen.NoTitleBar" />
<activity
android:name=".activity.GuideActivity"
android:theme="@style/Nafmii.Fullscreen.NoTitleBar" />
<service
android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
android:label="dexopt"
android:process=":dexopt" />
</application>
</manifest>
\ No newline at end of file \ No newline at end of file
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,maximun-scale=1,mininum-scsle=1,user-scale=1">
<title>file chooser</title>
<style>
.filechooser{
width:95%;
height: 50px;
-webkit-background-clip: border-box;
}
</style>
<script >
var display=function (){
var path=document.getElementById("file_chooser").textContent;
document.getElementById("filechooser_display").innerHTML("<b>"+path+"</b>");
}
</script>
</head>
<body style="padding-top:100px;">
<ul class="listview">
<li class="listviewItem">
<fieldset class="itemset">
<input class="filechooser" id="file_chooser" type="file" placeholder="file path" onchange="display()" oninput="display()"><br>
<p id="filechooser_display"></p>
<div class="line_black"></div>
</fieldset>
</li>
</ul>
</body>
</html>
\ No newline at end of file \ No newline at end of file
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, maximum-scale=1, minimum-scale=1, user-scale=1">
<title></title>
<style type="text/css" rel="stylesheet">
.line{
width:100%;
background: #000000;
height: 1px;
margin-top: 5px;
margin-bottom: 5px;
}
</style>
</head>
<body>
<video style="width:100%; height: auto;" controls>
<source src=http://125.64.133.74/data9/userfiles/video02/2014/12/11/2796948-280-068-1452.mp4 >
</video>
<div style="width:100%;height: 25px;"></div>
<button onclick="click_x5()" style="width:50%;height: 50px; float: left"> x5模式全屏</button>
<button onclick="click_normal()" style="width:50%;height: 50px;"> 普通模式全屏</button>
<div class="line"></div>
<button onclick="click_LiteWnd()" style="width:50%;height: 50px; float: left"> 小窗模式</button>
<button onclick="click_normal()" style="width:50%;height: 50px;"> 关闭小窗模式</button>
<div class="line"></div>
<button onclick="click_PageVideo()" style="width:50%;height: 50px; float: left"> 页面内全屏</button>
<button onclick="click_normal()" style="width:50%;height: 50px;"> 关闭页面内全屏</button>
</body>
<script type="text/javascript" >
function click_x5 (){
Android.onX5ButtonClicked();
location.reload(false);
}
function click_normal(){
Android.onCustomButtonClicked();
location.reload(false);
}
function click_LiteWnd(){
Android.onLiteWndButtonClicked();
location.reload(false);
}
function click_PageVideo(){
Android.onPageVideoClicked();
location.reload(false);
}
</script>
</html>
\ No newline at end of file \ No newline at end of file
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" context="width=device-width, maximum-scale=1, minimum-scale=0.5, user-scale=no">
<title><h2>请长按一下html元素</h2></title>
<style type="text/css" rel="stylesheet">
h2,p,input{
font-size: 50px;
}
</style>
</head>
<body>
<h2>请长按一下html元素</h2><br>
<p style="width:100%;">hello world!</p><br>
<input style="width: 100%;" placeholder="文本编辑区" type="text"><br>
<img src="image/nearly.png" style="width: 100% ; height: auto;" ><br>
</body>
</html>
\ No newline at end of file \ No newline at end of file
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,maximun-scale=1,mininum-scsle=1,user-scale=1">
<title>首页</title>
<style>
</style>
<script >
</script>
</head>
<body>
</body>
</html>
\ No newline at end of file \ No newline at end of file
const NativeInteface = [
'callNativePay',
'callNativeShare',
'callNativeAppInfo',
'callNativeCamera',
'callNativeAlbum',
'callNativeUpdate',
'callNativeMobile'
]
const JsInteface = [
'payResult',
'shareResult',
'photoResult',
'appInfoResult'
]
class Inteface {
constructor() {
this.listeners = {}
this.__init()
}
on (methodName, callback) {
this.listeners[methodName] = callback
}
__init () {
NativeInteface.forEach(methodName => {
this[methodName] = (data, jsMethodName, callback) => {
try {
if (jsMethodName) {
this.listeners[jsMethodName] = callback
}
const json = JSON.stringify(jsMethodName && { jsMethodName, data } || { data })
if (window.$NativeApi) {
window.$NativeApi[methodName](json)
} else if (window.webkit) {
window.webkit.messageHandlers[methodName](json)
}
} catch (e) {
callback && callback()
console.warn("===========无效,非内置调用", methodName);
}
}
})
JsInteface.forEach(methodName => {
this[methodName] = (data) => {
const objValue = data ? JSON.parse(data) : data
this.listeners[methodName](objValue)
}
})
}
}
window.$api = new Inteface()
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h3>WebSocket 测试</h3>
<p id="result"></p>
</body>
<script type="text/javascript">
var my_websocket = new WebSocket("ws://127.0.0.1:55555");
var result = document.getElementById("result");
if(!my_websocket){
result.innerHTML += "无法创建websocket实例<br>";
window.console.log("websocket can not be created!");
}else{
window.console.log("websocket create success!");
}
my_websocket.onerror = function(){
result.innerHTML+="websocket连接失败<br>";
}
my_websocket.onclose = function(){
result.innerHTML+="websocket 关闭<br>";
}
my_websocket.onmessage = function(event){
result.innerHTML+="收到数据:"+event.data+" <br>";
}
</script>
</html>
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii;
import android.app.Application;
import com.polysoft.nafmii.utils.CtxUtils;
import com.polysoft.nafmii.webview.X5Core;
import me.jessyan.autosize.AutoSizeConfig;
import ren.yale.android.cachewebviewlib.WebViewCacheInterceptor;
import ren.yale.android.cachewebviewlib.WebViewCacheInterceptorInst;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
CtxUtils.setApplication(this);
AutoSizeConfig.getInstance()
.setDesignWidthInDp(414)
.setDesignHeightInDp(896);
WebViewCacheInterceptor.Builder builder = new WebViewCacheInterceptor.Builder(this);
builder.setDebug(BuildConfig.DEBUG);
WebViewCacheInterceptorInst.getInstance().init(builder);
}
}
package com.polysoft.nafmii.activity;
import android.os.Bundle;
import android.view.KeyEvent;
import androidx.appcompat.app.AppCompatActivity;
import com.polysoft.nafmii.utils.StatusBarUtils;
import com.polysoft.nafmii.utils.ToastUtils;
import java.util.Timer;
import java.util.TimerTask;
public class BaseActivity extends AppCompatActivity {
private boolean mBackKeyPressed = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
this.initStatusBar();
}
private void initStatusBar() {
//沉浸式代码配置
//当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding
StatusBarUtils.setRootViewFitsSystemWindows(this, false);
//设置状态栏透明
StatusBarUtils.setTranslucentStatus(this);
//一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清
//所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容
if (!StatusBarUtils.setStatusBarDarkTheme(this, true)) {
//如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,
//这样半透明+白=灰, 状态栏的文字能看得清
StatusBarUtils.setStatusBarColor(this, 0x55000000);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (!this.mBackKeyPressed) {
ToastUtils.showLong("再点击一次退出程序");
this.mBackKeyPressed = true;
new Timer().schedule(new TimerTask() {
@Override
public void run() {
mBackKeyPressed = false;
}
}, 1000);
} else {
finish();
System.exit(0);
}
return false;
}
return super.onKeyDown(keyCode, event);
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RadioButton;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.polysoft.nafmii.R;
import com.polysoft.nafmii.utils.IntentUtils;
import com.polysoft.nafmii.utils.SpUtils;
import java.util.ArrayList;
import java.util.List;
public class GuideActivity extends BaseActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_guide);
this.initView();
}
private void initView() {
ViewPager viewPager = super.findViewById(R.id.guide_viewpager);
List<View> viewList = this.initGuideImage();
viewPager.setAdapter(new ViewPagerAdapter(viewList));
viewPager.setCurrentItem(0);
RadioButton point1 = super.findViewById(R.id.guide_point1);
RadioButton point2 = super.findViewById(R.id.guide_point2);
RadioButton point3 = super.findViewById(R.id.guide_point3);
RadioButton[] points = new RadioButton[]{point1, point2, point3};
View goHomeBtn = super.findViewById(R.id.guide_btn_gohome);
goHomeBtn.setOnClickListener(this);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
points[position].setChecked(true);
boolean show = viewList.size() == (position + 1);
goHomeBtn.setVisibility(show ? View.VISIBLE : View.GONE);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private List<View> initGuideImage() {
int[] arrays = new int[]{R.mipmap.guide1_bg, R.mipmap.guide2_bg, R.mipmap.guide3_bg};
List<View> viewList = new ArrayList<>();
int match = ViewGroup.LayoutParams.MATCH_PARENT;
for (int i = 0; i < arrays.length; i++) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(arrays[i]);
imageView.setLayoutParams(new ViewGroup.LayoutParams(match, match));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
viewList.add(imageView);
}
return viewList;
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.guide_btn_gohome) {
SpUtils.putBoolean("isFirstRun", true);
IntentUtils.startActivity(this, HomeActivity.class);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
class ViewPagerAdapter extends PagerAdapter {
private List<View> viewList = new ArrayList<>();
ViewPagerAdapter(List<View> viewList) {
this.viewList = viewList;
}
@Override
public int getCount() {
return this.viewList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = this.viewList.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(viewList.get(position));
}
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.activity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.RadioButton;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.polysoft.nafmii.R;
import com.polysoft.nafmii.enums.ModulesEnum;
import com.polysoft.nafmii.fragment.FingerprintDialogFragment;
import com.polysoft.nafmii.fragment.ModulesFragmentMgr;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HomeActivity extends WebviewActivity implements View.OnClickListener, ModulesFragmentMgr.OnChangeModuleListener {
private ModulesFragmentMgr modulesMgr;
private HashMap<ModulesEnum, RadioButton> moduleViewsMap;
@Override
public void onCoreInitFinished(boolean flag) {
super.setContentView(R.layout.activity_home);
this.initView();
this.initHomeModule();
}
private void initView() {
super.findViewById(R.id.home_footer_group).setVisibility(View.VISIBLE);
HashMap<ModulesEnum, RadioButton> modulesMap = new HashMap<>();
modulesMap.put(ModulesEnum.HOME, super.findViewById(R.id.home_btn_home));
modulesMap.put(ModulesEnum.MEMBER, super.findViewById(R.id.home_btn_member));
modulesMap.put(ModulesEnum.LEARN, super.findViewById(R.id.home_btn_learn));
modulesMap.put(ModulesEnum.MY, super.findViewById(R.id.home_btn_my));
Iterator<Map.Entry<ModulesEnum, RadioButton>> iterator = modulesMap.entrySet().iterator();
while (iterator.hasNext()) {
iterator.next().getValue().setOnClickListener(this);
}
this.moduleViewsMap = modulesMap;
}
private void initHomeModule() {
FragmentManager fragmentManager = super.getSupportFragmentManager();
int containerId = R.id.home_container_framelayout;
this.modulesMgr = new ModulesFragmentMgr(fragmentManager, containerId);
this.modulesMgr.addChangeModuleLsitener(this);
this.modulesMgr.showInitFragment(new ModulesEnum[]{
ModulesEnum.HOME, ModulesEnum.MEMBER,
ModulesEnum.LEARN, ModulesEnum.MY
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.home_btn_home:
this.modulesMgr.showModule(ModulesEnum.HOME);
break;
case R.id.home_btn_member:
this.modulesMgr.showModule(ModulesEnum.MEMBER);
break;
case R.id.home_btn_learn:
this.modulesMgr.showModule(ModulesEnum.LEARN);
break;
case R.id.home_btn_my:
this.modulesMgr.showModule(ModulesEnum.MY);
break;
default:
break;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (!this.modulesMgr.onBackStack()) {
return false;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
public void changeModule(ModulesEnum module, Fragment fragment) {
RadioButton moduleButton = this.moduleViewsMap.get(module);
if (null != moduleButton) {
moduleButton.setChecked(true);
}
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import com.polysoft.nafmii.R;
public class InputUrlActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_input_url);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText inputUrl = findViewById(R.id.input_url);
String url = inputUrl.getText().toString();
}
});
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.activity;
import android.Manifest;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.polysoft.nafmii.R;
import com.polysoft.nafmii.constants.ServerApi;
import com.polysoft.nafmii.enums.StateEnum;
import com.polysoft.nafmii.fragment.AdvertisementFragment;
import com.polysoft.nafmii.fragment.FingerprintDialogFragment;
import com.polysoft.nafmii.net.RequestBack;
import com.polysoft.nafmii.utils.IntentUtils;
import com.polysoft.nafmii.utils.PermissionUtils;
import com.polysoft.nafmii.utils.SpUtils;
import com.polysoft.nafmii.utils.ToastUtils;
import com.polysoft.nafmii.webview.X5Core;
public class MainActivity extends BaseActivity {
private static final String TAG = MainActivity.class.getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.checkAndRequestPermission();
}
private void checkAndRequestPermission() {
String[] permissions = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
PermissionUtils.requestMorePermissions(this, permissions);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode != PermissionUtils.REQUEST_CODE) {
return;
}
if (this.checkPermissionSetting()) {
X5Core.init();
this.showAdvertisement();
}
}
private boolean checkPermissionSetting() {
// 必要读写权限申请失败
if (!PermissionUtils.checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ToastUtils.showLong("请授权APP必要运行权限");
new CountDownTimer(2000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
PermissionUtils.toAppSetting(MainActivity.this);
}
}.start();
return false;
}
return true;
}
private void showAdvertisement() {
if (!SpUtils.getBoolean("isFirstRun", false)) {
IntentUtils.startActivity(this, GuideActivity.class);
return;
}
ServerApi.get(ServerApi.getAdvertSettings, new RequestBack<JSONObject>() {
@Override
protected void onResponse(StateEnum state, JSONObject data, String message) {
if (state == StateEnum.OK) {
JSONArray jsonArray = data.getJSONArray("item");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject item = jsonArray.getJSONObject(i);
Fragment fragment = AdvertisementFragment.getInstance(item.toJSONString());
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.main_framelayout, fragment).commit();
return;
}
}
}
});
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.activity;
import android.os.Bundle;
import com.polysoft.nafmii.webview.X5Core;
public abstract class WebviewActivity extends BaseActivity implements X5Core.InitCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
X5Core.setInitCallback(this);
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.broadcast;
import android.content.Context;
import android.content.Intent;
public class PhotosReceiver extends Receiver<String> {
public static final String ACTION_CAMERA = "com.polysoft.nafmii.action_camera";
public static final String ACTION_ALBUM = "com.polysoft.nafmii.action_album";
protected PhotosReceiver(Context context) {
super(context);
}
public static Receiver<String> getInstance(Context context) {
Receiver<String> receiver = getReceiver(PhotosReceiver.class);
return null != receiver ? receiver : new PhotosReceiver(context.getApplicationContext());
}
public static void sendBroadcastCamera(Context context, String filepath) {
Intent intent = new Intent().setAction(ACTION_CAMERA);
intent.putExtra("data", filepath);
onSendBroadcast(context, intent);
}
public static void sendBroadcastAlbum(Context context, String filepath) {
Intent intent = new Intent().setAction(ACTION_ALBUM);
intent.putExtra("data", filepath);
onSendBroadcast(context, intent);
}
@Override
protected String[] getActions() {
return new String[]{ACTION_CAMERA, ACTION_ALBUM};
}
@Override
protected String onReceiverData(String action, Intent intent) {
if (ACTION_CAMERA.equals(action)) {
return intent.getStringExtra("data");
} else if (ACTION_ALBUM.equals(action)) {
return intent.getStringExtra("data");
}
return null;
}
}
package com.polysoft.nafmii.broadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public abstract class Receiver<T> extends BroadcastReceiver {
private static final Map<String, Receiver> registerMap = new HashMap<>();
protected final Context context;
protected final Map<String, ReceiverListener<T>> listenerMap = new HashMap<>();
private final String KEY_DEFAULT_LISTENER = "DEFAULT_LISTENER";
protected Receiver(Context context) {
this.context = context;
}
protected static <T> Receiver<T> getReceiver(Class<? extends Receiver> receiver) {
return registerMap.get(receiver.getName());
}
protected static void onSendBroadcast(Context context, Intent intent) {
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
protected abstract String[] getActions();
protected abstract T onReceiverData(String action, Intent intent);
public void register() {
if (null != getReceiver(this.getClass())) {
return;
}
IntentFilter filter = new IntentFilter();
String[] actions = this.getActions();
for (int i = 0; i < actions.length; i++) {
filter.addAction(actions[i]);
}
LocalBroadcastManager.getInstance(this.context).registerReceiver(this, filter);
registerMap.put(this.getClass().getName(), this);
}
public void unregister() {
this.listenerMap.clear();
if (null == getReceiver(this.getClass())) {
return;
}
registerMap.remove(this.getClass().getName());
LocalBroadcastManager.getInstance(this.context).unregisterReceiver(this);
}
public void addDefaultListener(ReceiverListener<T> listener) {
this.addListener(KEY_DEFAULT_LISTENER, listener);
}
public void addListener(String key, ReceiverListener<T> listener) {
this.listenerMap.put(key, listener);
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
T data = this.onReceiverData(action, intent);
Iterator<String> iterator = this.listenerMap.keySet().iterator();
while (iterator.hasNext()) {
ReceiverListener<T> listener = this.listenerMap.get(iterator.next());
// 同步判断
if (null != listener) {
listener.onReceiverResult(action, data);
}
}
}
}
package com.polysoft.nafmii.broadcast;
public interface ReceiverListener<T> {
void onReceiverResult(String action, T data);
}
package com.polysoft.nafmii.broadcast;
import android.content.Context;
import android.content.Intent;
import com.alibaba.fastjson.JSON;
import com.polysoft.nafmii.wechat.ShareResult;
public class ShareReceiver extends Receiver<ShareResult> {
public static final String ACTION = "com.polysoft.nafmii.action_share";
protected ShareReceiver(Context context) {
super(context);
}
public static Receiver<ShareResult> getInstance(Context context) {
Receiver<ShareResult> receiver = getReceiver(ShareReceiver.class);
return null != receiver ? receiver : new ShareReceiver(context.getApplicationContext());
}
public static void sendBroadcast(Context context, ShareResult data) {
Intent intent = new Intent().setAction(ACTION);
intent.putExtra("data", JSON.toJSONString(data));
onSendBroadcast(context, intent);
}
@Override
protected String[] getActions() {
return new String[]{ACTION};
}
@Override
protected ShareResult onReceiverData(String action, Intent intent) {
if (ACTION.equals(action)) {
String dataJson = intent.getStringExtra("data");
return JSON.parseObject(dataJson, ShareResult.class);
}
return null;
}
}
package com.polysoft.nafmii.constants;
import com.polysoft.nafmii.BuildConfig;
import com.polysoft.nafmii.enums.StateEnum;
import com.polysoft.nafmii.net.OkhttpApi;
import com.polysoft.nafmii.net.RequestBack;
import java.util.Map;
public class ServerApi {
public static final String url_version = "";
public static final String getAdvertSettings = "storeSetting/getAdvertSettings";
public static <T> void get(String url, RequestBack<T> callback) {
get(url, null, callback);
}
public static <T> void get(String url, Map<String, String> param, RequestBack<T> callback) {
String newUrl = BuildConfig.API_HOST + url;
OkhttpApi.doGet(newUrl, param, callback);
}
public static <T> void post(String url, String param, RequestBack<T> callback) {
String newUrl = BuildConfig.API_HOST + url;
OkhttpApi.doPost(newUrl, param, callback);
}
}
package com.polysoft.nafmii.enums;
public enum ModulesEnum {
HOME("home", "file:///android_asset/webpage/fileChooser.html"),
MEMBER("member", "file:///android_asset/webpage/fileChooser.html"),
LEARN("learn", "http://debugtbs.qq.com"),
MY("my", "http://192.168.43.183:8080");
public final String name;
public final String webUrl;
ModulesEnum(String tag, String url) {
this.name = tag;
this.webUrl = url;
}
public static ModulesEnum findModule(String name) {
if (HOME.name.equals(name)) {
return HOME;
} else if (MEMBER.name.equals(name)) {
return MEMBER;
} else if (LEARN.name.equals(name)) {
return LEARN;
} else if (MY.name.equals(name)) {
return MY;
}
return null;
}
}
package com.polysoft.nafmii.enums;
public enum StateEnum {
OK(0, "成功"),
FAIL(-1, "失败");
public final int state;
public final String name;
StateEnum(int state, String name) {
this.state = state;
this.name = name;
}
}
package com.polysoft.nafmii.fragment;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.DrawableImageViewTarget;
import com.bumptech.glide.request.transition.Transition;
import com.polysoft.nafmii.R;
import com.polysoft.nafmii.activity.HomeActivity;
import com.polysoft.nafmii.utils.IntentUtils;
public class AdvertisementFragment extends Fragment implements View.OnClickListener {
private ImageView mImgView;
private TextView mCountDown;
private AdvertisementFragment() {
}
public static Fragment getInstance(String data) {
Fragment fragment = new AdvertisementFragment();
Bundle bundle = new Bundle();
bundle.putString("data", data);
fragment.setArguments(bundle);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_advertisement, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.advertisement_pass).setOnClickListener(this);
this.mImgView = view.findViewById(R.id.advertisement_imgview);
this.mCountDown = view.findViewById(R.id.advertisement_countdown);
this.loadAdvertisementImage();
}
@Override
public void onClick(View v) {
this.gotoHome();
}
private void loadAdvertisementImage() {
String json = getArguments().getString("data");
JSONObject item = JSON.parseObject(json);
String id = item.getString("id");
String description = item.getString("description");
String picture = item.getString("picture");
String url = item.getString("url");
Glide.with(getContext()).load(picture).into(new DrawableImageViewTarget(this.mImgView){
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
super.onResourceReady(resource, transition);
startCountDown();
}
});
}
private void startCountDown() {
long unit = 1000, maxSecond = 5;
mCountDown.setText(String.format("%ds", maxSecond));
new CountDownTimer(maxSecond * unit, unit) {
@Override
public void onTick(long millisUntilFinished) {
long second = millisUntilFinished / unit;
Log.d("CountDownTimer", "onTick: " + second);
mCountDown.setText(String.format("%ds", second));
}
@Override
public void onFinish() {
gotoHome();
}
}.start();
}
private synchronized void gotoHome() {
if (null != getActivity() && !getActivity().isFinishing()) {
IntentUtils.startActivity(getActivity(), HomeActivity.class);
}
}
}
package com.polysoft.nafmii.fragment;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import com.polysoft.nafmii.R;
import javax.crypto.Cipher;
@TargetApi(23)
public class FingerprintDialogFragment extends DialogFragment {
private FingerprintManager fingerprintManager;
private CancellationSignal mCancellationSignal;
private Cipher mCipher;
private Activity mActivity;
private TextView errorMsg;
/**
* 标识是否是用户主动取消的认证。
*/
private boolean isSelfCancelled;
public void setCipher(Cipher cipher) {
mCipher = cipher;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = getActivity();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fingerprintManager = getContext().getSystemService(FingerprintManager.class);
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fingerprint_dialog, container, false);
errorMsg = v.findViewById(R.id.error_msg);
TextView cancel = v.findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
stopListening();
}
});
return v;
}
@Override
public void onResume() {
super.onResume();
// 开始指纹认证监听
startListening(mCipher);
}
@Override
public void onPause() {
super.onPause();
// 停止指纹认证监听
stopListening();
}
private void startListening(Cipher cipher) {
isSelfCancelled = false;
mCancellationSignal = new CancellationSignal();
fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), mCancellationSignal, 0, new FingerprintManager.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
if (!isSelfCancelled) {
errorMsg.setText(errString);
if (errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
Toast.makeText(mActivity, errString, Toast.LENGTH_SHORT).show();
dismiss();
}
}
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
errorMsg.setText(helpString);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
Toast.makeText(mActivity, "指纹认证成功", Toast.LENGTH_SHORT).show();
mActivity.finish();
}
@Override
public void onAuthenticationFailed() {
errorMsg.setText("指纹认证失败,请再试一次");
}
}, null);
}
private void stopListening() {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
mCancellationSignal = null;
isSelfCancelled = true;
}
}
}
package com.polysoft.nafmii.fragment;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
public class HomeViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments;
public HomeViewPagerAdapter(@NonNull FragmentManager fm, List<Fragment> fragments) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.mFragments = fragments;
}
@NonNull
@Override
public Fragment getItem(int position) {
return this.mFragments.get(position);
}
@Override
public int getCount() {
return this.mFragments.size();
}
}
package com.polysoft.nafmii.fragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.polysoft.nafmii.enums.ModulesEnum;
import java.util.List;
public class ModulesFragmentMgr implements FragmentManager.OnBackStackChangedListener {
private FragmentManager manager;
private int containerId;
private ModulesEnum currentModule;
private OnChangeModuleListener changeListener;
public ModulesFragmentMgr(FragmentManager manager, int containerId) {
this.manager = manager;
this.containerId = containerId;
}
public void addChangeModuleLsitener(OnChangeModuleListener listener) {
this.changeListener = listener;
}
public void showInitFragment(ModulesEnum[] modules) {
for (int i = 1; i < modules.length; i++) {
this.addModuleFragment(modules[i]);
}
Fragment fragment = this.addModuleFragment(modules[0]);
FragmentTransaction transaction = this.manager.beginTransaction();
transaction.show(fragment).commitNow();
this.setCurrentModule(modules[0]);
}
public Fragment getCurrentFragment() {
String tag = this.currentModule.name;
return this.manager.findFragmentByTag(tag);
}
public boolean onBackStack() {
if (this.manager.getBackStackEntryCount() > 0) {
this.manager.addOnBackStackChangedListener(this);
this.manager.popBackStack();
return false;
}
return true;
}
public void showModule(ModulesEnum module) {
if (module.name.equals(this.currentModule.name)) {
return;
}
Fragment fragment = this.findFragment(module);
FragmentTransaction transaction = this.manager.beginTransaction();
transaction.hide(this.getCurrentFragment());
transaction.addToBackStack("").show(fragment).commit();
this.setCurrentModule(module);
}
public Fragment findFragment(ModulesEnum module) {
Fragment fragment = this.manager.findFragmentByTag(module.name);
if (null == fragment) {
return this.addModuleFragment(module);
}
return fragment;
}
private Fragment addModuleFragment(ModulesEnum module) {
FragmentTransaction transaction = this.manager.beginTransaction();
Fragment fragment = WebViewFragment.newInstances(module.webUrl);
transaction.add(this.containerId, fragment, module.name).hide(fragment).commitNow();
return fragment;
}
private void setCurrentModule(ModulesEnum module) {
this.currentModule = module;
if (null != this.changeListener) {
Fragment fragment = this.getCurrentFragment();
this.changeListener.changeModule(module, fragment);
}
}
@Override
public void onBackStackChanged() {
List<Fragment> fragments = this.manager.getFragments();
for (int i = 0; i < fragments.size(); i++) {
Fragment fragment = fragments.get(i);
if (fragment.isVisible()) {
setCurrentModule(ModulesEnum.findModule(fragment.getTag()));
return ;
}
}
}
public static interface OnChangeModuleListener {
void changeModule(ModulesEnum module, Fragment fragment);
}
}
package com.polysoft.nafmii.fragment;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ValueCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.polysoft.nafmii.R;
import com.polysoft.nafmii.webview.JavaToJsinterface;
import com.polysoft.nafmii.webview.JsToJavaInterface;
import com.polysoft.nafmii.webview.MyWebViewClient;
import com.polysoft.nafmii.webview.WebviewLoadListener;
import com.polysoft.nafmii.webview.X5WebviewUtils;
import com.tencent.smtt.sdk.WebView;
public class WebViewFragment extends Fragment implements WebviewLoadListener {
private View rootView;
private ViewGroup layout;
private WebView webView;
public static WebViewFragment newInstances(String url) {
WebViewFragment fragment = new WebViewFragment();
Bundle bundle = new Bundle();
bundle.putString("url", url);
fragment.setArguments(bundle);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (null == this.rootView) {
this.rootView = inflater.inflate(R.layout.fragment_webview, container, false);
}
return this.rootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
this.layout = view.findViewById(R.id.webview_layout);
this.initWebview();
}
private void initWebview() {
WebView webView = X5WebviewUtils.create(getActivity());
webView.setWebViewClient(new MyWebViewClient(this));
JsToJavaInterface nativeApi = new JsToJavaInterface(getActivity(), new JavaToJsinterface(webView));
webView.addJavascriptInterface(nativeApi, "$NativeApi");
this.layout.removeAllViews();
int match = ViewGroup.LayoutParams.MATCH_PARENT;
this.layout.addView(webView, new ViewGroup.LayoutParams(match, match));
this.webView = webView;
Bundle bundle = getArguments();
String url = bundle.getString("url", "");
this.webView.loadUrl(url);
}
@Override
public void onDestroy() {
super.onDestroy();
X5WebviewUtils.destroy(this.webView);
}
@Override
public void onWebviewLoad(int type, Object param) {
if (type == WebviewLoadListener.TYPE_FINISH) {
} else if (type == WebviewLoadListener.TYPE_ERROR) {
}
}
@Override
public void onShowFileChooser(ValueCallback<Uri[]> filePathCallback, String[] acceptTypes, boolean isCapture) {
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.net;
import com.polysoft.nafmii.utils.IOUtils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class OkhttpApi {
private static OkHttpClient client = null;
private OkhttpApi() {
}
public static OkHttpClient getInstance() {
if (client == null) {
synchronized (OkhttpApi.class) {
if (client == null) {
client = new OkHttpClient();
}
}
}
return client;
}
public static void doGet(String url, RequestBack callback) {
doGet(url, null, callback);
}
public static void doGet(String url, Map<String, String> param, RequestBack callback) {
HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
if (null != param && !param.isEmpty()) {
for (Map.Entry<String, String> entry : param.entrySet()) {
builder.addQueryParameter(entry.getKey(), entry.getValue());
}
}
Request.Builder request = buildRequest(1);
request.url(builder.build()).get();
getInstance().newCall(request.build()).enqueue(new CallbackImpl(callback));
}
public static void doPost(String url, String param, RequestBack callback) {
MediaType mediaType = MediaType.parse("application/json;charset=UTF-8");
RequestBody body = RequestBody.create(param, mediaType);
Request.Builder request = buildRequest(1);
request.url(url).post(body);
getInstance().newCall(request.build()).enqueue(new CallbackImpl(callback));
}
public static void doUpload(String url, File file, RequestBack callback) {
doUpload(url, file, null, callback);
}
public static void doUpload(String url, File file, Map<String, String> param, RequestBack callback) {
}
public static void doDownload(String url, final File file) {
Request request = new Request.Builder().url(url).build();
getInstance().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (!response.isSuccessful()) {
return;
}
ResponseBody body = response.body();
long total = body.contentLength();
FileOutputStream fos = new FileOutputStream(file);
InputStream stream = body.byteStream();
try {
int len = 0;
long sum = 0;
byte[] buffer = new byte[1024 * 4];
while ((len = stream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
// sum += len;
// int progress = (int) (sum * 100 / total );
}
} catch (Exception e) {
IOUtils.close(fos);
IOUtils.close(stream);
}
}
});
}
private static Request.Builder buildRequest(int type) {
Request.Builder request = new Request.Builder();
request.addHeader("X-Requested-With", "XMLHttpRequest");
if (type == 1) { // post / get
request.addHeader("Content-Type", "application/json");
} else if (type == 2) {
request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
} else if (type == 3) { // 文件上传下载
request.addHeader("Content-Type", "multipart/form-data");
}
return request;
}
private static class CallbackImpl implements Callback {
private final RequestBack callback;
public CallbackImpl(RequestBack callback) {
this.callback = callback;
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
if (null != this.callback) {
this.callback.onParseResponse(call, null, e);
}
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (null != this.callback) {
this.callback.onParseResponse(call, response, null);
}
}
}
}
package com.polysoft.nafmii.net;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.polysoft.nafmii.enums.StateEnum;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import okhttp3.Call;
import okhttp3.Response;
public abstract class RequestBack<T> {
void onParseResponse(Call call, Response response, Exception e) {
int resCode = response.code();
if (resCode < 200 && resCode >= 300) {
String message = String.format("网络错误(%d)", resCode);
this.onResponse(StateEnum.FAIL, null, message);
return;
}
String string = null;
try {
string = response.body().string();
} catch (IOException ioException) {
ioException.printStackTrace();
}
if (TextUtils.isEmpty(string)) {
String message = "返回数据格式错误";
this.onResponse(StateEnum.FAIL, null, message);
return;
}
JSONObject res = JSON.parseObject(string);
int status = res.getInteger("status");
if (status == 200) {
String json = res.getString("obj");
Log.d("onParseResponse", "onParseResponse: " + json);
Type type = this.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] arguments = parameterizedType.getActualTypeArguments();
if (this.isTypeCalss(arguments[0], String.class)) {
this.onResponse(StateEnum.OK, (T) json, null);
} else if (this.isTypeCalss(arguments[0], JSONObject.class)) {
JSONObject data = res.getJSONObject("obj");
this.onResponse(StateEnum.OK, (T) data, null);
} else {
T data = JSON.parseObject(json, type);
this.onResponse(StateEnum.OK, data, null);
}
} else {
this.onResponse(StateEnum.FAIL, null, "解析异常");
}
} else {
String message = res.getString("msg");
this.onResponse(StateEnum.FAIL, null, message);
}
}
protected abstract void onResponse(StateEnum state, T data, String message);
private boolean isTypeCalss(Type type, Class c) {
return c.toString().equals(type.toString());
}
}
package com.polysoft.nafmii.utils;
import android.app.Application;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
public class CtxUtils {
private static Application application;
public static void setApplication(Application application) {
CtxUtils.application = application;
}
public static Application getApplication() {
return CtxUtils.application;
}
public static PackageInfo getPackageInfo() {
PackageManager manager = getApplication().getPackageManager();
String name = getApplication().getPackageName();
try {
return manager.getPackageInfo(name, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
package com.polysoft.nafmii.utils;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import androidx.core.content.FileProvider;
import java.io.File;
public class FileProviderUtils {
public static Uri getUriForFile(Context context, File file) {
if (Build.VERSION.SDK_INT >= 24) {
return getUriForFile24(context, file);
} else {
return Uri.fromFile(file);
}
}
public static Uri getUriForFile24(Context context, File file) {
String authority = context.getPackageName() + ".fileprovider";
return FileProvider.getUriForFile(context, authority, file);
}
public static String getUriPath(Context context, Uri uri) {
String[] filePathColumn = {MediaStore.MediaColumns.DATA};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
try {
if (null != cursor) {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(filePathColumn[0]);
return cursor.getString(idx);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != cursor) {
cursor.close();
}
}
return uri.getPath();
}
public static void setIntentDataAndType(Context context,
Intent intent,
String type,
File file,
boolean writeAble) {
if (Build.VERSION.SDK_INT >= 24) {
intent.setDataAndType(getUriForFile(context, file), type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
}
package com.polysoft.nafmii.utils;
import java.io.Closeable;
import java.io.IOException;
public class IOUtils {
public static void close(Closeable io) {
if (null == io) {
return;
}
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.polysoft.nafmii.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import java.io.File;
public class IntentUtils {
public static final int ACTIVITY_CODE_CHOOSERFILE = 0x1000;
public static final int ACTIVITY_CODE_CAMERA = 0x1001;
public static final int ACTIVITY_CODE_ALBUM = 0x1002;
public static Intent chooserIntent(Context context) {
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (null != captureIntent.resolveActivity(context.getPackageManager())) {
String filePath = getTakePhotoPath(context);
File imgFile = new File(filePath);
if (!imgFile.getParentFile().exists()) {
imgFile.getParentFile().mkdirs();
}
Uri imageUri = FileProviderUtils.getUriForFile(context, imgFile);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
captureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
}
Intent Photo = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent chooserIntent = Intent.createChooser(Photo, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent});
return chooserIntent;
}
return null;
}
public static Intent openCamera(Context context) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(getTakePhotoPath(context));
Uri imgUri = FileProviderUtils.getUriForFile(context, file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
return intent;
}
public static Intent openAlbum(Context context) {
Intent intent = new Intent(Intent.ACTION_PICK, null);
File file = new File(getTakePhotoPath(context));
FileProviderUtils.setIntentDataAndType(context, intent, "image/*", file, false);
return intent;
}
public static void startActivity(Activity activity, Class<? extends Activity> target) {
startActivity(activity, new Intent(activity, target));
}
public static void startActivity(Activity activity, Class<? extends Activity> target, Bundle bundle) {
Intent intent = new Intent(activity, target);
intent.putExtra("data", bundle);
startActivity(activity, intent);
}
public static void startActivity(Activity activity, Intent intent) {
activity.startActivity(intent);
activity.finish();
}
public static String getTakePhotoPath(Context context) {
return Environment.getExternalStorageDirectory()
+ File.separator + "Android"
+ File.separator + "data"
+ File.separator + context.getPackageName()
+ File.separator + "temp.jpg";
}
}
package com.polysoft.nafmii.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
public class PermissionUtils {
public static final int REQUEST_CODE = 10000;
/**
* 检测权限
*
* @return true:已授权; false:未授权;
*/
public static boolean checkPermission(Context context, String permission) {
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
}
/**
* 检测多个权限
*
* @return 未授权的权限
*/
public static List<String> checkMorePermissions(Context context, String[] permissions) {
List<String> permissionList = new ArrayList<>();
for (int i = 0; i < permissions.length; i++) {
if (!checkPermission(context, permissions[i]))
permissionList.add(permissions[i]);
}
return permissionList;
}
/**
* 请求权限
*/
public static void requestPermission(Context context, String permission) {
ActivityCompat.requestPermissions((Activity) context, new String[]{permission}, REQUEST_CODE);
}
/**
* 请求多个权限
*/
public static void requestMorePermissions(Context context, List permissionList) {
String[] permissions = (String[]) permissionList.toArray(new String[permissionList.size()]);
requestMorePermissions(context, permissions);
}
/**
* 请求多个权限
*/
public static void requestMorePermissions(Context context, String[] permissions) {
ActivityCompat.requestPermissions((Activity) context, permissions, REQUEST_CODE);
}
/**
* 判断是否已拒绝过权限
*
* @return
* @describe :如果应用之前请求过此权限但用户拒绝,此方法将返回 true;
* -----------如果应用第一次请求权限或 用户在过去拒绝了权限请求,
* -----------并在权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。
*/
public static boolean judgePermission(Context context, String permission) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission))
return true;
else
return false;
}
/**
* 检测权限并请求权限:如果没有权限,则请求权限
*/
public static boolean checkAndRequestPermission(Context context, String permission) {
if (!checkPermission(context, permission)) {
requestPermission(context, permission);
return false;
}
return true;
}
/**
* 检测并请求多个权限
*/
public static boolean checkAndRequestMorePermissions(Context context, String[] permissions) {
List<String> permissionList = checkMorePermissions(context, permissions);
if (!permissionList.isEmpty()) {
requestMorePermissions(context, permissionList);
return false;
}
return true;
}
/**
* 检测权限
*
* @describe:具体实现由回调接口决定
*/
public static void checkPermission(Context context, String permission, PermissionCheckCallBack callBack) {
if (checkPermission(context, permission)) { // 用户已授予权限
callBack.onHasPermission();
} else {
if (judgePermission(context, permission)) // 用户之前已拒绝过权限申请
callBack.onUserHasAlreadyTurnedDown(permission);
else // 用户之前已拒绝并勾选了不在询问、用户第一次申请权限。
callBack.onUserHasAlreadyTurnedDownAndDontAsk(permission);
}
}
/**
* 检测多个权限
*
* @describe:具体实现由回调接口决定
*/
public static void checkMorePermissions(Context context, String[] permissions, PermissionCheckCallBack callBack) {
List<String> permissionList = checkMorePermissions(context, permissions);
if (permissionList.size() == 0) { // 用户已授予权限
callBack.onHasPermission();
} else {
boolean isFirst = true;
for (int i = 0; i < permissionList.size(); i++) {
String permission = permissionList.get(i);
if (judgePermission(context, permission)) {
isFirst = false;
break;
}
}
String[] unauthorizedMorePermissions = (String[]) permissionList.toArray(new String[permissionList.size()]);
if (isFirst)// 用户之前已拒绝过权限申请
callBack.onUserHasAlreadyTurnedDownAndDontAsk(unauthorizedMorePermissions);
else // 用户之前已拒绝并勾选了不在询问、用户第一次申请权限。
callBack.onUserHasAlreadyTurnedDown(unauthorizedMorePermissions);
}
}
/**
* 检测并申请权限
*/
public static void checkAndRequestPermission(Context context, String permission, PermissionRequestSuccessCallBack callBack) {
if (checkPermission(context, permission)) {// 用户已授予权限
callBack.onHasPermission();
} else {
requestPermission(context, permission);
}
}
/**
* 检测并申请多个权限
*/
public static void checkAndRequestMorePermissions(Context context, String[] permissions, PermissionRequestSuccessCallBack callBack) {
List<String> permissionList = checkMorePermissions(context, permissions);
if (permissionList.size() == 0) { // 用户已授予权限
callBack.onHasPermission();
} else {
requestMorePermissions(context, permissionList);
}
}
/**
* 判断权限是否申请成功
*/
public static boolean isPermissionRequestSuccess(int[] grantResults) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
}
/**
* 用户申请权限返回
*/
public static void onRequestPermissionResult(Context context, String permission, int[] grantResults, PermissionCheckCallBack callback) {
if (PermissionUtils.isPermissionRequestSuccess(grantResults)) {
callback.onHasPermission();
} else {
if (PermissionUtils.judgePermission(context, permission)) {
callback.onUserHasAlreadyTurnedDown(permission);
} else {
callback.onUserHasAlreadyTurnedDownAndDontAsk(permission);
}
}
}
/**
* 用户申请多个权限返回
*/
public static void onRequestMorePermissionsResult(Context context, String[] permissions, PermissionCheckCallBack callback) {
boolean isBannedPermission = false;
List<String> permissionList = checkMorePermissions(context, permissions);
if (permissionList.size() == 0)
callback.onHasPermission();
else {
for (int i = 0; i < permissionList.size(); i++) {
if (!judgePermission(context, permissionList.get(i))) {
isBannedPermission = true;
break;
}
}
// 已禁止再次询问权限
if (isBannedPermission)
callback.onUserHasAlreadyTurnedDownAndDontAsk(permissions);
else // 拒绝权限
callback.onUserHasAlreadyTurnedDown(permissions);
}
}
/**
* 跳转到权限设置界面
*/
public static void toAppSetting(Context context) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
intent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
}
context.startActivity(intent);
}
public interface PermissionRequestSuccessCallBack {
/**
* 用户已授予权限
*/
void onHasPermission();
}
public interface PermissionCheckCallBack {
/**
* 用户已授予权限
*/
void onHasPermission();
/**
* 用户已拒绝过权限
*
* @param permission:被拒绝的权限
*/
void onUserHasAlreadyTurnedDown(String... permission);
/**
* 用户已拒绝过并且已勾选不再询问选项、用户第一次申请权限;
*
* @param permission:被拒绝的权限
*/
void onUserHasAlreadyTurnedDownAndDontAsk(String... permission);
}
}
package com.polysoft.nafmii.utils;
import android.content.Context;
import android.content.SharedPreferences;
public class SpUtils {
private static final String SP_NAME = "NAFMII";
public static void putBoolean(String key, boolean val) {
SharedPreferences.Editor edit = getSpMgr().edit();
edit.putBoolean(key, val).commit();
}
public static boolean getBoolean(String key, boolean def) {
return getSpMgr().getBoolean(key, def);
}
public static void putString(String key, String val) {
SharedPreferences.Editor edit = getSpMgr().edit();
edit.putString(key, val).commit();
}
public static String getString(String key, String def) {
return getSpMgr().getString(key, def);
}
private static SharedPreferences getSpMgr() {
return CtxUtils.getApplication().getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
}
}
package com.polysoft.nafmii.utils;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.IntDef;
import com.polysoft.nafmii.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class StatusBarUtils {
public final static int TYPE_MIUI = 0;
public final static int TYPE_FLYME = 1;
public final static int TYPE_M = 3;//6.0
@IntDef({TYPE_MIUI, TYPE_FLYME, TYPE_M})
@Retention(RetentionPolicy.SOURCE)
@interface ViewType {
}
/**
* 修改状态栏颜色,支持4.4以上版本
*
* @param colorId 颜色
*/
public static void setStatusBarColor(Activity activity, int colorId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.setStatusBarColor(colorId);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//使用SystemBarTintManager,需要先将状态栏设置为透明
setTranslucentStatus(activity);
SystemBarTintManager systemBarTintManager = new SystemBarTintManager(activity);
systemBarTintManager.setStatusBarTintEnabled(true);//显示状态栏
systemBarTintManager.setStatusBarTintColor(colorId);//设置状态栏颜色
}
}
/**
* 设置状态栏透明
*/
@TargetApi(19)
public static void setTranslucentStatus(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
Window window = activity.getWindow();
View decorView = window.getDecorView();
//两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
//导航栏颜色也可以正常设置
//window.setNavigationBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = activity.getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
attributes.flags |= flagTranslucentStatus;
//int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; //attributes.flags |= flagTranslucentNavigation;
window.setAttributes(attributes);
}
}
/**
* 代码实现android:fitsSystemWindows
*
* @param activity
*/
public static void setRootViewFitsSystemWindows(Activity activity, boolean fitSystemWindows) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ViewGroup winContent = (ViewGroup) activity.findViewById(android.R.id.content);
if (winContent.getChildCount() > 0) {
ViewGroup rootView = (ViewGroup) winContent.getChildAt(0);
if (rootView != null) {
rootView.setFitsSystemWindows(fitSystemWindows);
}
}
}
}
/**
* 设置状态栏深色浅色切换
*/
public static boolean setStatusBarDarkTheme(Activity activity, boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setStatusBarFontIconDark(activity, TYPE_M, dark);
} else if (OSUtils.isMiui()) {
setStatusBarFontIconDark(activity, TYPE_MIUI, dark);
} else if (OSUtils.isFlyme()) {
setStatusBarFontIconDark(activity, TYPE_FLYME, dark);
} else {//其他情况
return false;
}
return true;
}
return false;
}
/**
* 设置 状态栏深色浅色切换
*/
public static boolean setStatusBarFontIconDark(Activity activity, @ViewType int type, boolean dark) {
switch (type) {
case TYPE_MIUI:
return setMiuiUI(activity, dark);
case TYPE_FLYME:
return setFlymeUI(activity, dark);
case TYPE_M:
default:
return setCommonUI(activity, dark);
}
}
//设置6.0 状态栏深色浅色切换
public static boolean setCommonUI(Activity activity, boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = activity.getWindow().getDecorView();
if (decorView != null) {
int vis = decorView.getSystemUiVisibility();
if (dark) {
vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
if (decorView.getSystemUiVisibility() != vis) {
decorView.setSystemUiVisibility(vis);
}
return true;
}
}
return false;
}
//设置Flyme 状态栏深色浅色切换
public static boolean setFlymeUI(Activity activity, boolean dark) {
try {
Window window = activity.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//设置MIUI 状态栏深色浅色切换
public static boolean setMiuiUI(Activity activity, boolean dark) {
try {
Window window = activity.getWindow();
Class<?> clazz = activity.getWindow().getClass();
@SuppressLint("PrivateApi") Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getDeclaredMethod("setExtraFlags", int.class, int.class);
extraFlagField.setAccessible(true);
if (dark) { //状态栏亮色且黑色字体.
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
} else {
extraFlagField.invoke(window, 0, darkModeFlag);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//获取状态栏高度
public static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}
package com.polysoft.nafmii.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.telephony.TelephonyManager;
import java.util.Locale;
public class SystemUtils {
/**
* 获取当前手机系统语言。
*
* @return 返回当前系统语言。例如:当前设置的是“中文-中国”,则返回“zh-CN”
*/
public static String getSystemLanguage() {
return Locale.getDefault().getLanguage();
}
/**
* 获取当前系统上的语言列表(Locale列表)
*
* @return 语言列表
*/
public static Locale[] getSystemLanguageList() {
return Locale.getAvailableLocales();
}
/**
* 获取当前手机系统版本号
*
* @return 系统版本号
*/
public static String getSystemVersion() {
return android.os.Build.VERSION.RELEASE;
}
/**
* 获取手机型号
*
* @return 手机型号
*/
public static String getSystemModel() {
return android.os.Build.MODEL;
}
/**
* 获取手机厂商
*
* @return 手机厂商
*/
public static String getDeviceBrand() {
return android.os.Build.BRAND;
}
/**
* 获取手机IMEI(需要“android.permission.READ_PHONE_STATE”权限)
*
* @return 手机IMEI
*/
public static String getIMEI(Context ctx) {
TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Activity.TELEPHONY_SERVICE);
if (tm != null && PermissionUtils.checkAndRequestPermission(ctx, Manifest.permission.READ_PHONE_STATE)) {
return tm.getDeviceId();
}
return null;
}
}
\ No newline at end of file \ No newline at end of file
package com.polysoft.nafmii.utils;
import android.widget.Toast;
public class ToastUtils {
public static void showLong(String message) {
Toast toast = Toast.makeText(CtxUtils.getApplication(), null, Toast.LENGTH_LONG);
toast.setText(message);
toast.show();
// Toast.makeText(CtxUtils.getApplication(), message, Toast.LENGTH_LONG).show();
}
public static void showShort(String message) {
Toast toast = Toast.makeText(CtxUtils.getApplication(), null, Toast.LENGTH_SHORT);
toast.setText(message);
toast.show();
// Toast.makeText(CtxUtils.getApplication(), message, Toast.LENGTH_SHORT).show();
}
}
package com.polysoft.nafmii.webview;
public interface IWebview {
void loadUrl(String url);
boolean onBack();
}
package com.polysoft.nafmii.webview;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import com.tencent.smtt.sdk.ValueCallback;
import com.tencent.smtt.sdk.WebView;
public class JavaToJsinterface {
private static final String TAG = JavaToJsinterface.class.getName();
protected WebView mWebView;
public JavaToJsinterface(WebView webView) {
this.mWebView = webView;
}
public void callJs(String methodName, String json) {
String param = JSON.toJSONString(json);
String script = String.format("javascript:$api.%s(%s)", methodName, param);
this.mWebView.evaluateJavascript(script, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.d(TAG, String.format("JavaToJsinterface: callJs is %s result : %s", methodName, value));
}
});
}
}
package com.polysoft.nafmii.webview;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
public class JsResult {
public static final String SUCCESS = "0";
public static final String FAIL = "1";
@JSONField(name = "status")
protected String status;
@JSONField(name = "statusText")
protected String statusText;
@JSONField(name = "data")
protected Object data;
private JsResult() {
}
private JsResult(String status, String statusText, Object data) {
this.status = status;
this.statusText = statusText;
this.data = data;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
public static JsResult success(String statusText, Object data) {
return new JsResult(SUCCESS, statusText, data);
}
public static JsResult success(Object data) {
return success("success", data);
}
public static JsResult fail(String statusText, Object data) {
return new JsResult(FAIL, statusText, data);
}
public static JsResult fail(String statusText) {
return fail(statusText, null);
}
}
package com.polysoft.nafmii.webview;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.text.TextUtils;
import android.webkit.JavascriptInterface;
import androidx.fragment.app.Fragment;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.polysoft.nafmii.broadcast.Receiver;
import com.polysoft.nafmii.broadcast.ReceiverListener;
import com.polysoft.nafmii.broadcast.ShareReceiver;
import com.polysoft.nafmii.utils.CtxUtils;
import com.polysoft.nafmii.utils.IntentUtils;
import com.polysoft.nafmii.utils.PermissionUtils;
import com.polysoft.nafmii.utils.StatusBarUtils;
import com.polysoft.nafmii.wechat.ShareBean;
import com.polysoft.nafmii.wechat.ShareResult;
import com.polysoft.nafmii.wechat.WechatApi;
import java.util.HashMap;
import java.util.Map;
public class JsToJavaInterface {
private Activity mActivity;
private JavaToJsinterface javaTojs;
private Fragment mFragment;
public JsToJavaInterface(Activity activity, JavaToJsinterface javaTojs) {
this.mActivity = activity;
this.javaTojs = javaTojs;
}
public JsToJavaInterface(Fragment fragment, JavaToJsinterface javaTojs) {
this(fragment.getActivity(), javaTojs);
this.mFragment = fragment;
}
@JavascriptInterface
public void nativeAppInfo(String params) {
String jsMethodName = null;
try {
JSONObject json = JSONObject.parseObject(params);
jsMethodName = json.getString("jsMethodName");
final Map<String, Object> dataMap = new HashMap<>();
PackageInfo packageInfo = CtxUtils.getPackageInfo();
dataMap.put("versionCode", packageInfo.versionCode);
dataMap.put("versionName", packageInfo.versionName);
dataMap.put("statusBarHeight", StatusBarUtils.getStatusBarHeight(this.mActivity));
this.sendMessage2Js(jsMethodName, JSON.toJSONString(dataMap));
}catch (Exception e) {
e.printStackTrace();
}
}
@JavascriptInterface
public void nativeLogin(String params) {
try{
final JSONObject json = JSONObject.parseObject(params);
final String jsMethodName = json.getString("jsMethodName");
final String data = json.getString("data");
} catch (Exception e) {
e.printStackTrace();
}
}
@JavascriptInterface
public void nativeShare(String params) {
final JSONObject json = JSONObject.parseObject(params);
final String jsMethodName = json.getString("jsMethodName");
this.mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
WechatApi instance = WechatApi.getInstance(mActivity);
if (!instance.isWXAppInstalled()) {
String dataJson = JSON.toJSONString(ShareResult.shareFail("未安装应用"));
javaTojs.callJs(jsMethodName, dataJson);
} else {
final Receiver<ShareResult> shareReceiver = ShareReceiver.getInstance(mActivity);
shareReceiver.addDefaultListener(new ReceiverListener<ShareResult>() {
@Override
public void onReceiverResult(String action, ShareResult data) {
javaTojs.callJs(jsMethodName, JSON.toJSONString(data));
shareReceiver.addDefaultListener(null);
}
});
instance.share(mActivity, json.getObject("data", ShareBean.class));
}
}
});
}
@JavascriptInterface
public void nativeCamera(String params) {
final JSONObject json = JSONObject.parseObject(params);
final String jsMethodName = json.getString("jsMethodName");
final JSONObject data = json.getJSONObject("data");
String permissions[] = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
};
// if (PermissionUtils.checkPermissions(this.mActivity, permissions)) {
// this.photosReceiverListener(jsMethodName);
// Intent intent = IntentUtils.openCamera(this.mActivity);
// this.mFragment.startActivityForResult(intent, IntentUtils.ACTIVITY_CODE_CAMERA);
// }
}
//
// @JavascriptInterface
// public void callNativeAlbum(String params) {
// final JSONObject json = JSONObject.parseObject(params);
// final String jsMethodName = json.getString("jsMethodName");
// final JSONObject data = json.getJSONObject("data");
//
// String permissions[] = {
// Manifest.permission.WRITE_EXTERNAL_STORAGE,
// Manifest.permission.READ_EXTERNAL_STORAGE,
// };
// if (PermissionUtils.checkPermissions(this.mActivity, permissions)) {
// this.photosReceiverListener(jsMethodName);
// Intent intent = IntentUtils.openAlbum(this.mActivity);
// this.mFragment.startActivityForResult(intent, IntentUtils.ACTIVITY_CODE_ALBUM);
// }
// }
//
// @JavascriptInterface
// public void callNativeUpdate(String params) {
// final JSONObject json = JSONObject.parseObject(params);
// final String jsMethodName = json.getString("jsMethodName");
// final JSONObject data = json.getJSONObject("data");
// final String downloadUrl = data.getString("url");
// final String version = data.getString("version");
//
// if (!TextUtils.isEmpty(version)) {
// PackageInfo packageInfo = UITools.getVersionInfo(this.mActivity);
// int localVersion = packageInfo.versionCode;
// double updateVersion = Double.parseDouble(version);
// if (updateVersion <= localVersion) {
// return;
// }
// }
// this.mActivity.runOnUiThread(new Runnable() {
// @Override
// public void run() {
// UITools.showMustUpdataDialog(downloadUrl, mActivity);
// }
// });
// }
//
// @JavascriptInterface
// public void callNativeMobile(String params) {
// final JSONObject json = JSONObject.parseObject(params);
// final String jsMethodName = json.getString("jsMethodName");
// final JSONObject data = json.getJSONObject("data");
// final String tel = data.getString("tel");
//
// Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + tel));
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// this.mActivity.startActivity(intent);
//
// if (TextUtils.isEmpty((jsMethodName))) {
// return;
// }
//
// this.mActivity.runOnUiThread(new Runnable() {
// @Override
// public void run() {
// javaTojs.callJs(jsMethodName, "");
// }
// });
// }
//
// @JavascriptInterface
// public void callNativeClearCache(String params) {
// JSONObject json = TextUtils.isEmpty(params) ? new JSONObject() : JSONObject.parseObject(params);
// final String jsMethodName = json.getString("jsMethodName");
// this.mActivity.runOnUiThread(new Runnable() {
// @Override
// public void run() {
// WebViewCacheInterceptorInst.getInstance().clearCache();
// if (!TextUtils.isEmpty(jsMethodName)) {
// javaTojs.callJs(jsMethodName, "");
// }
// }
// });
// }
private void sendMessage2Js(String jsMethodName, String json) {
if (TextUtils.isEmpty(jsMethodName)) {
return;
}
if ("'main'".equals(Thread.currentThread().getName())) {
javaTojs.callJs(jsMethodName, json);
return;
}
this.mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
javaTojs.callJs(jsMethodName, json);
}
});
}
}
package com.polysoft.nafmii.webview;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import com.tencent.smtt.export.external.interfaces.SslError;
import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;
import java.util.Map;
import ren.yale.android.cachewebviewlib.WebViewCacheInterceptorInst;
public class MyWebViewClient extends WebViewClient {
private WebviewLoadListener listener;
public MyWebViewClient(WebviewLoadListener listener) {
this.listener = listener;
}
/**
* 在开始加载网页时会回调
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (null != this.listener) {
this.listener.onWebviewLoad(WebviewLoadListener.TYPE_START, null);
}
}
/**
* 在结束加载网页时会回调
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (null != this.listener) {
this.listener.onWebviewLoad(WebviewLoadListener.TYPE_FINISH, null);
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("tel:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
/**
* 加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
if (null != this.listener) {
this.listener.onWebviewLoad(WebviewLoadListener.TYPE_ERROR, description);
}
}
/**
* 当接收到https错误时,会回调此函数,在其中可以做错误处理
*/
@Override
public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
// super.onReceivedSslError(webView, sslErrorHandler, sslError);
sslErrorHandler.proceed();
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView webView, String s) {
// return super.shouldInterceptRequest(webView, s);
android.webkit.WebResourceResponse response = WebViewCacheInterceptorInst.getInstance().interceptRequest(s);
if (null == response) {
return super.shouldInterceptRequest(webView, s);
}
return buildResponse(response);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest request) {
android.webkit.WebResourceRequest res = new android.webkit.WebResourceRequest() {
@Override
public Uri getUrl() {
return request.getUrl();
}
@Override
public boolean isForMainFrame() {
return request.isForMainFrame();
}
@Override
public boolean isRedirect() {
return request.isRedirect();
}
@Override
public boolean hasGesture() {
return request.hasGesture();
}
@Override
public String getMethod() {
return request.getMethod();
}
@Override
public Map<String, String> getRequestHeaders() {
return request.getRequestHeaders();
}
};
android.webkit.WebResourceResponse response = WebViewCacheInterceptorInst.getInstance().interceptRequest(res);
if (null == response) {
return super.shouldInterceptRequest(webView, request);
}
return buildResponse(response);
}
private WebResourceResponse buildResponse(android.webkit.WebResourceResponse response) {
WebResourceResponse res = new WebResourceResponse();
res.setMimeType(response.getMimeType());
res.setEncoding(response.getEncoding());
res.setData(response.getData());
res.setResponseHeaders(response.getResponseHeaders());
res.setStatusCodeAndReasonPhrase(response.getStatusCode(), response.getReasonPhrase());
return res;
}
}
package com.polysoft.nafmii.webview;
import android.net.Uri;
import android.webkit.ValueCallback;
public interface WebviewLoadListener {
public static final int TYPE_ERROR = -1;
public static final int TYPE_START = 1;
public static final int TYPE_PROGRESS = 2;
public static final int TYPE_FINISH = 3;
void onWebviewLoad(int type, Object param);
void onShowFileChooser(ValueCallback<Uri[]> filePathCallback, String[] acceptTypes, boolean isCapture);
}
package com.polysoft.nafmii.webview;
import android.util.Log;
import com.polysoft.nafmii.utils.CtxUtils;
import com.tencent.smtt.export.external.TbsCoreSettings;
import com.tencent.smtt.sdk.QbSdk;
import com.tencent.smtt.sdk.TbsListener;
import java.util.HashMap;
public class X5Core {
private static volatile X5Core.InitCallback callback;
private static volatile boolean initfinished = false;
public static void init() {
HashMap<String, Object> map = new HashMap<>();
map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true);
map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true);
QbSdk.initTbsSettings(map);
QbSdk.setTbsListener(new TbsListener() {
@Override
public void onDownloadFinish(int i) {
Log.d("QbSdk", "onDownloadFinish -->下载X5内核完成:" + i);
}
@Override
public void onInstallFinish(int i) {
Log.d("QbSdk", "onInstallFinish -->安装X5内核进度:" + i);
}
@Override
public void onDownloadProgress(int i) {
Log.d("QbSdk", "onDownloadProgress -->下载X5内核进度:" + i);
}
});
QbSdk.initX5Environment(CtxUtils.getApplication(), new QbSdk.PreInitCallback() {
@Override
public void onCoreInitFinished() {
//内核初始化完毕
Log.d("QbSdk", "内核初始化完毕");
}
@Override
public void onViewInitFinished(boolean b) {
// x5內核初始化完成的回调,true表x5内核加载成功,否则表加载失败,会自动切换到系统内核。
Log.d("QbSdk", " 内核加载 " + b);
X5Core.initfinished = true;
callInitFinish();
}
});
}
public static void setInitCallback(InitCallback callback) {
X5Core.callback = callback;
callInitFinish();
}
private static synchronized void callInitFinish() {
if (null == X5Core.callback) return;
if (X5Core.initfinished || QbSdk.isTbsCoreInited()) {
X5Core.callback.onCoreInitFinished(QbSdk.isTbsCoreInited());
reset();
}
}
private static void reset() {
X5Core.callback = null;
X5Core.initfinished = false;
}
public interface InitCallback {
void onCoreInitFinished(boolean flag);
}
}
package com.polysoft.nafmii.webview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import com.polysoft.nafmii.BuildConfig;
import com.tencent.smtt.export.external.extension.interfaces.IX5WebSettingsExtension;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
public class X5WebviewUtils {
public static WebView create(Context context) {
WebView webView = new WebView(context);
/** 设置透明色背景*/
webView.setBackgroundColor(0);
// 解决部分机型加载 背景为黑色问题
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
// webView.clearCache(true);
webView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG);
setWebView(webView);
return webView;
}
public static void destroy(WebView webView) {
if (null == webView) {
return;
}
webView.stopLoading();
webView.clearHistory();
webView.removeAllViews();
webView.setVisibility(View.GONE);
webView.loadUrl("about:blank");
webView.destroy();
ViewGroup parent = (ViewGroup) webView.getParent();
parent.removeAllViews();
}
@SuppressLint({"SetJavaScriptEnabled", "InlinedApi"})
private static void setWebView(WebView webView) {
WebSettings settings = webView.getSettings();
/** 支持javaScript*/
settings.setJavaScriptEnabled(true);
/** 设置页面文字的编码*/
settings.setDefaultTextEncodingName("utf-8");
/** 设置webview布局方式*/
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
/** 是否允许WebView度超出以概览的方式载入页面,默认false。
* 即缩小内容以适应屏幕宽度。该项设置在内容宽度超出WebView控件的宽度时生效,
* 例如当getUseWideViewPort() 返回true时*/
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
/** 支持访问Content Provider的资源*/
settings.setAllowContentAccess(true);
/** 支持访问本地文件*/
settings.setAllowFileAccess(true);
/** 支持通过file url加载的Javascript读取本地文件*/
settings.setAllowFileAccessFromFileURLs(true);
/** 支持https/http 混合加载*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
/** 支持通过file url加载的Javascript读取全部资源(包括文件,http,https)*/
settings.setAllowUniversalAccessFromFileURLs(true);
/** 禁止页面缩放*/
settings.setBuiltInZoomControls(false);
settings.setSupportZoom(false);
/** 禁止显示缩放图标*/
settings.setDisplayZoomControls(false);
// settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
// settings.setAppCacheEnabled(true);
settings.setDomStorageEnabled(true);
IX5WebSettingsExtension extension = webView.getSettingsExtension();
if (null != extension) {
/** 对于刘海屏机器如果webview被遮挡会自动padding */
extension.setDisplayCutoutEnable(true);
/** 正常加载显示所有图片 */
extension.setPicModel(IX5WebSettingsExtension.PicModel_NORMAL);
}
}
}
package com.polysoft.nafmii.wechat;
import com.alibaba.fastjson.annotation.JSONField;
public class ShareBean {
@JSONField(name = "shareType")
private String shareType;//分享类型 0文字 1图片 2url网址
@JSONField(name = "title")
private String title;//分享标题
@JSONField(name = "content")
private String content;//分享内容 文字 图片 展示的网页描述
@JSONField(name = "scene")
private String scene;//场景 0朋友圈 1好友
@JSONField(name = "webUrl")
private String webUrl;//分享链接
@JSONField(name = "webImg")
private String webImg;//网页位图
public String getWebImg() {
return webImg;
}
public void setWebImg(String webImg) {
this.webImg = webImg;
}
public String getShareType() {
return shareType;
}
public void setShareType(String shareType) {
this.shareType = shareType;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getScene() {
return scene;
}
public void setScene(String scene) {
this.scene = scene;
}
public String getWebUrl() {
return webUrl;
}
public void setWebUrl(String webUrl) {
this.webUrl = webUrl;
}
@Override
public String toString() {
return "WeChatShareBean{" +
"shareType='" + shareType + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
", scene='" + scene + '\'' +
", webUrl='" + webUrl + '\'' +
", webImg='" + webImg + '\'' +
'}';
}
}
package com.polysoft.nafmii.wechat;
import android.text.TextUtils;
import com.alibaba.fastjson.annotation.JSONField;
import java.io.Serializable;
public class ShareResult implements Serializable {
@JSONField(name = "status")
private String status;
@JSONField(name = "statusText")
private String statusText;
private ShareResult() {
}
private ShareResult(String status, String statusText) {
this.status = status;
this.statusText = statusText;
}
public static ShareResult shareSuccess() {
return new ShareResult("0", "分享成功");
}
public static ShareResult shareFail(String text) {
String statusText = TextUtils.isEmpty(text) ? text : "分享失败";
return new ShareResult("-1", statusText);
}
public static ShareResult shareCancel() {
return new ShareResult("-2", "分享取消");
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(String statusText) {
this.statusText = statusText;
}
}
package com.polysoft.nafmii.wechat;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.alibaba.fastjson.JSON;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.polysoft.nafmii.BuildConfig;
import com.polysoft.nafmii.R;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject;
import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
public class WechatApi {
private static WechatApi INSTANCE = null;
private final Context ctx;
private final IWXAPI api;
private WechatApi(Context ctx, boolean isDebug) {
this.ctx = ctx;
this.api = WXAPIFactory.createWXAPI(ctx, BuildConfig.WX_APPID, isDebug);
this.api.registerApp(BuildConfig.WX_APPID);
}
public static WechatApi getInstance(Context ctx) {
return getInstance(ctx, false);
}
public static WechatApi getInstance(Context ctx, boolean isDebug) {
if (null == WechatApi.INSTANCE) {
WechatApi.INSTANCE = new WechatApi(ctx, isDebug);
}
return WechatApi.INSTANCE;
}
public void sendRequest(BaseReq req) {
this.api.sendReq(req);
}
public boolean isWXAppInstalled() {
return this.api.isWXAppInstalled();
}
public void handleIntent(Intent intent, IWXAPIEventHandler handler) {
this.api.handleIntent(intent, handler);
}
public void pay(String payInfo) {
this.sendRequest(JSON.parseObject(payInfo, PayReq.class));
}
public void share(Context ctx, final ShareBean bean) {
String webImg = bean.getWebImg();
String shareType = bean.getShareType();
if ("0".equals(shareType)) { // 分享文字
this.shareText(bean);
} else if ("1".equals(shareType)) { // 分享图片
this.shareImage(bean);
} else if ("2".equals(shareType)) { // 分享url地址
this.loadImageUrl(ctx, webImg, new Callback<Bitmap>() {
@Override
public void onBack(Bitmap data) {
shareWebPage(bean, data);
}
});
}
}
private void shareText(ShareBean bean) {
}
private void shareImage(ShareBean bean) {
}
private void shareWebPage(ShareBean bean, Bitmap bitmap) {
WXWebpageObject web = new WXWebpageObject();
web.webpageUrl = bean.getWebUrl();
WXMediaMessage msg = new WXMediaMessage(web);
// 填写网页标题、描述、位图
msg.title = bean.getTitle();
//网页描述
msg.description = bean.getContent();
msg.setThumbImage(bitmap);
bitmap.recycle();
SendMessageToWX.Req req = new SendMessageToWX.Req();
// transaction用于唯一标识一个请求(可自定义)
req.transaction = "webpage";
// 上文的WXMediaMessage对象
req.message = msg;
req.scene = this.getShareScene(bean);
// 向微信发送请求
this.sendRequest(req);
}
private int getShareScene(ShareBean bean) {
String scene = bean.getScene();
if ("0".equals(scene)) { // 朋友圈
return SendMessageToWX.Req.WXSceneTimeline;
} else if ("1".equals(scene)) { // 分享到好友
return SendMessageToWX.Req.WXSceneSession;
} else if ("2".equals(scene)) { // 分享到收藏夹
return SendMessageToWX.Req.WXSceneFavorite;
}
// 默认分享到好友
return SendMessageToWX.Req.WXSceneSession;
}
private void loadImageUrl(Context ctx, String url, final Callback<Bitmap> callback) {
SimpleTarget<Bitmap> target = new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
callback.onBack(resource);
}
};
if (TextUtils.isEmpty(url)) {
Glide.with(ctx).asBitmap().load(R.mipmap.ic_launcher).override(120, 120).into(target);
} else {
Glide.with(ctx).asBitmap().load(url).override(120, 120).into(target);
}
}
private static interface Callback<T> {
public void onBack(T data);
}
}
package com.polysoft.nafmii.wxapi;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.polysoft.nafmii.broadcast.ShareReceiver;
import com.polysoft.nafmii.wechat.ShareResult;
import com.polysoft.nafmii.wechat.WechatApi;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WechatApi.getInstance(this).handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
WechatApi.getInstance(this).handleIntent(intent, this);
}
@Override
public void onReq(BaseReq baseReq) {
}
@Override
public void onResp(BaseResp resp) {
if (resp instanceof SendAuth.Resp) {
}
int code = resp.errCode;
if (code == BaseResp.ErrCode.ERR_OK) { // 分享成功
ShareReceiver.sendBroadcast(this, ShareResult.shareSuccess());
} else if (code == BaseResp.ErrCode.ERR_USER_CANCEL) { // 用户取消
ShareReceiver.sendBroadcast(this, ShareResult.shareCancel());
} else { // 分享失败
String errStr = resp.errStr;
ShareReceiver.sendBroadcast(this, ShareResult.shareFail(errStr));
}
super.finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
package com.polysoft.nafmii.wxapi;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.polysoft.nafmii.wechat.WechatApi;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = WXPayEntryActivity.class.getName();
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WechatApi.getInstance(this).handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
WechatApi.getInstance(this).handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(BaseResp resp) {
Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);
if (resp.getType() != ConstantsAPI.COMMAND_PAY_BY_WX) {
return;
}
int code = resp.errCode;
if (code == BaseResp.ErrCode.ERR_OK) { // 支付成功
// PayReceiver.sendBroadcast(this, PayResult.success(PayMode.WECHATPAY, null));
} else if (code == BaseResp.ErrCode.ERR_USER_CANCEL) { // 用户取消
// PayReceiver.sendBroadcast(this, PayResult.cancel(PayMode.WECHATPAY));
} else { // 支付失败
String errStr = resp.errStr;
// PayReceiver.sendBroadcast(this, PayResult.fail(PayMode.WECHATPAY, errStr));
}
super.finish();
}
}
\ No newline at end of file \ No newline at end of file
<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:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
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="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false">
<shape android:shape="oval">
<solid android:color="@color/black" />
<size android:width="15dp" android:height="15dp" />
</shape>
</item>
<item android:state_checked="true">
<shape android:shape="oval">
<solid android:color="@color/teal_200" />
<size android:width="15dp" android:height="15dp" />
</shape>
</item>
</selector>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Drop Shadow Stack -->
<item>
<shape>
<padding android:top="1dp" />
<solid android:color="#10DDDDDD" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" />
<solid android:color="#20DDDDDD" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" />
<solid android:color="#40DDDDDD" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" />
<solid android:color="#50DDDDDD" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" />
<solid android:color="#60DDDDDD" />
</shape>
</item>
<!-- Background -->
<item>
<shape>
<solid android:color="@android:color/white" />
</shape>
</item>
</layer-list>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/black" android:state_checked="false" />
<item android:color="@color/teal_200" android:state_checked="true" />
</selector>
\ No newline at end of file \ No newline at end of file
<?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="#3DDC84"
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>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.GuideActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/guide_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/guide_btn_gohome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:text="立即体验"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/guide_point_group"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<RadioGroup
android:id="@+id/guide_point_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints">
<RadioButton
android:id="@+id/guide_point1"
style="@style/Nafmii.Widget.Guide.RadioButton"
android:checked="true" />
<RadioButton
android:id="@+id/guide_point2"
style="@style/Nafmii.Widget.Guide.RadioButton" />
<RadioButton
android:id="@+id/guide_point3"
style="@style/Nafmii.Widget.Guide.RadioButton" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".activity.HomeActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/home_container_viewpager"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/home_footer_group"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/home_container_framelayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@+id/home_footer_group"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<RadioGroup
android:id="@+id/home_footer_group"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/home_bottom_menu_bg"
android:orientation="horizontal"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/home_btn_home"
style="@style/Nafmii.Widget.Home.RadioButton"
android:checked="true"
android:text="首页" />
<RadioButton
android:id="@+id/home_btn_member"
style="@style/Nafmii.Widget.Home.RadioButton"
android:text="会员" />
<RadioButton
android:id="@+id/home_btn_learn"
style="@style/Nafmii.Widget.Home.RadioButton"
android:text="学习" />
<RadioButton
android:id="@+id/home_btn_my"
style="@style/Nafmii.Widget.Home.RadioButton"
android:text="我的" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:fitsSystemWindows="false"
android:padding="20dp"
tools:context=".activity.InputUrlActivity">
<EditText
android:id="@+id/input_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="请输入完整url地址"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="进入"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/input_url" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="@+id/main_framelayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:src="@mipmap/icon_zhiwen" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:text="请验证指纹解锁"
android:textColor="#000"
android:textSize="16sp" />
<TextView
android:id="@+id/error_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:maxLines="1"
android:textColor="#f45"
android:textSize="12sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp"
android:background="#ccc" />
<TextView
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="取消"
android:textColor="#5d7883"
android:textSize="16sp" />
</LinearLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.AdvertisementFragment">
<ImageView
android:id="@+id/advertisement_imgview"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/advertisement_countdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5s"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="@+id/advertisement_pass"
app:layout_constraintEnd_toStartOf="@+id/advertisement_pass"
app:layout_constraintTop_toTopOf="@+id/advertisement_pass" />
<TextView
android:id="@+id/advertisement_pass"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginRight="40dp"
android:padding="20dp"
android:text="跳过"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.WebViewFragment">
<LinearLayout
android:id="@+id/webview_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical"></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file \ No newline at end of file
<?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>
\ No newline at end of file \ No newline at end of file
<?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>
\ No newline at end of file \ No newline at end of file
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Nafmii" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowBackground">@mipmap/splash1</item>
<!-- Customize your theme here. -->
</style>
<style name="Nafmii.Fullscreen" parent="Theme.Nafmii">
<!-- 设置全屏-->
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@mipmap/splash1</item>
</style>
<style name="Nafmii.Fullscreen.NoTitleBar" parent="Nafmii.Fullscreen">
<!-- 取消Actionbar-->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>
\ No newline at end of file \ No newline at end of file
<resources>
<string name="hello_world">Hello Round World!</string>
</resources>
\ No newline at end of file \ No newline at end of file
<resources>
<declare-styleable name="FullscreenAttrs">
<attr name="fullscreenBackgroundColor" format="color" />
<attr name="fullscreenTextColor" format="color" />
</declare-styleable>
</resources>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
<color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color>
</resources>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Because the window insets on round devices are larger than 15dp, this padding only applies
to square screens.
-->
<dimen name="box_inset_layout_padding">0dp</dimen>
<!--
This padding applies to both square and round screens. The total padding between the buttons
and the window insets is box_inset_layout_padding (above variable) on square screens and
inner_frame_layout_padding (below variable) on round screens.
-->
<dimen name="inner_frame_layout_padding">5dp</dimen>
</resources>
\ No newline at end of file \ No newline at end of file
<resources>
<string name="app_name">nafmii</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<string name="title_activity_base">BaseActivity</string>
<!--
This string is used for square devices and overridden by hello_world in
values-round/strings.xml for round devices.
-->
<string name="hello_world">Hello Square World!</string>
</resources>
\ No newline at end of file \ No newline at end of file
<resources>
<style name="Nafmii.Widget.Home.RadioButton" parent="">
<item name="android:textSize">16sp</item>
<item name="android:layout_weight">1</item>
<item name="android:button">@null</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@drawable/home_radio_selector</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">match_parent</item>
</style>
<style name="Nafmii.Widget.Guide.RadioButton" parent="">
<item name="android:textSize">0sp</item>
<item name="android:button">@null</item>
<item name="android:gravity">center</item>
<item name="android:layout_width">25dp</item>
<item name="android:layout_height">25dp</item>
<item name="android:drawableTop">@drawable/guide_radio_selector</item>
</style>
</resources>
\ No newline at end of file \ No newline at end of file
This diff is collapsed. Click to expand it.
No preview for this file type
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!