commit 02e9633de589d5227c1698d85da35f28e2887abe Author: Jay Gao <1109258889@qq.com> Date: Tue Aug 9 10:59:33 2022 +0800 代码提交。 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15f0564 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild +.idea +.apk diff --git a/DeviceAddModule/build.gradle b/DeviceAddModule/build.gradle new file mode 100644 index 0000000..4da048f --- /dev/null +++ b/DeviceAddModule/build.gradle @@ -0,0 +1,72 @@ +apply plugin: 'com.android.library' +repositories { + flatDir { + dirs 'libs' + } +} +android { + compileSdkVersion 29 + buildToolsVersion "29.0.1" + defaultConfig { + minSdkVersion 21 + targetSdkVersion 26 + javaCompileOptions { + annotationProcessorOptions { + arguments = [moduleName: project.getName()] + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + minifyEnabled false + } + } + sourceSets { + main.res.srcDirs = ['src/main/res', + 'src/main/res/lc', + 'src/main/res/lc/drawable', + 'src/main/res/lc/drawable-hdpi', + 'src/main/res/lc/drawable-xhdpi', + 'src/main/res/lc/drawable-xxhdpi', + 'src/main/res/lc/anim', + 'src/main/res/lc/color', + 'src/main/res/lc/values', + 'src/main/res/lc/values-en', + 'src/main/res/lc/layout'] + } + android { + lintOptions { + abortOnError false + } + resourcePrefix "demo_" + } +} + +dependencies { + provided fileTree(include: ['*.jar'], dir: 'libs') +// provided fileTree(include: ['*.aar'], dir: 'libs') + + api project(':third-zxing') + api "org.greenrobot:eventbus:3.0.0" + api 'com.google.code.gson:gson:2.8.1' + + api "com.android.support:recyclerview-v7:27.1.1" + api "com.android.support:support-v4:27.1.1" + api "com.android.support:appcompat-v7:27.1.1" + api "com.android.support:cardview-v7:27.1.1" + api "com.android.support:design:27.1.1" + api 'com.android.support.constraint:constraint-layout:1.1.0' + + api files('libs/PullToRefreshListView-release.aar') + api files('libs/DHMobileToolset-1.1.1.aar') + api files('libs/DHScanner-1.0.7.aar') + +} +configurations { + all*.exclude group: 'com.google.zxing' +} diff --git a/DeviceAddModule/libs/DHMobileToolset-1.1.1.aar b/DeviceAddModule/libs/DHMobileToolset-1.1.1.aar new file mode 100644 index 0000000..fd7bcd5 Binary files /dev/null and b/DeviceAddModule/libs/DHMobileToolset-1.1.1.aar differ diff --git a/DeviceAddModule/libs/DHScanner-1.0.7.aar b/DeviceAddModule/libs/DHScanner-1.0.7.aar new file mode 100644 index 0000000..1d96fca Binary files /dev/null and b/DeviceAddModule/libs/DHScanner-1.0.7.aar differ diff --git a/DeviceAddModule/libs/PullToRefreshListView-release.aar b/DeviceAddModule/libs/PullToRefreshListView-release.aar new file mode 100644 index 0000000..ba49c81 Binary files /dev/null and b/DeviceAddModule/libs/PullToRefreshListView-release.aar differ diff --git a/DeviceAddModule/libs/imageload4dh.jar b/DeviceAddModule/libs/imageload4dh.jar new file mode 100644 index 0000000..95097f3 Binary files /dev/null and b/DeviceAddModule/libs/imageload4dh.jar differ diff --git a/DeviceAddModule/libs/lechangeSDK.jar b/DeviceAddModule/libs/lechangeSDK.jar new file mode 100644 index 0000000..0088d21 Binary files /dev/null and b/DeviceAddModule/libs/lechangeSDK.jar differ diff --git a/DeviceAddModule/proguard-rules.pro b/DeviceAddModule/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/DeviceAddModule/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/DeviceAddModule/src/main/AndroidManifest.xml b/DeviceAddModule/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7b8f033 --- /dev/null +++ b/DeviceAddModule/src/main/AndroidManifest.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/assets/password.xml b/DeviceAddModule/src/main/assets/password.xml new file mode 100644 index 0000000..0867306 --- /dev/null +++ b/DeviceAddModule/src/main/assets/password.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/CommonParam.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/CommonParam.java new file mode 100644 index 0000000..027a3d8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/CommonParam.java @@ -0,0 +1,68 @@ +package com.mm.android.deviceaddmodule; + +import android.app.Application; + +import java.io.Serializable; + +public class CommonParam implements Serializable { + private Application context; + private String userId; + private String appId; + private String appSecret; + + private String envirment= ""; + + public String getEnvirment() { + return envirment; + } + + public void setEnvirment(String envirment) { + this.envirment = envirment; + } + + public Application getContext() { + return context; + } + + public void setContext(Application context) { + this.context = context; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppSecret() { + return appSecret; + } + + public void setAppSecret(String appSecret) { + this.appSecret = appSecret; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public void checkParam() throws Exception { + if (context == null) { + throw new Exception("context must not null"); + } + + if (appId == null || appId.isEmpty()) { + throw new Exception("appId must not empty"); + } + + if (appSecret == null || appSecret.isEmpty()) { + throw new Exception("appSecret must not empty"); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LCDeviceEngine.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LCDeviceEngine.java new file mode 100644 index 0000000..6e712d6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LCDeviceEngine.java @@ -0,0 +1,145 @@ +package com.mm.android.deviceaddmodule; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import com.lechange.opensdk.api.InitParams; +import com.lechange.opensdk.api.LCOpenSDK_Api; +import com.lechange.opensdk.device.LCOpenSDK_DeviceInit; +import com.mm.android.deviceaddmodule.device_wifi.CurWifiInfo; +import com.mm.android.deviceaddmodule.device_wifi.DeviceWifiListActivity; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.EnvironmentConfig; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; +import com.mm.android.deviceaddmodule.openapi.CONST; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; +import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; +import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; +import com.nostra13.universalimageloader.core.assist.QueueProcessingType; +import com.nostra13.universalimageloader.core.download.BaseImageDownloader; +import com.zxing.ContextHelper; + +import static com.mm.android.deviceaddmodule.device_wifi.DeviceConstant.IntentCode.DEVICE_SETTING_WIFI_LIST; + +/** + * 添加设备组件 唯一入口 + */ +public class LCDeviceEngine { + private boolean sdkHasInit = false; + private volatile static LCDeviceEngine lcDeviceEngine; + public String accessToken; + private Throwable throwable; + public CommonParam commonParam; + public String userId = ""; + + public static LCDeviceEngine newInstance() { + if (lcDeviceEngine == null) { + synchronized (LCDeviceEngine.class) { + if (lcDeviceEngine == null) { + lcDeviceEngine = new LCDeviceEngine(); + } + } + } + return lcDeviceEngine; + } + + public boolean init(CommonParam commonParam, String token) throws Throwable { + this.commonParam = commonParam; + this.accessToken = token; + this.userId = ""; + this.sdkHasInit = false; + if (commonParam == null) { + throw new Exception("commonParam must not null"); + } + //参数校验 + commonParam.checkParam(); + //初始化参数 + initParam(commonParam); + //获取开放平台token +// initToken(token); + if (TextUtils.isEmpty(accessToken)) { + throw throwable; + } + //组件初始化 + //LCOpenSDK_Api.setHost(CONST.HOST.replace("https://", ""), accessToken); + InitParams initParams = new InitParams(commonParam.getContext(), CONST.HOST.replace("https://", ""), accessToken); + LCOpenSDK_Api.initOpenApi(initParams); + LCOpenSDK_DeviceInit.getInstance(); + sdkHasInit = true; + return true; + } + + public void addDevice(Activity activity) throws Exception { + if (!sdkHasInit) { + throw new Exception("not init"); + } + //开启添加页面 + activity.startActivity(new Intent(commonParam.getContext(), LcnDeviceAddActivity.class)); + } + + public boolean deviceOnlineChangeNet(Activity activity, DHDevice device, CurWifiInfo wifiInfo) { + if (!sdkHasInit) { + return false; + } + //开启设备在线配网 + Intent intent = new Intent(commonParam.getContext(), DeviceWifiListActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable("DHDEVICE_INFO", device); + bundle.putSerializable("DEVICE_CURRENT_WIFI_INFO", wifiInfo); + intent.putExtras(bundle); + activity.startActivityForResult(intent, DEVICE_SETTING_WIFI_LIST); + return true; + } + + private String initToken(final String token) { + /*Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { +// accessToken = DeviceAddOpenApiManager.getToken(); + accessToken = token; + } catch (BusinessException e) { + throwable = new Throwable(e.errorDescription); + } + } + }); + try { + thread.start(); + thread.join(4000); + } catch (InterruptedException e) { + throwable = e; + }*/ + return token; + } + + private void initParam(CommonParam commonParam) throws Exception { + userId = TextUtils.isEmpty(commonParam.getUserId()) ? commonParam.getAppId() : commonParam.getUserId(); + //传入参数 AppId SecretKey 环境切换 + CONST.makeEnv(commonParam.getEnvirment(), commonParam.getAppId(), commonParam.getAppSecret()); + ContextHelper.init(commonParam.getContext()); + new EnvironmentConfig.Builder().setContext(commonParam.getContext()).build(); + initImageLoader(commonParam.getContext()); + } + + private void initImageLoader(Context context) { + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) + .threadPriority(Thread.NORM_PRIORITY - 2).threadPoolSize(3) + .tasksProcessingOrder(QueueProcessingType.LIFO) + .memoryCache(new LruMemoryCache((int) (Runtime.getRuntime().maxMemory() / 16))) + .memoryCacheExtraOptions(600, 400) + .diskCacheExtraOptions(600, 400, null).diskCacheSize(50 * 1024 * 1024) + .diskCacheFileNameGenerator(new Md5FileNameGenerator()) + .imageDownloader(new BaseImageDownloader(context)) + .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) + .writeDebugLogs() + .build(); + ImageLoader.getInstance().init(config); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LcnDeviceAddActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LcnDeviceAddActivity.java new file mode 100644 index 0000000..60826c1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/LcnDeviceAddActivity.java @@ -0,0 +1,527 @@ +package com.mm.android.deviceaddmodule; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.View; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.contract.DeviceAddConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseFragment; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.base.DefaultPermissionListener; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CommonEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.p_ap.ApBindSuccessFragment; +import com.mm.android.deviceaddmodule.p_ap.ApPairFragment; +import com.mm.android.deviceaddmodule.p_bindsuccess.BindSuccessFragment; +import com.mm.android.deviceaddmodule.p_cloudconnect.CloudConnectFragment; +import com.mm.android.deviceaddmodule.p_devlogin.DevLoginFragment; +import com.mm.android.deviceaddmodule.p_devlogin.DevSecCodeFragment; +import com.mm.android.deviceaddmodule.p_errortip.ErrorTipFragment; +import com.mm.android.deviceaddmodule.p_init.InitFragment; +import com.mm.android.deviceaddmodule.p_init.SecurityCheckFragment; +import com.mm.android.deviceaddmodule.p_softap.DevWifiListFragment; +import com.mm.android.deviceaddmodule.p_softap.oversea.SoftApResultFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.SmartConfigFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.WifiPwdFragment; +import com.mm.android.deviceaddmodule.presenter.DeviceAddPresenter; +import com.mm.android.deviceaddmodule.views.popwindow.BasePopWindow; +import com.mm.android.deviceaddmodule.views.popwindow.PopWindowFactory; + +import org.greenrobot.eventbus.EventBus; + +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static com.mm.android.deviceaddmodule.mobilecommon.common.Constants.PERMISSION_REQUEST_ID; + +/** + * 添加设备主界面,各功能模块以Fragment形式依附于此类 + */ +public class LcnDeviceAddActivity extends BaseFragmentActivity implements DeviceAddConstract.View, CommonTitle.OnTitleClickListener { + public static final String TAG = "LcnDeviceAddActivity"; + private CommonTitle mTitle; //标题栏 + DeviceAddConstract.Presenter mPresenter; + private final String STOP_ADD_DIALOG = "stop_add_dialog"; + LCAlertDialog mLCAlertDialog; + PopWindowFactory mPopWindowFactory; + BasePopWindow mMoreOptionPopWindow, mLoadingPopWindow, mTypeChosePopWindow; + private DefaultPermissionListener defaultPermissionListener; + private PermissionHelper permissionHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_device_lcadd); + initView(); + initData(); + } + + //接收EventBus消息 + @Override + public void onMessageEvent(BaseEvent event) { + super.onMessageEvent(event); + if (event instanceof DeviceAddEvent) { + String code = event.getCode(); + if (DeviceAddEvent.CONFIG_PAGE_NAVIGATION_ACTION.equals(code)) { + mPresenter.dispatchPageNavigation(); + } else if (DeviceAddEvent.CHANGE_TO_WIRELESS_ACTION.equals(code)) { + mPresenter.changeToWireless(); + } else if (DeviceAddEvent.CHANGE_TO_WIRED_ACTION.equals(code)) { + mPresenter.changeToWired(); + } else if (DeviceAddEvent.CHANGE_TO_SOFTAP_ACTION.equals(code)) { + mPresenter.changeToSoftAp(); + } else if (DeviceAddEvent.TITLE_MODE_ACTION.equals(code)) { + Bundle bundle = ((DeviceAddEvent) event).getBundle(); + String titleMode = bundle.getString(DeviceAddEvent.KEY.TITLE_MODE); + mPresenter.setCurTitleMode(titleMode); + dispatchTitle(titleMode); + } else if (DeviceAddEvent.SHOW_LOADING_VIEW_ACTION.equals(code)) { + synchronized (LcnDeviceAddActivity.this) { + if (mLoadingPopWindow != null && !this.isFinishing()) { + if (!mLoadingPopWindow.isShowing()) { + mLoadingPopWindow.showAsDropDown(mTitle); + } + } else if (!this.isFinishing() && hasWindowFocus()) { + mLoadingPopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.LOADING); + } + } + } else if (DeviceAddEvent.DISMISS_LOADING_VIEW_ACTION.equals(code)) { + synchronized (LcnDeviceAddActivity.this) { + LogUtil.debugLog(TAG, "LoadingDismiss-->" + mLoadingPopWindow); + if (mLoadingPopWindow != null) { + mLoadingPopWindow.dismiss(); + } + } + } else if (DeviceAddEvent.DESTROY_ACTION.equals(code)) { + destroy(); + } else if (DeviceAddEvent.OFFLINE_CONFIG_SUCCESS_ACTION.equals(code)) { + offlineConfigSucceed(); + } else if (DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST_DISABLE_ACTION.equals(code)) { + mTitle.setEnabled(false, CommonTitle.ID_RIGHT); + } else if (DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST_ENABLE_ACTION.equals(code)) { + mTitle.setEnabled(true, CommonTitle.ID_RIGHT); + } else if (DeviceAddEvent.SHOW_TYPE_CHOSE_ACTION.equals(code)) { + mTypeChosePopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.CHOSETYPE); + } + } + } + + //初始化页面布局 + private void initView() { + mPopWindowFactory = new PopWindowFactory(); + initTitle(); + } + + private void initTitle() { + mTitle = findViewById(R.id.title); + mTitle.initView(R.drawable.mobile_common_title_back, 0, R.string.add_device_title); + mTitle.setOnTitleClickListener(this); + } + + //初始化页面数据 + private void initData() { + mPresenter = new DeviceAddPresenter(this); + mPresenter.dispatchIntentData(getIntent()); + permissionHelper = new PermissionHelper(this); + defaultPermissionListener = new DefaultPermissionListener() { + @Override + public void onGranted() { + mPresenter.getGPSLocation(); + } + + @Override + public boolean onDenied() { + mPresenter.getGPSLocation(); + return true; + } + }; + permissionHelper.requestPermissions(new String[]{ + ACCESS_COARSE_LOCATION, + Manifest.permission.CAMERA, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE}, defaultPermissionListener); + } + + //动态权限申请回调 + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + if (requestCode == PERMISSION_REQUEST_ID) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (defaultPermissionListener != null) { + defaultPermissionListener.onGranted(); + } + } else { + if (defaultPermissionListener != null && permissionHelper != null) { + if (!defaultPermissionListener.onDenied()) { //返回false,默认处理,向用户说明权限的必要性并引导 + permissionHelper.gotoSettingPage(permissions, defaultPermissionListener); + } + } + } + } + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mPresenter = null; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + if (curFragment != null) { + curFragment.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public void onBackPressed() { + goBack(); + } + + private void goBack() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + int entryCount = getSupportFragmentManager().getBackStackEntryCount(); + boolean isWifiOfflineMode = DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode(); + if (curFragment == null + || entryCount <= 0 + || (isWifiOfflineMode && entryCount == 1) + || curFragment instanceof ApBindSuccessFragment) { + if (mLoadingPopWindow != null) { + mLoadingPopWindow.dismiss(); + } + if (curFragment instanceof ApBindSuccessFragment) { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { + showStopDevAddDialog(true); + } + return; + } + destroy(); + } else { + if (curFragment instanceof CloudConnectFragment + || curFragment instanceof InitFragment + || curFragment instanceof DevLoginFragment + || curFragment instanceof DevSecCodeFragment + || curFragment instanceof SmartConfigFragment + || curFragment instanceof DevWifiListFragment + || curFragment instanceof SoftApResultFragment + || curFragment instanceof SecurityCheckFragment + || curFragment instanceof ApPairFragment) {//以上界面退出需二次确认 + showStopDevAddDialog(curFragment instanceof ApPairFragment); + } else { + if (!((BaseFragment) curFragment).onBackPressed()) {//子类未消耗返回事件 + if (curFragment instanceof ErrorTipFragment) { + showStopDevAddDialog(false); + return; + } else if (curFragment instanceof BindSuccessFragment) { + destroy(); + return; + } + if (mLoadingPopWindow != null) { + mLoadingPopWindow.dismiss(); + } + + //从输入wifi密码页面返回,统一回到电源页面 + if (curFragment instanceof WifiPwdFragment) { + getSupportFragmentManager().popBackStackImmediate(PageNavigationHelper.TIP_POWER_FRAGMENT_TAG, 0); + return; + } + + getSupportFragmentManager().popBackStack(); //退回到上个界面 + } + } + } + } + + private void dispatchTitle(String titleMode) { + mTitle.setVisibleRight(View.VISIBLE); + if (DeviceAddHelper.TitleMode.MORE.name().equals(titleMode) + || DeviceAddHelper.TitleMode.MORE2.name().equals(titleMode) + || DeviceAddHelper.TitleMode.MORE3.name().equals(titleMode) + || DeviceAddHelper.TitleMode.MORE4.name().equals(titleMode)) { + mTitle.setIconRight(R.drawable.common_icon_nav_more); + } else if (DeviceAddHelper.TitleMode.REFRESH.name().equals(titleMode)) { + mTitle.setIconRight(R.drawable.common_image_nav_refresh_selector); + } else if (DeviceAddHelper.TitleMode.SHARE.name().equals(titleMode)) { + mTitle.setTitleCenter(R.string.mobile_common_device); + mTitle.setIconRight(R.drawable.mobile_common_share_selector); + boolean isOversea = ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA; + boolean canBeShare = mPresenter.canBeShare(); + mTitle.setVisibleRight(isOversea && canBeShare ? View.VISIBLE : View.GONE); + } else if (DeviceAddHelper.TitleMode.FREE_CLOUD_STORAGE.name().equals(titleMode)) { + mTitle.setVisibleLeft(View.GONE); + mTitle.setVisibleRight(View.GONE); + } else if (DeviceAddHelper.TitleMode.MODIFY_DEVICE_NAME.name().equals(titleMode)) { + mTitle.setTitleCenter(R.string.mobile_common_modify_device_pwd); + mTitle.setVisibleRight(View.GONE); + } else { + mTitle.setIconRight(0); + } + } + + /** + * 停止添加流程提示框 + */ + private void showStopDevAddDialog(final boolean isExitApAdd) { + dismissLCAlertDialog(); + LCAlertDialog.Builder builder = new LCAlertDialog.Builder(this); + builder.setTitle(R.string.add_device_confrim_to_quit); + builder.setMessage(R.string.add_device_not_complete_tip); + builder.setCancelButton(R.string.common_cancel, null); + builder.setConfirmButton(R.string.common_confirm, + new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, + boolean isChecked) { + destroy(); + } + }); + + mLCAlertDialog = builder.create(); + mLCAlertDialog.show(getSupportFragmentManager(), + STOP_ADD_DIALOG); + } + + private void dismissLCAlertDialog() { + if (mLCAlertDialog != null && mLCAlertDialog.isVisible()) { + mLCAlertDialog.dismissAllowingStateLoss(); + mLCAlertDialog = null; + } + } + + @Override + public void onCommonTitleClick(int id) { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + switch (id) { + case CommonTitle.ID_LEFT: + goBack(); + break; + case CommonTitle.ID_RIGHT: { + if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.MORE.name())) { + mMoreOptionPopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.OPTION1); + } else if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.MORE2.name())) { + mMoreOptionPopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.OPTION2); + } else if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.MORE3.name())) { + mMoreOptionPopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.OPTION3); + } else if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.MORE4.name())) { + mMoreOptionPopWindow = mPopWindowFactory.createPopWindow(this, mTitle, PopWindowFactory.PopWindowType.OPTION4); + } else if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.REFRESH.name())) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST)); + } else if (mPresenter.getCurTitleMode().equals(DeviceAddHelper.TitleMode.SHARE.name())) { + mPresenter.getDeviceShareInfo(); + } + } + } + } + + @Override + public Context getContextInfo() { + return this; + } + + @Override + public boolean isViewActive() { + return !isActivityDestory(); + } + + @Override + public void showToastInfo(String msg) { + toast(msg); + } + + @Override + public void showToastInfo(int msgId) { + toast(msgId); + } + + + @Override + public void showProgressDialog() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + + @Override + public void cancelProgressDialog() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DISMISS_LOADING_VIEW_ACTION)); + } + + @Override + public void setTitle(int titleId) { + mTitle.setTitleCenter(titleId); + } + + @Override + public void goScanPage() { + PageNavigationHelper.gotoScanPage(this); + } + + @Override + public void goDispatchPage() { + PageNavigationHelper.gotoDispatchPage(this); + } + + @Override + public void goHubPairPage(String sn, String hubType) { + PageNavigationHelper.gotoHubGuide1Page(this, sn, hubType); + } + + @Override + public void goApConfigPage(boolean hasSelecteGateway) { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoGatewayListPage(curFragment, hasSelecteGateway); + + } + + @Override + public void goTypeChoosePage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoTypeChoosePage(curFragment); + } + + @Override + public void goWiredwirelessPage(boolean isWifi) { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoPowerTipPage(curFragment, isWifi); + } + + @Override + public void goWiredwirelessPageNoAnim(boolean isWifi) { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoPowerTipPageNoAnim(curFragment, isWifi); + } + + @Override + public void goSoftApPage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoSoftApTipPage(curFragment); + } + + @Override + public void goSoftApPageNoAnim() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoSoftApTipPageNoAnim(curFragment); + } + + @Override + public void goNBPage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoNBTipPage(curFragment); + } + + @Override + public void goIMEIInputPage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoIMEIInputPage(curFragment); + } + + @Override + public void goNotSupportBindTipPage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoErrorTipPage(curFragment, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND); + } + + @Override + public void goLocationPage() { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoLocationTipPage(curFragment); + } + + @Override + public void goOfflineConfigPage(String sn, String devModelName, String imei) { + PageNavigationHelper.gotoOfflineConfigPage(this, sn, devModelName, imei); + } + + @Override + public void gotoDeviceSharePage(String sn) { + PageNavigationHelper.gotoDeviceSharePage(this, sn); + } + + @Override + public void goInitPage(DEVICE_NET_INFO_EX device_net_info_ex) { + final Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoInitPage(curFragment, device_net_info_ex); + } + + @Override + public void goCloudConnetPage() { + Fragment curFragment = getSupportFragmentManager().findFragmentById(R.id.content); + PageNavigationHelper.gotoCloudConnectPage(curFragment); + } + + @Override + public void completeAction(boolean isAp) { + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + boolean isDeviceDetail = deviceAddInfo.isDeviceDetail(); + + String code = CommonEvent.AP_PAIR_SUCCEED_2_MAIN_ACTION; + if (isDeviceDetail) { + code = CommonEvent.AP_PAIR_SUCCEED_2_MID_ACTION; + } + + if (isAp && deviceAddInfo.getGatewayInfo() != null) { + String deviceId = deviceAddInfo.getGatewayInfo().getSn(); + String apId = deviceAddInfo.getDeviceSn(); + + Bundle bundle = new Bundle(); + bundle.putString(LCConfiguration.Device_ID, deviceId); + bundle.putString(LCConfiguration.AP_ID, apId); + CommonEvent commonEvent = new CommonEvent(code); + commonEvent.setBundle(bundle); + EventBus.getDefault().post(commonEvent); + } + + destroy(); + + if (!isDeviceDetail) { + ProviderManager.getDeviceAddCustomProvider().goHomePage(getContextInfo()); + } + } + + /** + * 跳转到蓝牙模块 + */ + public void gotoAddBleLockPage(Bundle bundle) { + PageNavigationHelper.gotoAddBleLockPage(bundle); + destroy(); + } + + // 主动释放资源、结束activity,而不依赖于onDestroy方法来释放资源(onDestroy方法时机不可控) + private void destroy() { + finish(); + mPresenter.uninit(); + if (mLoadingPopWindow != null) { + if (mLoadingPopWindow.isShowing()) { + mLoadingPopWindow.dismiss(); + } + mLoadingPopWindow = null; + } + } + + // 离线配网成功,返回上一级页面 + private void offlineConfigSucceed() { + setResult(RESULT_OK); + finish(); + mPresenter.uninit(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SeachDeviceService.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SeachDeviceService.java new file mode 100644 index 0000000..9ea1b79 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SeachDeviceService.java @@ -0,0 +1,182 @@ +package com.mm.android.deviceaddmodule; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; + +import com.company.NetSDK.CB_fSearchDevicesCB; +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.company.NetSDK.INetSDK; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.util.concurrent.CopyOnWriteArrayList; + +public class SeachDeviceService extends Service { + public static final int SEND_START = 1; + public static final String TAG = "SeachDeviceService"; + + private long mLRet; + + private CopyOnWriteArrayList mListenerList; + long lastReceiveTime = 0; + private BroadcastReceiver mReceiver; + Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (!SearchDeviceManager.getInstance().mIsExist) return; + if (System.currentTimeMillis() - lastReceiveTime > 2000) { + handler.removeMessages(SEND_START); + handler.removeCallbacks(searchRunnable); + handler.postDelayed(searchRunnable, 500); //若2S内没有再搜索到设备,则重新开始搜索 + } else { + handler.removeMessages(SEND_START); + handler.sendEmptyMessageDelayed(SEND_START, 500); + } + } + }; + Runnable searchRunnable = new Runnable() { + @Override + public void run() { + SearchDeviceManager.getInstance().removeInvalidDevice(); + if (mLRet != 0) { + stopSearchDevices(); + } + mLRet = INetSDK.StartSearchDevices(new CB_fSearchDevicesCB() { + @Override + public void invoke(DEVICE_NET_INFO_EX device_net_info_ex) { + lastReceiveTime = System.currentTimeMillis(); + if (device_net_info_ex != null) { + String szSerialNo = new String(device_net_info_ex.szSerialNo).trim(); + if (device_net_info_ex.iIPVersion == 4 && mListenerList != null) { + for (int i = 0; i < mListenerList.size(); i++) { + SearchDeviceManager.ISearchDeviceListener listener = mListenerList.get(i); + if (listener != null) { + listener.onDeviceSearched(szSerialNo, device_net_info_ex); + } + } + } + } + } + }); + if (System.currentTimeMillis() - lastReceiveTime > 500) { + handler.removeMessages(SEND_START); + handler.removeCallbacks(searchRunnable); + handler.postDelayed(searchRunnable, 2000); //若2S内没有再搜索到设备,则重新开始搜索 + } else { + handler.removeMessages(SEND_START); + handler.sendEmptyMessageDelayed(SEND_START, 500); + } + if (mLRet == 0) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + } + } + }; + + @Override + public void onCreate() { + super.onCreate(); + mListenerList = new CopyOnWriteArrayList<>(); + // 注册广播监听器监听网络变化 + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(LCConfiguration.CONNECTIVITY_CHAGET_ACTION); + mReceiver = new Broadcast(); + registerReceiver(mReceiver, intentFilter); + } + + @Override + public IBinder onBind(Intent intent) { + return new SearchDeviceBinder(); + } + + /** + * 局域网内搜索设备信息 + */ + private void startSearchDevices() { + handler.removeCallbacks(searchRunnable); + handler.post(searchRunnable); + } + + /** + * 停止搜索 + */ + private void stopSearchDevicesAsync() { + handler.removeCallbacks(searchRunnable); + if (mLRet != 0) { + ProviderManager.getDeviceAddProvider().stopSearchDevicesAsync(mLRet, null); + } + } + + private void stopSearchDevices() { + handler.removeCallbacks(searchRunnable); + if (mLRet != 0) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + ProviderManager.getDeviceAddProvider().stopSearchDevices(mLRet, deviceAddInfo.getRequestId()); + } + } + + private void registerListener(SearchDeviceManager.ISearchDeviceListener listener) { + if (mListenerList != null && !mListenerList.contains(listener)) { + mListenerList.add(listener); + } + } + + private void unRegisterListener(SearchDeviceManager.ISearchDeviceListener listener) { + if (mListenerList != null && mListenerList.contains(listener)) { + mListenerList.remove(listener); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + stopSearchDevicesAsync(); + if (mListenerList != null) { + mListenerList.clear(); + } + mListenerList = null; + } + + public class SearchDeviceBinder extends Binder { + + public void startSearchDevices() { + SeachDeviceService.this.startSearchDevices(); + } + + public void stopSearchDevicesAsync() { + SeachDeviceService.this.stopSearchDevicesAsync(); + } + + public void stopSearchDevices() { + SeachDeviceService.this.stopSearchDevices(); + } + + public void registerListener(SearchDeviceManager.ISearchDeviceListener listener) { + SeachDeviceService.this.registerListener(listener); + } + + public void unRegisterListener(SearchDeviceManager.ISearchDeviceListener listener) { + SeachDeviceService.this.unRegisterListener(listener); + } + } + + private class Broadcast extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (LCConfiguration.CONNECTIVITY_CHAGET_ACTION.equals(intent.getAction())) { + SearchDeviceManager.getInstance().clearDevice(); + startSearchDevices(); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SearchDeviceManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SearchDeviceManager.java new file mode 100644 index 0000000..d656e78 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/SearchDeviceManager.java @@ -0,0 +1,224 @@ +package com.mm.android.deviceaddmodule; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.text.TextUtils; +import com.company.NetSDK.CB_fSDKLogCallBack; +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.entity.DeviceNetInfo; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 搜索局域网内设备信息的管理类 + */ + +public class SearchDeviceManager { + private static final String TAG = "SeachDeviceService"; + + private static volatile SearchDeviceManager sInstance; + private volatile ConcurrentHashMap mDeviceNetInfos = new ConcurrentHashMap<>(); + private SeachDeviceService.SearchDeviceBinder searchDevice; + private ISearchDeviceListener mListener; + boolean mIsConnected; //service是否已连接 + private LogCallBack mLogCallBack; + + + private SearchDeviceManager() { + mListener = new SearchDeviceImpl(); + mDeviceNetInfos = new ConcurrentHashMap<>(); + mLogCallBack = new LogCallBack(); + } + + public static SearchDeviceManager getInstance() { + if (sInstance == null) { + synchronized (SearchDeviceManager.class) { + if (sInstance == null) { + sInstance = new SearchDeviceManager(); + + } + } + } + return sInstance; + } + + public synchronized void connnectService() { + + if(!mIsConnected){ + Intent intent = new Intent(ProviderManager.getAppProvider().getAppContext(), SeachDeviceService.class); + mIsConnected = ProviderManager.getAppProvider().getAppContext().bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE); + } + if(!mIsExist)mIsExist = true; + } + + private ServiceConnection mBinderPoolConnection = new ServiceConnection() { + + @Override + public void onServiceDisconnected(ComponentName arg0) { + } + + @Override + public void onServiceConnected(ComponentName arg0, IBinder arg1) { + LogUtil.debugLog(TAG, "onServiceConnected"); + + searchDevice = (SeachDeviceService.SearchDeviceBinder) arg1; + + if (searchDevice != null) { + try { + searchDevice.linkToDeath(mBinderPoolDeathRecipient, 0); + } catch (Exception e) { + e.printStackTrace(); + } + } + registerListener(mListener); + startSearch(); + } + }; + + private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() { + + @Override + public void binderDied() { + LogUtil.debugLog(TAG, "binderDied"); + if (searchDevice != null) { + searchDevice.unlinkToDeath(mBinderPoolDeathRecipient, 0); + searchDevice = null; + } + + connnectService(); + } + }; + + public void registerListener(ISearchDeviceListener listener) { + if (searchDevice != null) { + searchDevice.registerListener(listener); + } + } + + public void unRegisterListener(ISearchDeviceListener listener) { + if (searchDevice != null) { + searchDevice.unRegisterListener(listener); + } + } + private void stopSearch() { + if (searchDevice != null) { + searchDevice.stopSearchDevicesAsync(); + if(mIsConnected){ + ProviderManager.getAppProvider().getAppContext().unbindService(mBinderPoolConnection); + mIsConnected = false; + } + + } + } + + public synchronized DEVICE_NET_INFO_EX getDeviceNetInfo(String snCode) { + if (TextUtils.isEmpty(snCode)) + return null; + if (mDeviceNetInfos != null&&mDeviceNetInfos.get(snCode)!=null) { + return mDeviceNetInfos.get(snCode).getDevNetInfoEx(); + } + return null; + } + + /** + * 搜索 + */ + public synchronized void startSearch() { + removeInvalidDevice(); + + if (searchDevice != null) { + connnectService(); + searchDevice.startSearchDevices(); + + } + } + + public synchronized void clearDevice() { + if (mDeviceNetInfos != null) { + mDeviceNetInfos.clear(); + LogUtil.debugLog(TAG, "clear"); + } + } + + /** + * 列表中移除无效的设备信息 + */ + public synchronized void removeInvalidDevice() { + if (mDeviceNetInfos != null) { + LogUtil.debugLog(TAG, "removeInvalidDevice: " + mDeviceNetInfos); + for (Map.Entry entry : mDeviceNetInfos.entrySet()) { + if (entry.getValue() != null) { + if (!entry.getValue().isValid()) { + // 移除无效的DeviceNetInfo + mDeviceNetInfos.remove(entry.getKey()); + LogUtil.debugLog(TAG, "remove: " + entry.getKey()); + } else { + // 将标志位重置 + entry.getValue().setValid(false); + } + } + } + LogUtil.debugLog(TAG, "removeInvalidDevice: " + mDeviceNetInfos); + } + } + volatile boolean mIsExist = false; + /** + * 释放资源 + */ + public synchronized void checkSearchDeviceServiceDestory() { + stopSearch(); + unRegisterListener(mListener); + clearDevice(); + mIsExist = false; + } + + public synchronized boolean checkSearchDeviceServiceIsExist() { + return mIsExist; + } + + private class SearchDeviceImpl implements ISearchDeviceListener { + + @Override + public void onDeviceSearched(String sncode, DEVICE_NET_INFO_EX info) { + if (mDeviceNetInfos != null) { + DeviceNetInfo deviceNetInfo=new DeviceNetInfo(info); + mDeviceNetInfos.put(sncode, deviceNetInfo); + LogUtil.debugLog(TAG, "onDeviceSearched: " + mDeviceNetInfos); + } + } + } + + public interface ISearchDeviceListener { + void onDeviceSearched(String sncode, DEVICE_NET_INFO_EX info); + } + + private class LogCallBack implements CB_fSDKLogCallBack{ + + @Override + public int invoke(byte[] bytes, int length) { + String netSDKLog = new String(bytes).trim(); + LogUtil.debugLog(TAG, netSDKLog); + + String type = ""; + String content = ""; + try { + JSONObject jsonObject = new JSONObject(netSDKLog); + type = jsonObject.optString("type"); + content = jsonObject.optString("log"); + LogUtil.debugLog(TAG, "type : " + type + " content : " + content); + } catch (JSONException e) { + e.printStackTrace(); + } + return 0; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/GatewayListAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/GatewayListAdapter.java new file mode 100644 index 0000000..6761164 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/GatewayListAdapter.java @@ -0,0 +1,53 @@ +package com.mm.android.deviceaddmodule.adapter; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.adapter.CommonAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; + +import java.util.List; + +/** + * 网关设备列表适配器 + */ +public class GatewayListAdapter extends CommonAdapter { + private int mSelectPosition=-1; + public GatewayListAdapter(List list, Context context) { + super(R.layout.gateway_list_item, list, context); + } + + @Override + public void convert(ViewHolder viewHolder, final DHDevice entity, + final int position, ViewGroup parent) { + CheckBox checkBox = (CheckBox) viewHolder + .findViewById(R.id.checkbox); + TextView deviceName = (TextView) viewHolder + .findViewById(R.id.device_name); + + deviceName.setText(entity.getName()); + if (entity.isOnline()) { + deviceName.setTextColor(mContext.getResources().getColor(R.color.c2)); + } else { + deviceName.setTextColor(mContext.getResources().getColor(R.color.c5)); + } + + if (mSelectPosition == position) + checkBox.setChecked(true); + else + checkBox.setChecked(false); + } + + public void setSelectPosition(int selectPosition){ + mSelectPosition = selectPosition; + notifyDataSetChanged(); + } + + public int getSelectPosition() { + return mSelectPosition; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/WifiListAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/WifiListAdapter.java new file mode 100644 index 0000000..e64d0b3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/adapter/WifiListAdapter.java @@ -0,0 +1,46 @@ +package com.mm.android.deviceaddmodule.adapter; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.mobilecommon.base.adapter.CommonAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; + +import java.util.List; + + +public class WifiListAdapter extends CommonAdapter { + public WifiListAdapter(int layout, List list, Context mContext) { + super(layout, list, mContext); + } + + @Override + public void convert(ViewHolder viewHolder, WlanInfo entity, + final int position, ViewGroup parent) { + TextView wlanName = (TextView) viewHolder.findViewById(R.id.wlan_name); + ImageView wlanStrength = (ImageView) viewHolder.findViewById(R.id.wlan_len); + ImageView wlanAuthMode = (ImageView) viewHolder.findViewById(R.id.wlan_mode); + + wlanName.setText(entity.getWlanSSID()); //设置wifi名 + + int quality = entity.getWlanQuality(); //获取wifi信号 + + if (quality < 15) { + int singalDrawable=entity.getWlanAuthMode() == 0 && entity.getWlanEncrAlgr() == 0?R.drawable.devicedetail_wifi_nosingal:R.drawable.devicedetail_wifi_nosingal_lock; + wlanStrength.setImageResource(singalDrawable); + } else if (quality < 45) { + int singalDrawable=entity.getWlanAuthMode() == 0 && entity.getWlanEncrAlgr() == 0?R.drawable.devicedetail_wifi_1singal:R.drawable.devicedetail_wifi_1singal_lock; + wlanStrength.setImageResource(singalDrawable); + } else if (quality < 75) { + int singalDrawable=entity.getWlanAuthMode() == 0 && entity.getWlanEncrAlgr() == 0?R.drawable.devicedetail_wifi_2singal:R.drawable.devicedetail_wifi_2singal_lock; + wlanStrength.setImageResource(singalDrawable); + } else { + int singalDrawable=entity.getWlanAuthMode() == 0 && entity.getWlanEncrAlgr() == 0?R.drawable.devicedetail_wifi_3singal:R.drawable.devicedetail_wifi_3singal_lock; + wlanStrength.setImageResource(singalDrawable); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseDevAddFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseDevAddFragment.java new file mode 100644 index 0000000..1d4148d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseDevAddFragment.java @@ -0,0 +1,85 @@ +package com.mm.android.deviceaddmodule.base; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseFragment; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.greenrobot.eventbus.EventBus; + +public abstract class BaseDevAddFragment extends BaseFragment { + + protected boolean isDestoryView; + + protected abstract void initView(View view); + + protected abstract void initData(); + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + isDestoryView = false; + LogUtil.debugLog("lcxw-fragment",getClass().getSimpleName()+ "--->onViewCreated"); + initView(view); + initData(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + isDestoryView = true; + hideSoftKeyboard(); + } + + public void hideSoftKeyboard() { + if (getActivity() == null) return ; + InputMethodManager im = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + if (im.isActive() || getActivity().getCurrentFocus() != null) { + im.hideSoftInputFromWindow(getActivity().findViewById(android.R.id.content) + .getWindowToken(), 0); + } + } + + public boolean isDestoryView() { + return isDestoryView; + } + + public Context getContextInfo() { + return getActivity(); + } + + public boolean isViewActive() { + return !isDestoryView(); + } + + public void showToastInfo(String msg) { + toast(msg); + } + + public void showToastInfo(int msgId) { + toast(msgId); + } + + public void showToastInfo(int msgId, String msg) { + if (!TextUtils.isEmpty(msg)) { + toast(msg); + } else { + toast(msgId); + } + } + + public void showProgressDialog() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + + public void cancelProgressDialog() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DISMISS_LOADING_VIEW_ACTION)); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseTipFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseTipFragment.java new file mode 100644 index 0000000..1de9788 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseTipFragment.java @@ -0,0 +1,88 @@ +package com.mm.android.deviceaddmodule.base; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; + +/** + * 引导提示页基类 + **/ +public abstract class BaseTipFragment extends BaseDevAddFragment implements View.OnClickListener { + protected ImageView mTipImg; + protected TextView mTipTxt, mTipTxt2, mHelpTxt, mNextBtn; + protected CheckBox mConfirmCheck; + protected View mView; + + protected abstract void nextAction(); //下一步操作 + + protected abstract void helpAction(); //帮助操作 + + protected abstract void init(); //初始化view及Data + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + if (mView != null) { + ViewGroup parent = (ViewGroup) mView.getParent(); + if (parent != null) { + parent.removeView(mView); + } + } else { + mView = inflater.inflate(R.layout.fragment_base_tip, container, false); + init(); + } + return mView; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + + } + + @Override + protected void initView(View view) { + mTipImg = view.findViewById(R.id.tip_img); + mTipTxt = view.findViewById(R.id.tip_txt); + mTipTxt2 = view.findViewById(R.id.tip_txt2); + mHelpTxt = view.findViewById(R.id.help_tip); + mNextBtn = view.findViewById(R.id.tv_next); + mConfirmCheck = view.findViewById(R.id.cb_confirm); + mNextBtn.setOnClickListener(this); + mConfirmCheck.setOnClickListener(this); + mHelpTxt.setOnClickListener(this); + } + + //提示图平铺 + protected void tipImageMatch(){ + RelativeLayout.LayoutParams params= (RelativeLayout.LayoutParams) mTipImg.getLayoutParams(); + params.height= RelativeLayout.LayoutParams.WRAP_CONTENT; + params.width=RelativeLayout.LayoutParams.MATCH_PARENT; + params.setMargins(0,0,0,0); + } + + @Override + protected void initData() { + + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_next) { + nextAction(); + } else if (id == R.id.cb_confirm) { + mNextBtn.setEnabled(mConfirmCheck.isChecked()); + } else if (id == R.id.help_tip) { + helpAction(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseWifiListenerFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseWifiListenerFragment.java new file mode 100644 index 0000000..c112b51 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/BaseWifiListenerFragment.java @@ -0,0 +1,78 @@ +package com.mm.android.deviceaddmodule.base; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Parcelable; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +/** + * 主要用于监听wifi状态的变化,变化的话就解除绑定,连接上后还是我们的那个的话就重新绑定 + */ +public abstract class BaseWifiListenerFragment extends BaseDevAddFragment { + protected DHWifiUtil mDHWifiUtil; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mDHWifiUtil = new DHWifiUtil(getContext().getApplicationContext()); + } + + @Override + protected IntentFilter createBroadCast() { + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + return filter; + } + + + + @Override + protected void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { + Parcelable parcelable = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + if (parcelable != null) { + NetworkInfo networkInfo = (NetworkInfo) parcelable; + NetworkInfo.State state = networkInfo.getState(); + if (state == NetworkInfo.State.DISCONNECTED) { + DeviceAddHelper.clearNetWork(); + } else if (state == NetworkInfo.State.CONNECTED) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String mSsid = deviceAddInfo.getSsid(); + String mCurrentSsid = getCurrentWifiInfo(); + if (mCurrentSsid!=null){ + String mTempStr = mCurrentSsid.startsWith("\"") ? mCurrentSsid : "\""+mCurrentSsid+"\""; + String mTempStrCache = "\"" + mSsid + "\""; + if (mTempStr.equals(mTempStrCache)){ + DeviceAddHelper.bindNetwork(null); + } + } + } + } + } + + } + + + public String getCurrentWifiInfo(){ + WifiInfo wifiInfo = mDHWifiUtil.getCurrentWifiInfo(); + return wifiInfo!=null?wifiInfo.getSSID():null; + } + + + @Override + public void onDestroyView() { + super.onDestroyView(); + unRegisterBroadCast(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBasePresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBasePresenter.java new file mode 100644 index 0000000..4a46061 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBasePresenter.java @@ -0,0 +1,7 @@ +package com.mm.android.deviceaddmodule.base; + +/** + * MVP模式P层接口 + */ +public interface IBasePresenter { +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBaseView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBaseView.java new file mode 100644 index 0000000..267e8a1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/base/IBaseView.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.base; + +import android.content.Context; + +/** + * MVP模式V层接口 + **/ +public interface IBaseView { + Context getContextInfo(); + boolean isViewActive(); //View层是否处于活动状态 + //Toast + void showToastInfo(String msg); + void showToastInfo(int msgId); + void showProgressDialog(); + void cancelProgressDialog(); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApBindSuccessConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApBindSuccessConstract.java new file mode 100644 index 0000000..8335bd3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApBindSuccessConstract.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; + +public interface ApBindSuccessConstract { + interface Presenter extends IBasePresenter { + void modifyApName(); + void setData(AddApResult addApResult); + } + + + interface View extends IBaseView { + String getApName(); + void setApName(String name); + void setApImg(String img); + void completeAction(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApPairConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApPairConstract.java new file mode 100644 index 0000000..2c1fbab --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ApPairConstract.java @@ -0,0 +1,18 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; + +public interface ApPairConstract { + interface Presenter extends IBasePresenter { + void pair(); + void stopPair(); + } + + + interface View extends IBaseView { + void goErrorTipPage(); + void goApBindSuccessPage(AddApResult addApResult); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BaseSoftApTipConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BaseSoftApTipConstract.java new file mode 100644 index 0000000..cddfa13 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BaseSoftApTipConstract.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface BaseSoftApTipConstract { + interface Presenter extends IBasePresenter { + boolean isLastTipPage(); //是否为最后一页引导页 + void dealWithUnknownSsid(); + boolean isWifiConnect(); + void verifyWifiOrLocationPermission(); + + } + + interface View extends IBaseView { + void updateTipImage(String imageUrl); + void updateTipTxt(String tipInfo); + void updateResetTxt(String resetTxt); + void goErrorTipPage(); + void applyLocationPermission(); + void gotoSoftApTipConnectWifiPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BindSuccessConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BindSuccessConstract.java new file mode 100644 index 0000000..927670a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/BindSuccessConstract.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + + +public interface BindSuccessConstract { + interface Presenter extends IBasePresenter { + void refreshDevice(boolean isExit); + + void modifyDevName(); + + void getDevName(); + } + + + interface View extends IBaseView { + + void updateDevImg(String img); + + String getDevName(); + + void setDevName(String name); + + void completeAction(); + + void deviceName(String name); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/CloudConnectConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/CloudConnectConstract.java new file mode 100644 index 0000000..af518aa --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/CloudConnectConstract.java @@ -0,0 +1,49 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface CloudConnectConstract { + interface Presenter extends IBasePresenter { + void bindDevice(); + + void getDeviceInfo(); + + void recyle(); + + boolean isWifiOfflineConfiMode(); //是否为离线配置模式 + + void notifyMiddleTimeUp(); + + void startConnectTiming(); //开始连接云 + + void stopConnectTiming(); //结束连接 + } + + + interface View extends IBaseView { + void goBindSuceesPage(); //绑定成功页 + + void goDevLoginPage(); //设备登录页 + + void goDevSecCodePage(); //设备安全码页 + + void goErrorTipPage(); //错误提示页 + + void goErrorTipPage(int errorCode); //错误提示页 + + void goBindDevicePage(); //绑定设备页 + + void completeAction(); //流程结束 + + void setCountDownTime(int time); //设置倒计时时间 + + void setMiddleTime(int time); //设置中间时间 + + void goOtherUserBindTipPage(); //设备被他人绑定提示页 + + void goNotSupportBuindTipPage(); //设备不支持被绑定 + + void goMainbind(String sn, String code, String encryptPwd); //返回主项目添加 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevLoginConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevLoginConstract.java new file mode 100644 index 0000000..0ff0e08 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevLoginConstract.java @@ -0,0 +1,32 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface DevLoginConstract { + interface Presenter extends IBasePresenter { + void devLogin(); + } + + interface View extends IBaseView { + String getDevicePassword(); //从输入框中获取设备密码 + + void goSoftAPWifiListPage(); //软AP添加wifi选择页 + + void goDeviceBindPage(); //进入设备绑定页 + + void goBindSuceesPage(); //进入绑定成功页 + + void goOtherUserBindTipPage(); //进入其他用户绑定提示页 + + void goErrorTipPage(int errorCode); //错误提示页 + + void completeAction(); //完成退出 + + void goDevLoginPage(); //设备登录页 + + void goDevSecCodePage(); //设备安全码页 + + void goMainbind(String sn, String code, String encryptPwd); //返回主项目添加 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevSecCodeConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevSecCodeConstract.java new file mode 100644 index 0000000..35b9ac3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevSecCodeConstract.java @@ -0,0 +1,28 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface DevSecCodeConstract { + interface Presenter extends IBasePresenter { + void validate(); + } + + interface View extends IBaseView { + String getDeviceSecCode(); //从输入框中获取设备安全码 + + void goErrorTipPage(int errorCode); //错误提示页 + + void goBindSuceesPage(); //进入绑定成功页 + + void goOtherUserBindTipPage(); + + void completeAction(); //完成退出 + + void goDevLoginPage(); //设备登录页 + + void goDevSecCodePage(); //设备安全码页 + + void goMainbind(String sn, String code, String encryptPwd); //返回主项目添加 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevWifiListConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevWifiListConstract.java new file mode 100644 index 0000000..4f22cbd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DevWifiListConstract.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.entity.WlanInfo; + +import java.util.List; + +public interface DevWifiListConstract { + interface Presenter extends IBasePresenter { + boolean isDevSupport5G(); + void getWifiList(); + } + + interface View extends IBaseView { + void updateWifiList(List list); + void goWifiPwdPage(WlanInfo wlanInfo, boolean isNotNeedLogin); + void goHiddenWifiPwdPage(boolean isNotNeedLogin); + void goDevLoginPage(); + void showListView(); + void showErrorInfoView(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DeviceAddConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DeviceAddConstract.java new file mode 100644 index 0000000..90eaa92 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DeviceAddConstract.java @@ -0,0 +1,75 @@ +package com.mm.android.deviceaddmodule.contract; + +import android.content.Intent; +import android.os.Bundle; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface DeviceAddConstract { + interface Presenter extends IBasePresenter { + String getCurTitleMode(); + + void setCurTitleMode(String titleMode); + + void dispatchIntentData(Intent intent); + + void getGPSLocation(); //获取gps信息 + + void dispatchPageNavigation(); //添加流程页跳转 + + void uninit(); //释放相关资源 + + void getDeviceShareInfo(); + + boolean canBeShare(); + + void changeToWireless(); + void changeToWired(); + void changeToSoftAp(); + void changeToNB(); + } + + interface View extends IBaseView { + void setTitle(int titleId); //设置标题 + + void goScanPage(); //扫描页 + + void goDispatchPage(); //分发页 + + void goHubPairPage(String sn, String hubType); //hub电池相机引导页 + + void goApConfigPage(boolean hasSelecteGateway); //跳转至配件添加页 + + void goWiredwirelessPage(boolean isWifi); //跳转至有线/无线添加 + + void goWiredwirelessPageNoAnim(boolean isWifi); //跳转至有线/无线添加 + + void goSoftApPage(); //跳转至软AP添加 + + void goSoftApPageNoAnim(); //跳转至软AP添加 + + void goNBPage(); //跳转至NB添加 + + void goOfflineConfigPage(String sn, String devModelName, String imei); //跳转到离线配网页面 + + void gotoDeviceSharePage(String sn); //跳转设备分享页面 + + void gotoAddBleLockPage(Bundle bundle); + + void goInitPage(DEVICE_NET_INFO_EX device_net_info_ex); + + void goCloudConnetPage(); + + void goTypeChoosePage(); + + void completeAction(boolean isAp); + + void goLocationPage(); //跳转至设备本地配网添加 + + void goIMEIInputPage(); //跳转至输入imei页 + + void goNotSupportBindTipPage(); //跳转到不支持绑定的设备页面 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DispatchContract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DispatchContract.java new file mode 100644 index 0000000..38da078 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/DispatchContract.java @@ -0,0 +1,25 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface DispatchContract { + interface Presenter extends IBasePresenter { + boolean isManualInputPage(); //是否为手动输入设备序列号页面 + boolean isSnInValid(String sn); + boolean isScCodeInValid(String scCode); + void dispatchResult(); + } + + interface View extends IBaseView { + void goTypeChoosePage(); //跳转到设备类型选择页 + void goNotSupportBindTipPage(); //跳转到不支持绑定的设备页面 + void goOtherUserBindTipPage(); //跳转至设备被其他用户绑定提示页 + void showAddBoxTip(); //盒子添加提示 + void goCloudConnectPage(); //跳转至云平台连接页 + void goDeviceLoginPage(); //跳转至设备登录页 + void goSecCodePage(); //跳转至安全码验证页 + void goDeviceBindPage(); //跳转至设备绑定页 + void goIMEIInputPage(); //跳转至输入imei页 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ErrorTipConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ErrorTipConstract.java new file mode 100644 index 0000000..7d4a8b8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ErrorTipConstract.java @@ -0,0 +1,25 @@ +package com.mm.android.deviceaddmodule.contract; + +import android.support.v4.app.Fragment; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface ErrorTipConstract { + interface Presenter extends IBasePresenter { + void dispatchError(int errorCode); + boolean isResetPage(); //通用错误页,及没有按钮 + boolean isUserBindTipPage(); //是否为设备绑定提示页 + boolean isUserBindTipPageByBind();//绑定时提示设备被其他用户绑定 + } + + interface View extends IBaseView { + Fragment getParent(); + void updateInfo(String info,String img,boolean isNeedMatch); + void updateInfo(int infoId,int tip2Id,String img,boolean isNeedMatch); + void updateInfo(int infoId,String img,boolean isNeedMatch); + void hideTipTxt(); + void hideHelp(); + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/GatewayListConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/GatewayListConstract.java new file mode 100644 index 0000000..2527c23 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/GatewayListConstract.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; + +import java.util.List; + +public interface GatewayListConstract { + interface Presenter extends IBasePresenter { + List getGatewayData(boolean selectedGateway); + int gatewaySize(); + void dispatchCurSelect(int pos); + int getSelectedpos(); + } + + interface View extends IBaseView { + void goTipPage(); + void setApSn(String apSn); + void setApImg(String img); + void setSelectedPos(int pos); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HiddenWifiPwdConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HiddenWifiPwdConstract.java new file mode 100644 index 0000000..ad8ad8f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HiddenWifiPwdConstract.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + + +public interface HiddenWifiPwdConstract { + interface Presenter extends IBasePresenter { + + void setIsNotNeedLogin(boolean isNotNeedLogin); + String getCurWifiName(); + void updateWifiCache(); + void connectWifi(); + boolean isDevSupport5G(); + } + + interface View extends IBaseView { + String getWifiPwd(); + String getWifiSSID(); + void goCloudConnectPage(); + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HubApGuide1Constract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HubApGuide1Constract.java new file mode 100644 index 0000000..db4741a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/HubApGuide1Constract.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface HubApGuide1Constract { + interface Presenter extends IBasePresenter { + void checkDevIntroductionInfo(String deviceModel); + } + + + interface View extends IBaseView { + void updateTip(String tipImg, String tipTxt,String helpTxt); + void showInfoView(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/InitContract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/InitContract.java new file mode 100644 index 0000000..5e4f13d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/InitContract.java @@ -0,0 +1,25 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface InitContract { + interface Presenter extends IBasePresenter { + void setDeviceEX(DEVICE_NET_INFO_EX deviceEX); + void playTipSound(); //播放提示音频 + void startDevInitByIp(); //设备单播初始化 + void startDevInit(); //设备组播初始化 + boolean isPwdValid(); //密码是否有效 + void checkDevice(); + void recyle(); + } + + interface View extends IBaseView { + int getMusicRes(); //获取音频资源 + String getInitPwd(); //获取设备密码 + void goSoftAPWifiListPage(); //软AP添加wifi选择页 + void goConnectCloudPage(); //进入连接云平台页 + void goErrorTipPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ManualInputConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ManualInputConstract.java new file mode 100644 index 0000000..e42c28b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ManualInputConstract.java @@ -0,0 +1,4 @@ +package com.mm.android.deviceaddmodule.contract; + +public interface ManualInputConstract extends ScanContract { +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/OfflineConfigConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/OfflineConfigConstract.java new file mode 100644 index 0000000..054b207 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/OfflineConfigConstract.java @@ -0,0 +1,15 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface OfflineConfigConstract { + interface Presenter extends IBasePresenter { + void resetCache(); + void getDeviceInfo(String deviceSn, String deviceModelName, String imeiCode); //从服务获取设备信息 + } + + interface View extends IBaseView { + void onGetDeviceInfoError(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ScanContract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ScanContract.java new file mode 100644 index 0000000..0b00a69 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/ScanContract.java @@ -0,0 +1,33 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResult; + +/** + * 二维码扫描契约类,定义二维码扫描页面相关View层和Presenter层的接口 + **/ +public interface ScanContract { + interface Presenter extends IBasePresenter{ + ScanResult parseScanStr(String scanStr, String sc); //解析扫描到的二维码 + void getDeviceInfo(String deviceSn, String deviceCodeModel); //从服务获取设备信息 + boolean isManualInputPage(); //是否为手动输入设备序列号页面 + boolean isSnInValid(String sn); + void recyle(); + void resetCache(); + boolean isScCodeInValid(String scCode); + } + + interface View extends IBaseView{ + void goTypeChoosePage(); //跳转到设备类型选择页 + void goNotSupportBindTipPage(); //跳转到不支持绑定的设备页面 + void goOtherUserBindTipPage(); //跳转至设备被其他用户绑定提示页 + void showAddBoxTip(); //盒子添加提示,维持乐橙逻辑 + void goCloudConnectPage(); //跳转至云平台连接页 + void goDeviceLoginPage(); //跳转至设备登录页 + void goSecCodePage(); //跳转至安全码验证页 + void goDeviceBindPage(); //跳转至设备绑定页 + void goIMEIInputPage(); //跳转至输入imei页 + void goMainbind(String sn, String code, String encryptPwd); //返回主项目添加 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SecurityCheckConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SecurityCheckConstract.java new file mode 100644 index 0000000..9da97b8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SecurityCheckConstract.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface SecurityCheckConstract { + interface Presenter extends IBasePresenter { + void checkDevice(); + void recyle(); + } + + interface View extends IBaseView { + void goInitPage(DEVICE_NET_INFO_EX device_net_info_ex); + void goErrorTipPage(); + void goDevLoginPage(); //设备登录页 + void goSoftApWifiListPage(boolean isNotNeedLogin); + void goCloudConnetPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SmartConfigConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SmartConfigConstract.java new file mode 100644 index 0000000..d498c22 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SmartConfigConstract.java @@ -0,0 +1,38 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface SmartConfigConstract { + interface Presenter extends IBasePresenter { + void startSmartConfig(); //开始smartconfig配对线程,和声波配对 + void recyle(); //回收资源 + + String getConfigMode(); + + void stopAudio(); + + void playAudio(); + + void pauseAudio(); + + void releaseAudio(); + + void wifiPwdErrorClick(); + } + + interface View extends IBaseView { + void goDevInitPage(DEVICE_NET_INFO_EX device_net_info_ex); //进入设备初始化页 + void goConnectCloudPage(); //进入连接云平台页 + void goDevLoginPage(); //P2P设备进入设备登录页 + void goConfigTimeoutPage(); //配置超时页 + void goWfiPwdPage(); + void stopCountDown(); + void updateTip2Txt(boolean isSupportSoundWave, boolean isSupportSoundWaveV2); + + void hideTipWifiPwdErrorTxt(boolean isOversea); + void completeAction(); + void goBindDevicePage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SoftApWifiPwdConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SoftApWifiPwdConstract.java new file mode 100644 index 0000000..953f5e5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/SoftApWifiPwdConstract.java @@ -0,0 +1,24 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; +import com.mm.android.deviceaddmodule.entity.WlanInfo; + +public interface SoftApWifiPwdConstract { + interface Presenter extends IBasePresenter { + void setWlanInfo(WlanInfo wlanInfo); + void setIsNotNeedLogin(boolean isNotNeedLogin); + boolean isDevSupport5G(); + String getCurWifiName(); + void updateWifiCache(); + String getSavedWifiPwd(); + void connectWifi(); + boolean getSavedWifiCheckBoxStatus(); + } + + interface View extends IBaseView { + String getWifiPwd(); + boolean isSavePwdChecked(); + void goCloudConnectPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TimeoutConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TimeoutConstract.java new file mode 100644 index 0000000..813992f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TimeoutConstract.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface TimeoutConstract { + interface Presenter extends IBasePresenter { + void setErrorData(int errorCode, String timeoutDevtypeModel); + + void dispatchAction1(); + } + + interface View extends IBaseView { + //A类型 + void showAView(); + + void goScanPage(); + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipSoftApConnectWifiConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipSoftApConnectWifiConstract.java new file mode 100644 index 0000000..58f4b49 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipSoftApConnectWifiConstract.java @@ -0,0 +1,19 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface TipSoftApConnectWifiConstract { + interface Presenter extends IBasePresenter { + void copyWifiPwd(); + void connectWifiAction(boolean isFirst); //开始连接设备热点 + void dispatchHotConnected(); //处理热点连接,判断当前wifi是否已连接至热点 + String getHotSSID(); //获取热点ssid + } + + interface View extends IBaseView { + void updateWifiName(String wifiName); + void updateConnectFailedTipText(String wifiName, String wifiPwd, boolean isSupportAddBySc, boolean isManualInput); + void goSecurityCheckPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipWifiConnectConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipWifiConnectConstract.java new file mode 100644 index 0000000..d282870 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TipWifiConnectConstract.java @@ -0,0 +1,19 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface TipWifiConnectConstract { + interface Presenter extends IBasePresenter { + void searchDevice(); + void stopSearchDevice(); + String getConfigMode(); + } + + interface View extends IBaseView { + void goDevInitPage(DEVICE_NET_INFO_EX device_net_info_ex); //进入设备初始化页 + void goWifiConfigPage(); //进入配网页 + void goCloudConnectPage(); //进入云连接页 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TypeChooseConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TypeChooseConstract.java new file mode 100644 index 0000000..f6ee520 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/TypeChooseConstract.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface TypeChooseConstract { + interface Presenter extends IBasePresenter { + void getDeviceInfoSync(String deviceModelName); + void checkDevIntroductionInfo(String deviceModelName); + void resetDevPwdCache(); //回到设备选择页,清空设备密码缓存 + } + + interface View extends IBaseView { + void showSearchError(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/WifiPwdConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/WifiPwdConstract.java new file mode 100644 index 0000000..e8c5a2a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/contract/WifiPwdConstract.java @@ -0,0 +1,26 @@ +package com.mm.android.deviceaddmodule.contract; + +import com.mm.android.deviceaddmodule.base.IBasePresenter; +import com.mm.android.deviceaddmodule.base.IBaseView; + +public interface WifiPwdConstract { + interface Presenter extends IBasePresenter { + boolean isDevSupport5G(); + + String getCurWifiName(); + + void updateWifiCache(); + + String getSavedWifiPwd(); + + boolean getSavedWifiCheckBoxStatus(); + + String getConfigMode(); + } + + interface View extends IBaseView { + String getWifiPwd(); + + boolean isSavePwdChecked(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/BasePresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/BasePresenter.java new file mode 100644 index 0000000..578ec65 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/BasePresenter.java @@ -0,0 +1,46 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Intent; +import android.os.Handler; + +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBasePresenter; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.common.HandlerManager; + +import java.lang.ref.WeakReference; + +/** + * Presenter基类,所有Presenter继承自此类 + */ +public abstract class BasePresenter implements IBasePresenter { + protected WeakReference mView; + private HandlerManager mHandlerManager; + public BasePresenter(T view) { + mView = new WeakReference<>(view); + } + + protected Handler addHandler(Handler handler){ + if(mHandlerManager == null){ + mHandlerManager = new HandlerManager(); + } + return mHandlerManager.addHandler(handler); + } + + private void clearHandlers(){ + if(mHandlerManager != null){ + mHandlerManager.clearHandlers(); + } + } + + @Override + public void unInit() { + clearHandlers(); + } + + @Override + public void dispatchIntentData(Intent intent) { + + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/CurWifiInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/CurWifiInfo.java new file mode 100644 index 0000000..2ee2e81 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/CurWifiInfo.java @@ -0,0 +1,70 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; + +/** + * 当前连接Wifi状态信息 + */ +public class CurWifiInfo implements Serializable { + public static class Response { + public CurWifiInfo data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), CurWifiInfo.class); + } + } + + //当前有无连接热点 + private boolean linkEnable; + //若连接了热点,填热点的名称;若未连接,填空 + private String ssid; + //强度, 0最弱,5最强 + private int intensity; + //强度,单位为dbm + private String sigStrength; + //WIFI认证模式 + private String auth; + + public boolean isLinkEnable() { + return linkEnable; + } + + public void setLinkEnable(boolean linkEnable) { + this.linkEnable = linkEnable; + } + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public int getIntensity() { + return intensity; + } + + public void setIntensity(int intensity) { + this.intensity = intensity; + } + + public String getSigStrength() { + return sigStrength; + } + + public void setSigStrength(String sigStrength) { + this.sigStrength = sigStrength; + } + + public String getAuth() { + return auth; + } + + public void setAuth(String auth) { + this.auth = auth; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceConstant.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceConstant.java new file mode 100644 index 0000000..ae75f68 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceConstant.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +/** + * 设备管理常量类 + */ + +public class DeviceConstant { + + /** + * Intent跳转的key常量或者一些常量key值 + */ + public interface IntentKey { + String DEVICE_CURRENT_WIFI_INFO = "DEVICE_CURRENT_WIFI_INFO"; + String DEVICE_WIFI_CONFIG_INFO = "DEVICE_WIFI_CONFIG_INFO"; + String DHDEVICE_INFO = "DHDEVICE_INFO"; + String DHDEVICE_UNBIND = "DHDEVICE_UNBIND"; + String DHDEVICE_NEW_NAME = "DHDEVICE_NEW_NAME"; + + } + + /** + * Intent跳转请求码返回码常量 + */ + public interface IntentCode { + int DEVICE_SETTING_WIFI_OPERATE = 208; + int DEVICE_SETTING_WIFI_LIST = 209; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListActivity.java new file mode 100644 index 0000000..ac42c3b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListActivity.java @@ -0,0 +1,213 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.app.Activity; +import android.content.Intent; +import android.os.Handler; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.BaseManagerFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; + +import java.util.ArrayList; +import java.util.List; + +import static com.mm.android.deviceaddmodule.device_wifi.ErrorTipActivity.ERROR_PARAMS; + +/** + * 设备wifi列表界面 + */ +public class DeviceWifiListActivity extends BaseManagerFragmentActivity implements DeviceWifiListConstract.View, + CommonTitle.OnTitleClickListener, AdapterView.OnItemClickListener{ + + protected DeviceWifiListAdapter mAdapter; + protected ListView mList; + protected TextView mCurWifiSSIDTv; + protected ImageView mCurWifiQualityIv; + protected LinearLayout mNo5GLl; + protected TextView mNo5GTv; + protected TextView deviceWifi; + + @Override + protected void initLayout() { + setContentView(R.layout.activity_device_wifi_list); + } + + @Override + protected View initTitle() { + CommonTitle title = (CommonTitle) findViewById(R.id.device_wifi_list_title); + title.initView(R.drawable.mobile_common_title_back, R.drawable.common_title_refresh_selector, R.string.mobile_common_network_config); + title.setOnTitleClickListener(this); + return title; + } + + @Override + protected void initView() { + super.initView(); + mList = (ListView) findViewById(R.id.device_wifi_list); + mCurWifiSSIDTv = (TextView) findViewById(R.id.wifi_ssid); + mCurWifiQualityIv = (ImageView) findViewById(R.id.wifi_quality_icon); + mNo5GLl = findViewById(R.id.device_wifi_no_5g); + mNo5GTv = findViewById(R.id.tv_5g_tip); + + mNo5GTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(DeviceWifiListActivity.this, ErrorTipActivity.class); + intent.putExtra(ERROR_PARAMS,1); + startActivity(intent); + } + }); + deviceWifi = findViewById(R.id.device_wifi_list_text); + deviceWifi.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(DeviceWifiListActivity.this, ErrorTipActivity.class); + intent.putExtra(ERROR_PARAMS,2); + startActivity(intent); + } + }); + mList.setOnItemClickListener(this); + View view = LayoutInflater.from(this).inflate(R.layout.item_wifi_list_more, null); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(DeviceWifiListActivity.this, HiddenWifiActivity.class); + intent.putExtra(LCConfiguration.Device_ID,mPresenter.getDHDevice().getDeviceId()); + intent.putExtra(LCConfiguration.SUPPORT_5G,mPresenter.isSupport5G(mPresenter.getDHDevice().getWifiTransferMode())); + startActivity(intent); + } + }); + mList.addFooterView(view,null,true); + mAdapter = new DeviceWifiListAdapter(R.layout.include_device_wifi_list_item, new ArrayList(), this); + mList.setAdapter(mAdapter); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + if (!isActivityDestory()) { + mPresenter.getDeviceWifiListAsync(); + } + } + }, 100); + } + + @Override + public void initPresenter() { + mPresenter = (T) new DeviceWifiListPresenter(this); + } + + @Override + protected void initData() { + mPresenter.dispatchIntentData(getIntent()); + } + + @Override + public void onCommonTitleClick(int id) { + switch (id) { + case CommonTitle.ID_LEFT: + Intent intent = new Intent(); + intent.putExtra(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO, mPresenter.getCurWifiInfo()); + setResult(RESULT_OK, intent); + DeviceWifiListActivity.this.finish(); + break; + case CommonTitle.ID_RIGHT: + mPresenter.getDeviceWifiListAsync(); + break; + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent intent = new Intent(this,DeviceWifiPasswordActivity.class); + intent.putExtra(DeviceConstant.IntentKey.DEVICE_WIFI_CONFIG_INFO,mPresenter.getWifiInfo(position)); + intent.putExtra(LCConfiguration.Device_ID,mPresenter.getDHDevice().getDeviceId()); + intent.putExtra(LCConfiguration.SUPPORT_5G,mPresenter.isSupport5G(mPresenter.getDHDevice().getWifiTransferMode())); + startActivityForResult(intent,DeviceConstant.IntentCode.DEVICE_SETTING_WIFI_OPERATE); + } + + @Override + public void refreshListView(List wifiInfos) { + if (mAdapter != null){ + mAdapter.clearData(); + mAdapter.addData(wifiInfos); + mAdapter.notifyDataSetChanged(); + } + } + + @Override + public void onLoadSucceed(boolean isEmpty,boolean isError) { + if (isEmpty) { + findViewById(R.id.device_wifi_list_empty_view).setVisibility(View.VISIBLE); + findViewById(R.id.device_wifi_list_layout).setVisibility(View.GONE); + mNo5GLl.setVisibility(View.GONE); + ((TextView) findViewById(R.id.device_wifi_list_empty_view)).setText(isError?R.string.mobile_common_get_info_failed:R.string.device_manager_wifi_list_empty); + } else { + if (!mPresenter.isSupport5G(mPresenter.getDHDevice().getWifiTransferMode())) { + mNo5GLl.setVisibility(View.VISIBLE); + } + findViewById(R.id.device_wifi_list_empty_view).setVisibility(View.GONE); + findViewById(R.id.device_wifi_list_layout).setVisibility(View.VISIBLE); + } + } + + @Override + public void updateCurWifiLayout(CurWifiInfo curWifiInfo) { + if (curWifiInfo == null || !curWifiInfo.isLinkEnable() || TextUtils.isEmpty(curWifiInfo.getSsid())) { + findViewById(R.id.device_wifi_list_connected).setVisibility(View.GONE); + findViewById(R.id.device_wifi_list_connected_info).setVisibility(View.GONE); + } else { + findViewById(R.id.device_wifi_list_connected).setVisibility(View.VISIBLE); + findViewById(R.id.device_wifi_list_connected_info).setVisibility(View.VISIBLE); + mCurWifiSSIDTv.setText(curWifiInfo.getSsid()); + mCurWifiQualityIv.setVisibility(View.VISIBLE); + if (curWifiInfo.getIntensity() < 2) { + mCurWifiQualityIv.setImageResource("OPEN".equalsIgnoreCase(curWifiInfo.getAuth()) + ? R.drawable.devicedetail_wifi_nosingal : R.drawable.devicedetail_wifi_nosingal_lock); + } else if (curWifiInfo.getIntensity() < 3) { + mCurWifiQualityIv.setImageResource("OPEN".equalsIgnoreCase(curWifiInfo.getAuth()) + ? R.drawable.devicedetail_wifi_1singal : R.drawable.devicedetail_wifi_1singal_lock); + } else if (curWifiInfo.getIntensity() < 4) { + mCurWifiQualityIv.setImageResource("OPEN".equalsIgnoreCase(curWifiInfo.getAuth()) + ? R.drawable.devicedetail_wifi_2singal : R.drawable.devicedetail_wifi_2singal_lock); + } else { + mCurWifiQualityIv.setImageResource("OPEN".equalsIgnoreCase(curWifiInfo.getAuth()) + ? R.drawable.devicedetail_wifi_3singal : R.drawable.devicedetail_wifi_3singal_lock); + } + } + } + + @Override + public void viewFinish() { + DeviceWifiListActivity.this.finish(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == DeviceConstant.IntentCode.DEVICE_SETTING_WIFI_OPERATE && resultCode == Activity.RESULT_OK + && data != null) { + CurWifiInfo curWifiInfo = (CurWifiInfo) data.getSerializableExtra(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO); + Intent intent = new Intent(); + intent.putExtra(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO, curWifiInfo); + setResult(RESULT_OK, intent); + DeviceWifiListActivity.this.finish(); + } + } + + @Override + public void onBackPressed() { + Intent intent = new Intent(); + intent.putExtra(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO, mPresenter.getCurWifiInfo()); + setResult(RESULT_OK, intent); + super.onBackPressed(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListAdapter.java new file mode 100644 index 0000000..c85c91c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListAdapter.java @@ -0,0 +1,43 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.adapter.CommonAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; + +import java.util.List; + +public class DeviceWifiListAdapter extends CommonAdapter { + + public DeviceWifiListAdapter(int layout, List list, Context context) { + super(layout, list, context); + } + + @Override + public void convert(ViewHolder viewHolder, WifiInfo entity, + final int position, ViewGroup parent) { + TextView wifiSSID = (TextView) viewHolder.findViewById(R.id.wifi_ssid); + ImageView wifiQualityIcon = (ImageView) viewHolder.findViewById(R.id.wifi_quality_icon); + + wifiSSID.setText(entity.getSsid()); //设置wifi名 + int quality = entity.getIntensity(); //获取wifi信号 + + if (quality < 2) { + wifiQualityIcon.setImageResource("OPEN".equalsIgnoreCase(entity.getAuth()) + ? R.drawable.devicedetail_wifi_nosingal : R.drawable.devicedetail_wifi_nosingal_lock); + } else if (quality < 3) { + wifiQualityIcon.setImageResource("OPEN".equalsIgnoreCase(entity.getAuth()) + ? R.drawable.devicedetail_wifi_1singal : R.drawable.devicedetail_wifi_1singal_lock); + } else if (quality < 4) { + wifiQualityIcon.setImageResource("OPEN".equalsIgnoreCase(entity.getAuth()) + ? R.drawable.devicedetail_wifi_2singal : R.drawable.devicedetail_wifi_2singal_lock); + } else { + wifiQualityIcon.setImageResource("OPEN".equalsIgnoreCase(entity.getAuth()) + ? R.drawable.devicedetail_wifi_3singal : R.drawable.devicedetail_wifi_3singal_lock); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListConstract.java new file mode 100644 index 0000000..4dc1df7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListConstract.java @@ -0,0 +1,24 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBasePresenter; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBaseView; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; + +import java.util.List; + +public interface DeviceWifiListConstract { + interface Presenter extends IBasePresenter { + void getDeviceWifiListAsync(); + WifiInfo getWifiInfo(int position); + CurWifiInfo getCurWifiInfo(); + boolean isSupport5G(String wifiMode); + DHDevice getDHDevice(); + } + + interface View extends IBaseView { + void refreshListView(List wlanInfos); + void onLoadSucceed(boolean isEmpty, boolean isError); + void updateCurWifiLayout(CurWifiInfo curWifiInfo); + void viewFinish(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListPresenter.java new file mode 100644 index 0000000..5a1cc91 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiListPresenter.java @@ -0,0 +1,199 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.DHBaseHandler; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; + +import java.util.ArrayList; +import java.util.List; + +public class DeviceWifiListPresenter + extends BasePresenter implements DeviceWifiListConstract.Presenter { + + protected DHDevice mDHDevice; + protected CurWifiInfo mCurWifiInfo; + protected List mWifiInfos; + protected LCBusinessHandler mGetWifiConfigHandler; + protected boolean mIsLoading = false; + + public DeviceWifiListPresenter(T view) { + super(view); + initModel(); + mWifiInfos = new ArrayList<>(); + } + + protected void initModel() { + + } + + @Override + public void dispatchIntentData(Intent intent) { + if (intent != null && intent.getExtras() != null) { + Bundle bundle = intent.getExtras(); + mDHDevice = (DHDevice) bundle.getSerializable(DeviceConstant.IntentKey.DHDEVICE_INFO); + if (bundle.containsKey(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO)) + mCurWifiInfo = (CurWifiInfo) bundle.getSerializable(DeviceConstant.IntentKey.DEVICE_CURRENT_WIFI_INFO); + } + if (mDHDevice == null) + mView.get().viewFinish(); + } + + @Override + public void unInit() { + if (mGetWifiConfigHandler != null) { + mGetWifiConfigHandler.cancle(); + mGetWifiConfigHandler.removeCallbacksAndMessages(null); + mGetWifiConfigHandler = null; + } + } + + @Override + public void getDeviceWifiListAsync() { + if (mIsLoading) + return; + if (mGetWifiConfigHandler != null) { + mGetWifiConfigHandler.cancle(); + mGetWifiConfigHandler = null; + } + mGetWifiConfigHandler = new DHBaseHandler(mView) { + @Override + public void onStart() { + mView.get().showProgressDialog(); + mIsLoading = true; + } + + @Override + protected void onCompleted() { + mView.get().cancelProgressDialog(); + mIsLoading = false; + } + + @Override + public void handleBusinessFinally(Message msg) { + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + WifiConfig wifiConfig = (WifiConfig) msg.obj; + if (wifiConfig != null && wifiConfig.isEnable()) { + List wifiInfos = processWifiInfos(wifiConfig.getwLan()); + mWifiInfos.clear(); + mWifiInfos.addAll(wifiInfos); + mView.get().refreshListView(mWifiInfos); + mView.get().onLoadSucceed(mWifiInfos.isEmpty(), false); + mView.get().updateCurWifiLayout(mCurWifiInfo); + } else { + mView.get().onLoadSucceed(true, false); + mView.get().updateCurWifiLayout(mCurWifiInfo); + mView.get().showToastInfo(mView.get().getContextInfo().getString(R.string.device_manager_wifi_disable)); + } + } else { + mView.get().onLoadSucceed(true, true); + mView.get().updateCurWifiLayout(null); + mView.get().showToastInfo(mView.get().getContextInfo().getString(R.string.mobile_common_get_info_failed)); + } + } + }; + new BusinessRunnable(mGetWifiConfigHandler) { + @Override + public void doBusiness() throws BusinessException { + try { + WifiConfig response = DeviceAddOpenApiManager.wifiAround(LCDeviceEngine.newInstance().accessToken, mDHDevice.getDeviceId()); + mGetWifiConfigHandler.obtainMessage(HandleMessageCode.HMC_SUCCESS, response).sendToTarget(); + } catch (BusinessException e) { + throw e; + } + } + }; + } + + @Override + public WifiInfo getWifiInfo(int position) { + if (position >= mWifiInfos.size()) + return null; + return mWifiInfos.get(position); + } + + public boolean isSupport5G(String wifiMode) { + if (!TextUtils.isEmpty(wifiMode)) { + return wifiMode.toUpperCase().contains("5GHZ"); + } + return false; + } + + @Override + public CurWifiInfo getCurWifiInfo() { + return mCurWifiInfo; + } + + @Override + public DHDevice getDHDevice() { + return mDHDevice; + } + + /** + * 处理去掉相同的wifi,和当前已连接的wifi + * + * @param wifiInfos + * @return + */ + protected List processWifiInfos(List wifiInfos) { + List tems = new ArrayList<>(); + if (mCurWifiInfo == null) { + mCurWifiInfo = new CurWifiInfo(); + } + if (wifiInfos == null || wifiInfos.isEmpty()) + return tems; + // 获取当前连接的wifi + for (WifiInfo wifiInfo : wifiInfos) { + if (WifiInfo.Status.connected.equalsIgnoreCase(wifiInfo.getLinkStatus())) { + mCurWifiInfo.setIntensity(wifiInfo.getIntensity()); + mCurWifiInfo.setSsid(wifiInfo.getSsid()); + mCurWifiInfo.setAuth(wifiInfo.getAuth()); + mCurWifiInfo.setLinkEnable(true); + break; + } + } + + for (WifiInfo wifiInfo : wifiInfos) { + boolean isContains = false; + for (WifiInfo tem : tems) { + if (wifiInfo.getSsid() != null && wifiInfo.getSsid().equalsIgnoreCase(tem.getSsid())) { + isContains = true; + break; + } + } + + if (isContains) { + //已包含,去重 + continue; + } + + if (mCurWifiInfo.getSsid() == null) { + //当前热点为空 + tems.add(wifiInfo); + } else if (!mCurWifiInfo.getSsid().equalsIgnoreCase(wifiInfo.getSsid())) { + //当前热点不为空,去除当前已连接wifi + tems.add(wifiInfo); + } + } + + return tems; + } + + public boolean isDevSupport5G() { + String wifiMode = ""; + if (!TextUtils.isEmpty(wifiMode)) { + return wifiMode.toUpperCase().contains("5GHZ"); + } + return false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordActivity.java new file mode 100644 index 0000000..6710e3b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordActivity.java @@ -0,0 +1,155 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.BaseManagerFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; + +import static com.mm.android.deviceaddmodule.device_wifi.ErrorTipActivity.ERROR_PARAMS; + +/** + * 设备wifi列表界面 + */ +public class DeviceWifiPasswordActivity + extends BaseManagerFragmentActivity implements DeviceWifiPasswordConstract.View, + CommonTitle.OnTitleClickListener, View.OnClickListener { + + protected TextView mWifiSSIDTv; + protected Button mDoneBtn; + protected ClearPasswordEditText mWifiPasswordEdt; + private TextView mSaveWifiPwdCheckbox; + private ImageView mWifiImg; + private TextView m5GWifiTipTv; + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + mWifiPasswordEdt.removeTextChangedListener(mTextWatcher); + String str = Utils4DeviceManager.wifiPwdFilter(s.toString()); + if (!str.equals(s.toString())) { + mWifiPasswordEdt.setText(str); + mWifiPasswordEdt.setSelection(str.length()); + } + mWifiPasswordEdt.addTextChangedListener(mTextWatcher); + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + @Override + protected void initLayout() { + setContentView(R.layout.activity_device_wifi_password); + } + + @Override + protected View initTitle() { + CommonTitle title = (CommonTitle) findViewById(R.id.device_wifi_password_title); + title.initView(R.drawable.mobile_common_title_back, 0, R.string.mobile_common_network_config); + title.setOnTitleClickListener(this); + return title; + } + + @Override + protected void initView() { + super.initView(); + + mWifiSSIDTv = (TextView) findViewById(R.id.device_wifi_ssid); + mDoneBtn = (Button) findViewById(R.id.device_wifi_password_done_btn); + mWifiPasswordEdt = (ClearPasswordEditText) findViewById(R.id.device_wifi_password); + mWifiSSIDTv.setText(mPresenter.getWifiSSID()); + mDoneBtn.setOnClickListener(this); + mWifiPasswordEdt.addTextChangedListener(mTextWatcher); + mSaveWifiPwdCheckbox = (TextView) findViewById(R.id.wifi_pwd_check); + mSaveWifiPwdCheckbox.setOnClickListener(this); + String savePassword = mPresenter.getSavedWifiPassword(); + boolean wifiCheckBoxStatus = mPresenter.getSavedWifiCheckBoxStatus(); + if (!TextUtils.isEmpty(savePassword)) { + mWifiPasswordEdt.setText(savePassword); + mWifiPasswordEdt.setSelection(savePassword.length()); + } + mSaveWifiPwdCheckbox.setSelected(wifiCheckBoxStatus); + mWifiImg = (ImageView) findViewById(R.id.wifi_img); + mWifiImg.setImageResource(mPresenter.getSupport5G() ? R.drawable.adddevice_icon_wifipassword_nosupport5g : R.drawable.adddevice_icon_wifipassword_nosupport5g); + m5GWifiTipTv = findViewById(R.id.tv_5g_tip); + m5GWifiTipTv.setOnClickListener(this); + m5GWifiTipTv.setVisibility(mPresenter.getSupport5G() ? View.GONE : View.VISIBLE); + } + + @Override + public void initPresenter() { + mPresenter = (T) new DeviceWifiPasswordPresenter<>(this); + } + + @Override + protected void initData() { + mPresenter.dispatchIntentData(getIntent()); + } + + @Override + public void onCommonTitleClick(int id) { + switch (id) { + case CommonTitle.ID_LEFT: + DeviceWifiPasswordActivity.this.finish(); + break; + } + } + + @Override + public String getWifiPassword() { + return mWifiPasswordEdt.getText().toString(); + } + + @Override + public boolean isSavePwdChecked() { + return mSaveWifiPwdCheckbox.isSelected(); + } + + @Override + public void onWifiOperateSucceed(CurWifiInfo curWifiInfo) { + DeviceWifiPasswordActivity.this.finish(); + } + + @Override + public void onClick(View view) { + int viewId = view.getId(); + if (viewId == R.id.device_wifi_password_done_btn) { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPasswordEdt.getWindowToken(), 0); + mWifiPasswordEdt.postDelayed(new Runnable() { + @Override + public void run() { + mPresenter.updateWifiCache(); + mPresenter.wifiOperate(); + } + }, 100); + } else if (viewId == R.id.wifi_pwd_check) { + view.setSelected(!view.isSelected()); + if (!view.isSelected()) { + mPresenter.updateWifiCache(); + } + } else if (viewId == R.id.tv_5g_tip) { + Intent intent = new Intent(this, ErrorTipActivity.class); + intent.putExtra(ERROR_PARAMS, 1); + startActivity(intent); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordConstract.java new file mode 100644 index 0000000..9272192 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordConstract.java @@ -0,0 +1,21 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBasePresenter; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBaseView; + +public interface DeviceWifiPasswordConstract { + interface Presenter extends IBasePresenter { + void wifiOperate(); + String getWifiSSID(); + void updateWifiCache(); + String getSavedWifiPassword(); + boolean getSavedWifiCheckBoxStatus(); + boolean getSupport5G(); + } + + interface View extends IBaseView { + String getWifiPassword(); + boolean isSavePwdChecked(); + void onWifiOperateSucceed(CurWifiInfo curWifiInfo); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordPresenter.java new file mode 100644 index 0000000..4cd888d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/DeviceWifiPasswordPresenter.java @@ -0,0 +1,104 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Intent; +import android.os.Handler; + +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.DHBaseHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; + +public class DeviceWifiPasswordPresenter extends BasePresenter implements DeviceWifiPasswordConstract.Presenter { + + public String WIFI_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_ADD_"; + public String WIFI_CHECKBOX_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_CHECKBOX_ADD_"; + + protected String mDeviceId; + protected WifiInfo mWifiInfo; + private DHBaseHandler mWifiOperateHandler; + protected boolean support5G = false; + + public DeviceWifiPasswordPresenter(T view) { + super(view); + initModel(); + } + + protected void initModel() { + + } + + @Override + public void dispatchIntentData(Intent intent) { + if (intent != null && intent.getExtras() != null) { + mDeviceId = intent.getStringExtra(LCConfiguration.Device_ID); + mWifiInfo = (WifiInfo) intent.getSerializableExtra(DeviceConstant.IntentKey.DEVICE_WIFI_CONFIG_INFO); + support5G = intent.getBooleanExtra(LCConfiguration.SUPPORT_5G, false); + } + } + + @Override + public boolean getSupport5G() { + return support5G; + } + + @Override + public void updateWifiCache() { + if (mView.get().isSavePwdChecked()) { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + mWifiInfo.getSsid(), mView.get().getWifiPassword()); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + mWifiInfo.getSsid(), true); + } else { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + mWifiInfo.getSsid(), ""); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + mWifiInfo.getSsid(), false); + } + } + + @Override + public String getSavedWifiPassword() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getString(WIFI_SAVE_PREFIX + mWifiInfo.getSsid()); + } + + @Override + public boolean getSavedWifiCheckBoxStatus() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getBoolean(WIFI_CHECKBOX_SAVE_PREFIX + mWifiInfo.getSsid()); + } + + @Override + public void wifiOperate() { + new BusinessRunnable(mWifiOperateHandler) { + @Override + public void doBusiness() throws BusinessException { + try { + DeviceAddOpenApiManager.controlDeviceWifi(LCDeviceEngine.newInstance().accessToken, mDeviceId, mWifiInfo.getSsid(), mWifiInfo.getBSSID(), true, mView.get().getWifiPassword()); + mWifiOperateHandler.obtainMessage(HandleMessageCode.HMC_SUCCESS, true).sendToTarget(); + } catch (BusinessException e) { + throw e; + } + } + }; + mView.get().showToastInfo(R.string.device_manager_wifi_connetting_tip); + Handler mHandler = new Handler(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mView.get().onWifiOperateSucceed(null); + } + }, 3000); + } + + @Override + public String getWifiSSID() { + if (mWifiInfo == null) + return ""; + return mWifiInfo.getSsid(); + } + + @Override + public void unInit() { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/ErrorTipActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/ErrorTipActivity.java new file mode 100644 index 0000000..fdf7ca1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/ErrorTipActivity.java @@ -0,0 +1,87 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.graphics.Paint; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.BaseManagerFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; + +/** + * 设备wifi列表界面 + */ +public class ErrorTipActivity extends BaseManagerFragmentActivity implements CommonTitle.OnTitleClickListener { + + public static String ERROR_PARAMS = "error_params"; + + private ImageView imageView; + private TextView textView; + private TextView textView1; + private TextView mHelpLinkTxt,mHelpPhoneTv; + int errorcode; + + private PermissionHelper mPermissionHelper; + + @Override + protected void initLayout() { + setContentView(R.layout.activity_error_tip); + } + + @Override + protected View initTitle() { + CommonTitle title = (CommonTitle) findViewById(R.id.error_tip_title); + title.initView(R.drawable.mobile_common_title_back, 0, R.string.mobile_common_network_config); + title.setOnTitleClickListener(this); + return title; + } + + @Override + protected void initView() { + super.initView(); + imageView = findViewById(R.id.tip_img); + textView = findViewById(R.id.tip_txt); + textView1 = findViewById(R.id.tip_txt_1); + mHelpLinkTxt = findViewById(R.id.help_link); + mHelpLinkTxt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ProviderManager.getDeviceAddCustomProvider().goFAQWebview(ErrorTipActivity.this); + } + }); + mHelpPhoneTv = findViewById(R.id.tv_help_phone); + mHelpPhoneTv.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); + mHelpPhoneTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + if (errorcode == 1) { + imageView.setBackgroundResource(R.drawable.adddevice_icon_wifiexplain); + textView1.setVisibility(View.VISIBLE); + textView.setText(R.string.add_device_tip_not_support_5g_1); + } else if (errorcode == 2) { + imageView.setBackgroundResource(R.drawable.adddevice_icon_wifiexplain_choosewifi); + textView.setText(R.string.add_device_tip_wifi_name); + } + } + + @Override + protected void initData() { + errorcode = getIntent().getIntExtra(ERROR_PARAMS, 0); + + } + + @Override + public void onCommonTitleClick(int id) { + switch (id) { + case CommonTitle.ID_LEFT: + ErrorTipActivity.this.finish(); + break; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiActivity.java new file mode 100644 index 0000000..a0983ea --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiActivity.java @@ -0,0 +1,112 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.BaseManagerFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; + +import static com.mm.android.deviceaddmodule.device_wifi.ErrorTipActivity.ERROR_PARAMS; + +public class HiddenWifiActivity + extends BaseManagerFragmentActivity implements HiddenWifiConstract.View { + + + private TextView mNext; + + private ClearEditText mWifiName; + + private ClearPasswordEditText mWifiPsw; + + @Override + protected View initTitle() { + CommonTitle title = findViewById(R.id.device_hidden_title); + title.initView(R.drawable.mobile_common_title_back, 0, R.string.device_manager_wifi_title); + title.setOnTitleClickListener(new CommonTitle.OnTitleClickListener() { + @Override + public void onCommonTitleClick(int id) { + if (id == CommonTitle.ID_LEFT) { + HiddenWifiActivity.this.finish(); + } + } + }); + return title; + } + + @Override + protected void initLayout() { + setContentView(R.layout.activity_device_hidden_wifi); + } + + protected void initView() { + super.initView(); + + mWifiName = findViewById(R.id.wifi_name); + mWifiPsw = findViewById(R.id.wifi_psw); + + mNext = findViewById(R.id.next); + mNext.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPsw.getWindowToken(), 0); + mWifiPsw.postDelayed(new Runnable() { + @Override + public void run() { + mPresenter.wifiOperate(); + } + }, 100); + } + }); + findViewById(R.id.tv_5g_tip).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(HiddenWifiActivity.this, ErrorTipActivity.class); + intent.putExtra(ERROR_PARAMS, 1); + startActivity(intent); + } + }); + + mWifiName.addTextChangedListener(new SimpleTextChangedListener() { + @Override + public void afterTextChanged(Editable s) { + mNext.setEnabled(s.length()>0); + } + }); + + } + + @Override + public void initPresenter() { + mPresenter = (T) new HiddenWifiPresenter<>(this); + } + + @Override + protected void initData() { + mPresenter.dispatchIntentData(getIntent()); + } + + + @Override + public String getWifiSSID() { + return mWifiName.getText().toString().trim(); + } + + @Override + public String getWifiPassword() { + return mWifiPsw.getText().toString().trim(); + } + + @Override + public void onWifiOperateSucceed(CurWifiInfo curWifiInfo) { + finish(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiConstract.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiConstract.java new file mode 100644 index 0000000..0dd1bb8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiConstract.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBasePresenter; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBaseView; + +public interface HiddenWifiConstract { + interface Presenter extends IBasePresenter { + void wifiOperate(); + } + + interface View extends IBaseView { + String getWifiSSID(); + String getWifiPassword(); + void onWifiOperateSucceed(CurWifiInfo curWifiInfo); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiPresenter.java new file mode 100644 index 0000000..46bc081 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/HiddenWifiPresenter.java @@ -0,0 +1,68 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.content.Intent; +import android.os.Handler; + +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.DHBaseHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; + +public class HiddenWifiPresenter extends BasePresenter implements HiddenWifiConstract.Presenter { + + protected String mDeviceId; + private DHBaseHandler mWifiOperateHandler; + + public HiddenWifiPresenter(T view) { + super(view); + initModel(); + } + + protected void initModel() { + + } + + @Override + public void dispatchIntentData(Intent intent) { + if (intent != null && intent.getExtras() != null) { + mDeviceId = intent.getStringExtra(LCConfiguration.Device_ID); + } + } + + + @Override + public void wifiOperate() { + if (mView.get().getWifiSSID().equalsIgnoreCase("")) { + return; + } + new BusinessRunnable(mWifiOperateHandler) { + @Override + public void doBusiness() throws BusinessException { + try { + DeviceAddOpenApiManager.controlDeviceWifi(LCDeviceEngine.newInstance().accessToken, mDeviceId, mView.get().getWifiSSID(),"", true, mView.get().getWifiPassword()); + mWifiOperateHandler.obtainMessage(HandleMessageCode.HMC_SUCCESS, true).sendToTarget(); + } catch (BusinessException e) { + throw e; + } + } + }; + mView.get().showToastInfo(R.string.device_manager_wifi_connetting_tip); + Handler mHandler = new Handler(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mView.get().onWifiOperateSucceed(null); + } + }, 3000); + } + + + @Override + public void unInit() { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/SimpleTextChangedListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/SimpleTextChangedListener.java new file mode 100644 index 0000000..4de0184 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/SimpleTextChangedListener.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.text.Editable; +import android.text.TextWatcher; + +public class SimpleTextChangedListener implements TextWatcher{ + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/Utils4DeviceManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/Utils4DeviceManager.java new file mode 100644 index 0000000..40722a8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/Utils4DeviceManager.java @@ -0,0 +1,95 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.text.TextUtils; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * 设备管理相关工具类 + * + */ +public class Utils4DeviceManager { + public static String wifiPwdFilter(String str) { + + if (TextUtils.isEmpty(str)) { + return str; + } + + String chinese1 = "[\u2E80-\uA4CF]"; + String chinese2 = "[\uF900-\uFAFF]"; + String chinese3 = "[\uFE30-\uFE4F]"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (temp.matches(chinese1) || temp.matches(chinese2) || temp.matches(chinese3)) { + str = str.replace(temp, ""); + return wifiPwdFilter(str); + } + } + return str; + } + + public static String replaceSpecial(String source, + List filterStringList) { + for (String s : filterStringList) { + if (source.contains(s)) { + return source.replaceAll(s, ""); + } + } + return source; + } + + // 转换从服务获取的timeInfo + public static long convertTimeInfo(String time){ + // 服务时间格式:"THHMMSS" 现转换时的格式"HHMM" + if(time.length() == 4){ + long hour = Long.valueOf(time.substring(0, 2)); + long min = Long.valueOf(time.substring(2, time.length())); + return hour * 3600 + min * 60; + } + return 0; + } + + public static String getServerBeginTime(int hour, int minute) { + Calendar beginCalendar = Calendar.getInstance(); + beginCalendar.set(Calendar.SECOND, 0); + beginCalendar.set(Calendar.HOUR_OF_DAY, hour); + beginCalendar.set(Calendar.MINUTE, minute); + SimpleDateFormat format = new SimpleDateFormat("HHmmss"); + Date date = beginCalendar.getTime(); + String time = format.format(date); + return "T" + time; + } + + public static String getServerEndTime(int hour, int minute) { + Calendar beginCalendar = Calendar.getInstance(); + beginCalendar.set(Calendar.SECOND, 59); + beginCalendar.set(Calendar.HOUR_OF_DAY, hour); + beginCalendar.set(Calendar.MINUTE, minute); + SimpleDateFormat format = new SimpleDateFormat("HHmmss"); + Date date = beginCalendar.getTime(); + String time = format.format(date); + return "T" + time; + } + + public static Calendar resolveTime(String time){ + time = time.substring(1); + SimpleDateFormat format = new SimpleDateFormat("HHmmss"); + Date date = null; + try { + date = format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + Calendar calendar = Calendar.getInstance(); + if(date != null){ + calendar.setTime(date); + } + + return calendar; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiConfig.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiConfig.java new file mode 100644 index 0000000..8cf8f1b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiConfig.java @@ -0,0 +1,42 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import java.io.Serializable; +import java.util.List; + +/** + * Wifi配置信息 + */ +public class WifiConfig implements Serializable { + public static class Response { + public WifiConfig data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), WifiConfig.class); + } + } + + //设备是否开启WIFI。true:开启,false:关闭 + private boolean enable; + //设备搜索到的wifi列表 + private List wLan; + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public List getwLan() { + return wLan; + } + + public void setwLan(List wLan) { + this.wLan = wLan; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiInfo.java new file mode 100644 index 0000000..abed7ab --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/device_wifi/WifiInfo.java @@ -0,0 +1,79 @@ +package com.mm.android.deviceaddmodule.device_wifi; + +import android.support.annotation.StringDef; + +import java.io.Serializable; +import java.lang.annotation.Retention; + +import static com.mm.android.deviceaddmodule.device_wifi.WifiInfo.Status.connected; +import static com.mm.android.deviceaddmodule.device_wifi.WifiInfo.Status.connecting; +import static com.mm.android.deviceaddmodule.device_wifi.WifiInfo.Status.unconnected; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Wifi状态信息 + */ +public class WifiInfo implements Serializable { + //该WIFI的唯一标示符,通常是一个MAC地址 + private String bssid ; + //若连接了热点,填热点的名称;若未连接,填空 + private String ssid; + //连接状态。unconnected:未连接;connecting:连接中;connected:已连接 + private String linkStatus; + //强度, 0最弱,5最强 + private int intensity; + //WIFI认证模式:OPEN,WEP,WPA/WPA2 PSK,WPA/WPA2 + private String auth; + + @Retention(SOURCE) + @StringDef({unconnected, connecting, connected,""}) + public @interface Status { + String unconnected = "unconnected"; //未连接; + String connecting = "connecting"; //连接中; + String connected = "connected"; //已连接 + } + + public String getBSSID() { + return bssid; + } + + public String getBssid() { + return bssid; + } + + public void setBssid(String bssid) { + this.bssid = bssid; + } + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getLinkStatus() { + return linkStatus; + } + + public void setLinkStatus(String linkStatus) { + this.linkStatus = linkStatus; + } + + public int getIntensity() { + return intensity; + } + + public void setIntensity(int intensity) { + this.intensity = intensity; + } + + public String getAuth() { + return auth; + } + + public void setAuth(String auth) { + this.auth = auth; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/DeviceNetInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/DeviceNetInfo.java new file mode 100644 index 0000000..1444d0b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/DeviceNetInfo.java @@ -0,0 +1,39 @@ +package com.mm.android.deviceaddmodule.entity; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; + +/** + * 封装DEVICE_NET_INFO_EX + */ + +public class DeviceNetInfo { + private DEVICE_NET_INFO_EX mDevNetInfoEx; + + private boolean mIsValid; + + public DeviceNetInfo(DEVICE_NET_INFO_EX devNetInfoEx) { + mDevNetInfoEx = devNetInfoEx; + mIsValid = true; + } + + public DEVICE_NET_INFO_EX getDevNetInfoEx() { + return mDevNetInfoEx; + } + + public void setDevNetInfoEx(DEVICE_NET_INFO_EX devNetInfoEx) { + this.mDevNetInfoEx = devNetInfoEx; + } + + public boolean isValid() { + return mIsValid; + } + + public void setValid(boolean isValid) { + this.mIsValid = isValid; + } + + @Override + public String toString() { + return "byInitStatus:" + mDevNetInfoEx.byInitStatus + "bySpecialAbility:" + mDevNetInfoEx.bySpecialAbility;/*.append(":").append(mDevNetInfoEx)*/ + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/WlanInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/WlanInfo.java new file mode 100644 index 0000000..1e5a759 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/entity/WlanInfo.java @@ -0,0 +1,75 @@ +package com.mm.android.deviceaddmodule.entity; + +import java.io.Serializable; + + +public class WlanInfo implements Serializable { + /** + * 序列化ID + */ + private static final long serialVersionUID = 1L; + + private String wlanSSID; //wifi名称 + private int wlanQuality; //wifi信号 + private int wlanEncry; //加密方式 + private int wlanAuthMode; //当wlanAuthMode和wlanEncrAlgr都为0时就是不需要密码 + private int wlanEncrAlgr; + private String wlanPassword; //wifi密码 + private String wlanBSSID; //wifi Mac地址 + + public int getWlanQuality() { + return wlanQuality; + } + + public void setWlanQuality(int wlanQuality) { + this.wlanQuality = wlanQuality; + } + + public String getWlanSSID() { + return wlanSSID; + } + + public void setWlanSSID(String wlanSSID) { + this.wlanSSID = wlanSSID; + } + + public int getWlanEncry() { + return wlanEncry; + } + + public void setWlanEncry(int wlanEncry) { + this.wlanEncry = wlanEncry; + } + + public String getWlanPassword() { + return wlanPassword; + } + + public void setWlanPassword(String wlanPassword) { + this.wlanPassword = wlanPassword; + } + + public int getWlanAuthMode() { + return wlanAuthMode; + } + + public void setWlanAuthMode(int wlanAuthMode) { + this.wlanAuthMode = wlanAuthMode; + } + + public int getWlanEncrAlgr() { + return wlanEncrAlgr; + } + + public void setWlanEncrAlgr(int wlanEncrAlgr) { + this.wlanEncrAlgr = wlanEncrAlgr; + } + + public String getWlanBSSID() { + return wlanBSSID; + } + + public void setWlanBSSID(String wlanBSSID) { + this.wlanBSSID = wlanBSSID; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/event/DeviceAddEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/event/DeviceAddEvent.java new file mode 100644 index 0000000..556cd23 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/event/DeviceAddEvent.java @@ -0,0 +1,49 @@ +package com.mm.android.deviceaddmodule.event; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; + +/** + * 设备添加消息通信类 + **/ +public class DeviceAddEvent extends BaseEvent { + //EVENT ACTION + public static String TITLE_MODE_ACTION="title_mode_action"; //标题栏模式控制 + public static String CONFIG_PAGE_NAVIGATION_ACTION="config_page_navigation_action"; //添加流程页跳转通知 + public static String SOFTAP_REFRSH_WIFI_LIST="softap_refresh_wifi_list"; //软AP刷新wifi列表 + public static String SOFTAP_REFRSH_WIFI_LIST_DISABLE_ACTION ="softap_refresh_wifi_list_disable_action"; //软AP刷新wifi列表按钮置灰 + public static String SOFTAP_REFRSH_WIFI_LIST_ENABLE_ACTION ="softap_refresh_wifi_list_enable_action"; //软AP刷新wifi列表按钮高亮 + public static String SHOW_LOADING_VIEW_ACTION="show_loading_view_action"; //显示加载框 + public static String DISMISS_LOADING_VIEW_ACTION="dismiss_loading_view_action"; //隐藏加载框 + public static String CHANGE_TO_WIRELESS_ACTION="change_to_wireless_action"; //切换到无线 + public static String CHANGE_TO_WIRED_ACTION="change_to_wired_action"; //切换到有线 + public static String CHANGE_TO_SOFTAP_ACTION="change_to_softap_action"; //切换到软AP + public static String SHOW_TYPE_CHOSE_ACTION="show_type_chose_action"; //切换到软AP + public static String REFRESH_BATTERY_CAMERA_LIST = "refresh_battery_camera_list"; //更新电池相机列表 + public static String DESTROY_ACTION = "destroy_action"; //销毁设备添加使用的缓存数据 + public static String OFFLINE_CONFIG_SUCCESS_ACTION = "offline_config_success"; //离线配网成功 + + //EVENT KEY + public interface KEY{ + String TITLE_MODE="title_mode"; //标题栏模式 + } + + Bundle bundle; + public DeviceAddEvent(String code) { + super(code); + } + + public DeviceAddEvent(String code,Bundle bundle){ + super(code); + this.bundle=bundle; + } + + public Bundle getBundle() { + return bundle; + } + + public void setBundle(Bundle bundle) { + this.bundle = bundle; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/ActivityHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/ActivityHelper.java new file mode 100644 index 0000000..ca7d3c9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/ActivityHelper.java @@ -0,0 +1,42 @@ +package com.mm.android.deviceaddmodule.helper; + +import android.app.Activity; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +public class ActivityHelper { + public static Activity getCurrentActivity () { + try { + Class activityThreadClass = Class.forName("android.app.ActivityThread"); + Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke( + null); + Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); + activitiesField.setAccessible(true); + Map activities = (Map) activitiesField.get(activityThread); + for (Object activityRecord : activities.values()) { + Class activityRecordClass = activityRecord.getClass(); + Field pausedField = activityRecordClass.getDeclaredField("paused"); + pausedField.setAccessible(true); + if (!pausedField.getBoolean(activityRecord)) { + Field activityField = activityRecordClass.getDeclaredField("activity"); + activityField.setAccessible(true); + Activity activity = (Activity) activityField.get(activityRecord); + return activity; + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddHelper.java new file mode 100644 index 0000000..87d79b4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddHelper.java @@ -0,0 +1,439 @@ +package com.mm.android.deviceaddmodule.helper; + +import android.annotation.TargetApi; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; + +import com.company.NetSDK.CFG_NETAPP_WLAN; +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.company.NetSDK.FinalVar; +import com.company.NetSDK.INetSDK; +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.LcnDeviceAddActivity; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.p2pDevice.P2PErrorHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; +import org.json.JSONException; +import org.json.JSONObject; + +public class DeviceAddHelper { + public static final String DEVICE_MODEL_NAME_PARAM= "device_model_name_param"; //设备市场型号 + public static final int DEVICE_NAME_MAX_LENGTH = 20; //设备名长度限制 + public static final int AP_NAME_MAX_LENGTH = 20; //配件名长度限制 + public static final String AP_WIFI_NAME_DAP = "DAP-XXXX"; //软Ap通用设备热点名称 + public static final String AP_WIFI_VERSION_V1 = "V1"; //软Ap wifi version版本 + public static final String AP_WIFI_VERSION_V2 = "V2"; //软Ap wifi version版本 + + // 是否支持新声波,二进制第1位,0表示否,1表示是 + public static final int ALLOW_SoundWaveV2 = 1; // 0001 + + // 是否支持老声波,二进制第2位,0表示否,1表示是 + public static final int ALLOW_SoundWave = 1 << 1; // 0010 + + // 是否支持SmartConfig,二进制第3位,0表示否,1表示是 + public static final int ALLOW_SmartConfig = 1 << 2; // 0100 + + // 是否支持SoftAP,二进制第4位,0表示否,1表示是 + public static final int ALLOW_SoftAP = 1 << 3; // 1000 + + // 是否支持LAN,二进制第4位,0表示否,1表示是 + public static final int ALLOW_LAN = 1 << 4; // 10000 + + // 是否支持蓝牙,二进制第4位,0表示否,1表示是 + public static final int ALLOW_BT = 1 << 5; // 100000 + + public enum TitleMode { +// FLASH, //闪光灯 + MORE, //更多 + MORE2, //更多模式2 + MORE3, //更多模式3 + MORE4, //更多模式4 + REFRESH, //刷新 + BLANK, //空白 + SHARE, //设备共享 + FREE_CLOUD_STORAGE, //免费云存储 + MODIFY_DEVICE_NAME //修改设备密码 + } + + public enum TimeoutDevTypeModel { + A_MODEL, //A系列 + CK_MODEL, //CK系列 + COMMON_MODEL, //通用设备 + DOORBELL_MODEL, //门铃系列 + AP_MODEL, //配件 + OTHER_MODEL, //其他 + TP1_MODEL, //TP1类型 + TP1S_MODEL, //TP1S类型 + G1_MODEL, //G1类型 + K5_MODEL //门锁类型 + } + + //设备添加相关错误码 + public interface ErrorCode { + //输入设备序列号流程相关错误码 + int INPUT_SN_ERROR_BIND_BY_OTHER = 1000 + 1; //输入序列号时设备被其他用户绑定 + int DEVICE_BIND_ERROR_BIND_BY_OTHER = 1000 + 2; //绑定时设备被其他用户绑定 + int DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND = 1000 + 3; //扫码、选型号、设备上线绑定时不支持绑定的设备类型 + //设备选择流程相关错误码 + int TYPE_CHOOSE_ERROR_1 = 2000; + //有线无线配置流程相关错误码 + int WIRED_WIRELESS_ERROR_CONFIG_TIMEOUT = 3000 + 1; //配置超时 + //软AP添加流程相关错误码 + int SOFTAP_ERROR_CONNECT_HOT_FAILED = 4000 + 1; //连接设备热点失败 + int SOFTAP_ERROR_CONNECT_WIFI_FAILED = 4000 + 2; //设备连接wifi失败 + //设备初始化流程相关错误码 + int INIT_ERROR_SERCRITY_CHECK_TIMEOUT = 5000 + 1; //安全检查超时 + int INIT_ERROR_INIT_FAILED = 5000 + 2; //初始化失败 + //连接云平台流程相关错误码 + int CLOUND_CONNECT_ERROR_CONNECT_TIMEOUT = 6000 + 1; //连接超时 + int CLOUND_CONNECT_QUERY_STATUS_TIMEOUT = 6000 + 2; //查询超时 + + //通用 + int COMMON_ERROR_NOT_SUPPORT_5G = 7000 + 1; //不支持5G + int COMMON_ERROR_NOT_SUPPORT_RESET = 7000 + 2; //重置设备 + int COMMON_ERROR_NOT_SUPPORT_HUB_AP_RESET = 7000 + 3; //重置设备 + int COMMON_ERROR_NOT_SUPPORT_HUB_RESET = 7000 + 4; //重置设备 + + int COMMON_ERROR_DEVICE_LOCKED = 7000 + 5; //设备锁定 + int COMMON_ERROR_RED_ROTATE = 7000 + 6; //红灯旋转 + int COMMON_ERROR_RED_ALWAYS = 7000 + 7; //红灯长亮 + int COMMON_ERROR_RED_FLASH = 7000 + 8; //红灯闪烁 + int COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN = 7000 + 9; //超过10次 + int COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE = 7000 + 10; //再次超过10次 + int COMMON_ERROR_DEVICE_IP_ERROR = 7000 + 11; //IP + int COMMON_ERROR_DEVICE_SN_CODE_CONFLICT = 7000 + 12; //串号 + int COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH = 7000 + 13; //imei和device id不匹配 + + int COMMON_ERROR_ABOUT_WIFI_PWD = 7000 + 14; //关于WIFI密码 + + int COMMON_ERROR_CONNECT_FAIL = 7000 + 15; //软AP连接失败 + int COMMON_ERROR_WIFI_NAME = 7000 + 16; //软AP连接失败 + + //配件 + int AP_ERROR_PAIR_TIMEOUT = 8000 + 2; //配对超时 + } + + //OMS配置key + public interface OMSKey { + final static String ERROR_TIPS_TYPE = "ErrorTipsType"; + final static String ERROR_WIFI_TIPS_TYPE = "WifiErrorTipsType"; //有线无线配网错误页面模式 + final static String ERROR_SOFTAP_TIPS_TYPE = "SoftAPErrorTipsType"; //软AP配网错误页面模式 + final static String ERROR_ACCESSORY_TIPS_TYPE = "AccessoryErrorTipsType"; //配件配网错误页面模式 + //有线无线 + final static String WIFI_MODE_GUIDING_LIGHT_IMAGE = "WifiModeGuidingLightImage"; + final static String WIFI_MODE_CONFIG_INTRODUCTION = "WifiModeConfigIntroduction"; + final static String WIFI_MODE_CONFIG_CONFIRM_INTRODUCTION = "WifiModeConfigConfirmIntroduction"; + final static String WIFI_MODE_RESET_GUIDE_INTRODUCTION = "WifiModeResetGuideIntroduction"; + final static String WIFI_MODE_RESET_IMAGE = "WifiModeResetImage"; + final static String WIFI_MODE_RESET_OPERATION_INTRODUCTION = "WifiModeResetOperationIntroduction"; + final static String WIFI_MODE_FINISH_DEVICE_IMAGE = "WifiModeFinishDeviceImage"; + //软AP + final static String SOFT_AP_MODE_WIFI_NAME = "SoftAPModeWifiName"; + final static String SOFT_AP_MODE_GUIDING_STEP_ONE_IMAGE = "SoftAPModeGuidingStepOneImage"; + final static String SOFT_AP_MODE_GUIDING_STEP_ONE_INTRODUCTION = "SoftAPModeGuidingStepOneIntroduction"; + final static String SOFT_AP_MODE_GUIDING_STEP_TWO_IMAGE = "SoftAPModeGuidingStepTwoImage"; + final static String SOFT_AP_MODE_GUIDING_STEP_TWO_INTRODUCTION = "SoftAPModeGuidingStepTwoIntroduction"; + final static String SOFT_AP_MODE_GUIDING_STEP_THREE_IMAGE = "SoftAPModeGuidingStepThreeImage"; + final static String SOFT_AP_MODE_GUIDING_STEP_THREE_INTRODUCTION = "SoftAPModeGuidingStepThreeIntroduction"; + final static String SOFT_AP_MODE_GUIDING_STEP_FOUR_IMAGE = "SoftAPModeGuidingStepFourImage"; + final static String SOFT_AP_MODE_GUIDING_STEP_FOUR_INTRODUCTION = "SoftAPModeGuidingStepFourIntroduction"; + final static String SOFT_AP_MODE_RESET_GUIDE_INTRODUCTION = "SoftAPModeResetGuideIntroduction"; + final static String SOFT_AP_MODE_RESET_IMAGE = "SoftAPModeResetImage"; + final static String SOFT_AP_MODE_RESET_OPERATION_INTRODUCTION = "SoftAPModeResetOperationIntroduction"; + final static String SOFT_AP_MODE_RESULT_PROMPT_IMAGE = "SoftAPModeResultPromptImage"; + final static String SOFT_AP_MODE_RESULT_INTRODUCTION = "SoftAPModeResultIntroduction"; + final static String SOFT_AP_MODE_CONFIRM_INTRODUCTION = "SoftAPModeConfirmIntroduction"; + final static String SOFT_AP_MODE_WIFI_VERSION = "SoftAPModeWifiVersion"; + //配件 + final static String ACCESSORY_MODE_PAIR_STATUS_IMAGE = "AccessoryModePairStatusImage"; + final static String ACCESSORY_MODE_PAIR_OPERATION_INTRODUCTION = "AccessoryModePairOperationIntroduction"; + final static String ACCESSORY_MODE_PAIR_CONFIRM_INTRODUCTION = "AccessoryModePairConfirmIntroduction"; + final static String ACCESSORY_MODE_RESET_GUIDE_INTRODUCTION = "AccessoryModeResetGuideIntroduction"; + final static String ACCESSORY_MODE_RESET_IMAGE = "AccessoryModeResetImage"; + final static String ACCESSORY_MODE_RESET_OPERATION_INTRODUCTION = "AccessoryModeResetOperationIntroduction"; + final static String ACCESSORY_MODE_FINISH_DEVICE_IMAGE = "AccessoryModeFinishDeviceImage"; + //Hub + final static String HUB_MODE_PAIR_STATUS_IMAGE = "HubModePairStatusImage"; + final static String HUB_MODE_PAIR_OPERATION_INTRODUCTION = "HubModePairOperationIntroduction"; + final static String HUB_MODE_RESET_GUIDE_INTRODUCTION = "HubModeResetGuideIntroduction"; + final static String HUB_MODE_RESET_IMAGE = "HubModeResetImage"; + final static String HUB_MODE_RESET_OPERATION_INTRODUCTION = "HubModeResetOperationIntroduction"; + final static String HUB_ACCESSORY_MODE_PAIR_STATUS_IMAGE = "HubAccessoryModePairStatusImage"; + final static String HUB_ACCESSORY_MODE_PAIR_OPERATION_INTRODUCTION = "HubAccessoryModePairOperationIntroduction"; + final static String HUB_ACCESSORY_MODE_RESET_GUIDE_INTRODUCTION = "HubAccessoryModeResetGuideIntroduction"; + final static String HUB_ACCESSORY_MODE_RESET_IMAGE = "HubAccessoryModeResetImage"; + final static String HUB_ACCESSORY_MODE_RESET_OPERATION_INTRODUCTION = "HubAccessoryModeResetOperationIntroduction"; + final static String HUB_MODE_RESULT_PROMPT_IMAGE = "HUBModeResultPromptImage"; + final static String HUB_MODE_RESULT_INTRODUCTION = "HUBModeResultIntroduction"; + final static String HUB_MODE_CONFIRM_INTRODUCTION = "HUBModeConfirmIntroduction"; + //设备本地配网 + final static String LOCATION_MODE_OPERATION_IMAGE = "LocationOperationImages"; //引导图 + final static String LOCATION_MODE_OPERATION_INTRODUCTION = "LocationOperationIntroduction"; //引导文案 + final static String LOCATION_MODE_FINISH_DEVICE_IMAGE = "LocationModeFinishDeviceImage"; //添加完成正视图 + // NB + final static String THIRD_PARTY_PLATFORM_MODE_GUIDING_LIGHT_IMAGE = "ThirdPartyPlatformModeGuidingLightImage"; //引导图 + final static String THIRD_PARTY_PLATFORM_MODE_RESULT_PROMPT_IMAGE = "ThirdPartyPlatformModeResultPromptImage"; + } + + public static void updateTile(TitleMode titleMode) { + Bundle bundle = new Bundle(); + bundle.putString(DeviceAddEvent.KEY.TITLE_MODE, titleMode.name()); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.TITLE_MODE_ACTION, bundle)); + } + + //判断设备是否需要初始化 + public static boolean isDeviceNeedInit(DEVICE_NET_INFO_EX device_net_info_ex) { + byte[] s = getByteArray(device_net_info_ex.byInitStatus); + // 设备初始化状态,按位确定初始化状态 + // bit0~1:0-老设备,没有初始化功能 1-未初始化帐号 2-已初始化帐户 + // bit2~3:0-老设备,保留 1-公网接入未使能 2-公网接入已使能 + // bit4~5:0-老设备,保留 1-手机直连未使能 2-手机直连使能 + if (s[s.length - 1] != 1) { + return false; + } else { + return true; + } + } + + //判断设备是否已经初始化 + public static boolean isDeviceInited(DEVICE_NET_INFO_EX device_net_info_ex) { + byte[] s = getByteArray(device_net_info_ex.byInitStatus); + // 设备初始化状态,按位确定初始化状态 + // bit0~1:0-老设备,没有初始化功能 1-未初始化帐号 2-已初始化帐户 + // bit2~3:0-老设备,保留 1-公网接入未使能 2-公网接入已使能 + // bit4~5:0-老设备,保留 1-手机直连未使能 2-手机直连使能 + if (s[s.length - 1] != 2) { + return false; + } else { + return true; + } + } + + //判断设备是否支持初始化,仅在软AP添加流程中使用(为了兼容K5不支持初始化,需要用默认用admin登录设备)。其余添加流程仅判断是否需要初始化即可,需要的弹框用户输入,不需要的跳过。 + public static boolean isDeviceSupportInit(DEVICE_NET_INFO_EX device_net_info_ex){ + byte[] s = getByteArray(device_net_info_ex.byInitStatus); + // 设备初始化状态,按位确定初始化状态 + // bit0~1:0-老设备,没有初始化功能 1-未初始化帐号 2-已初始化帐户 + // bit2~3:0-老设备,保留 1-公网接入未使能 2-公网接入已使能 + // bit4~5:0-老设备,保留 1-手机直连未使能 2-手机直连使能 + if (s[s.length - 2] != 1) { + return false; + } else { + return true; + } + } + + /** + * 获取配置,3代协议 + * + * @param loginHandle + * @param channelID + * @param strCommand + * @param BUFFERLEN + * @param stCfg + * @return + */ + public static boolean getNewDevConfig(long loginHandle, int channelID, String strCommand, int BUFFERLEN, CFG_NETAPP_WLAN stCfg, String requestId) { + boolean ret = false; + //netsdk 使用局限,只能使用 类对象传递参数。 + Integer error = new Integer(0); + char szBuffer[] = new char[BUFFERLEN]; + ret = INetSDK.GetNewDevConfig(loginHandle, strCommand, channelID, szBuffer, BUFFERLEN, error, 5 * 1000); + if (!ret) { + return false; + } + ret = INetSDK.ParseData(strCommand, szBuffer, stCfg, null); + if (!ret) { + return false; + } + return true; + } + + /** + * 判断是否是设备用户名或密码错误 + * + * @param error + */ + public static boolean isDevPwdError(int error) { + return (error == P2PErrorHelper.LOGIN_ERROR_KEY_OR_USER_MISMATCH + || error == P2PErrorHelper.LOGIN_ERROR_KEY_MISMATCH + || error == FinalVar.NET_LOGIN_ERROR_PASSWORD + || error == FinalVar.NET_USER_FLASEPWD + || error == FinalVar.NET_LOGIN_ERROR_USER_OR_PASSOWRD); + } + + public static byte[] getByteArray(byte b) { + byte[] array = new byte[8]; + for (int i = 7; i >= 0; i--) { + array[i] = (byte) (b & 1); + b = (byte) (b >> 1); + } + return array; + } + + /** + * 字符过滤 + * @param str + * @return + */ + public static String strDeviceNameFilter(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + StringBuilder builder = new StringBuilder(); + String strEx = "^[a-zA-Z0-9\\-\u4E00-\u9FA5\\_\\@\\s]+"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (temp.matches(strEx)) { + builder.append(temp); + } + } + return builder.toString(); + } + + /** + * 支持sc码添加 + * @param deviceAddInfo + * @return + */ + public static boolean isSupportAddBySc(DeviceAddInfo deviceAddInfo) { + if(deviceAddInfo == null) { + return false; + } + if(!TextUtils.isEmpty(deviceAddInfo.getSc()) && deviceAddInfo.getSc().length() == 8) { + return true; + } + if(deviceAddInfo.hasAbility(DeviceAbility.SCCode)) { + return true; + } + return false; + } + + /** + * 支持SC码的设备,使用SC码作为设备密码 + */ + public static void setDevicePwdBySc() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + deviceAddInfo.setDevicePwd(deviceAddInfo.getSc()); + } + } + + /** + * 支持2代声波 + * @param deviceAddInfo + * @return + */ + public static boolean isSupportSoundWaveV2(DeviceAddInfo deviceAddInfo) { + if(deviceAddInfo == null) { + return false; + } + return deviceAddInfo.getConfigMode() != null && deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWaveV2.name()); + } + + public static String getJsonString(DeviceAddInfo deviceAddInfo, boolean offlineConfigType) { + JSONObject result = new JSONObject(); + try { + result.put("SN", deviceAddInfo.getDeviceSn()); + if(offlineConfigType) { + result.put("deviceModelName", deviceAddInfo.getDeviceModel()); + } else { + result.put("SC", deviceAddInfo.getSc()); + } + result.put("imeiCode", deviceAddInfo.getImeiCode()); + } catch (JSONException e){ + e.printStackTrace(); + } + return result.toString(); + } + + // 打印错误码 + public static int printError() { + int error = (INetSDK.GetLastError() & 0x7fffffff); + LogUtil.debugLog("DeviceAddHelper", "error:" + error); + return error; + } + + + public interface BindNetworkListener{ + void onBindWifiListener(); + } + + /** + * 指定手机走wifi链路 + */ + public static void bindNetwork(final BindNetworkListener bindNetworkListener){ + final ConnectivityManager connectivityManager = (ConnectivityManager) + ProviderManager.getAppProvider().getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkRequest.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new NetworkRequest.Builder(); + //set the transport type do WIFI + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() { + + @TargetApi(Build.VERSION_CODES.M) + @Override + public void onAvailable(Network network) { + LogUtil.debugLog(LcnDeviceAddActivity.TAG, "bindNetwork succuss"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + connectivityManager.bindProcessToNetwork(null); + connectivityManager.bindProcessToNetwork(network); + } else { + //This method was deprecated in API level 23 + ConnectivityManager.setProcessDefaultNetwork(null); + ConnectivityManager.setProcessDefaultNetwork(network); + } + connectivityManager.unregisterNetworkCallback(this); + if(bindNetworkListener != null){ + bindNetworkListener.onBindWifiListener(); + } + } + }); + } + } + + /** + * 清除网络链路配置,注意软ap调用过{@link #bindNetwork},需要在合适的时机释放,否则无法连外网 + */ + public static void clearNetWork(){ + LogUtil.debugLog(LcnDeviceAddActivity.TAG, "clearNetWork succuss"); + final ConnectivityManager connectivityManager = (ConnectivityManager) + ProviderManager.getAppProvider().getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + connectivityManager.bindProcessToNetwork(null); + } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ + //This method was deprecated in API level 23 + ConnectivityManager.setProcessDefaultNetwork(null); + } + } + + /** + * 连接之前的wifi + * @return + */ + public static void connectPreviousWifi(){ + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String previousSsid = deviceAddInfo.getPreviousSsid(); + if(!TextUtils.isEmpty(previousSsid)) { + deviceAddInfo.setPreviousSsid(""); + DHWifiUtil wifiUtil = new DHWifiUtil(ProviderManager.getAppProvider().getAppContext()); + wifiUtil.connectWifi(previousSsid, ""); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddImageLoaderHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddImageLoaderHelper.java new file mode 100644 index 0000000..46a2269 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/DeviceAddImageLoaderHelper.java @@ -0,0 +1,27 @@ +package com.mm.android.deviceaddmodule.helper; + +import com.mm.android.deviceaddmodule.R; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; + +public class DeviceAddImageLoaderHelper { + public static DisplayImageOptions getCommonOptions() { + DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() + .cacheOnDisk(true) + .showImageForEmptyUri(R.drawable.adddevice_default) + .showImageOnFail(R.drawable.adddevice_default) + .considerExifParams(true).cacheOnDisk(true).cacheInMemory(true) + .imageScaleType(ImageScaleType.EXACTLY_STRETCHED).build(); + return displayImageOptions; + } + + public static DisplayImageOptions getCommonOptions4success() { + DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() + .cacheOnDisk(true) + .showImageForEmptyUri(R.drawable.adddevice_icon_success_default) + .showImageOnFail(R.drawable.adddevice_icon_success_default) + .considerExifParams(true).cacheOnDisk(true).cacheInMemory(true) + .imageScaleType(ImageScaleType.EXACTLY_STRETCHED).build(); + return displayImageOptions; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/MyURLSpan.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/MyURLSpan.java new file mode 100644 index 0000000..855bdc4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/MyURLSpan.java @@ -0,0 +1,28 @@ +package com.mm.android.deviceaddmodule.helper; + +import android.text.style.URLSpan; +import android.view.View; +import android.view.View.OnClickListener; + +/** + * 自定义加下划线及点击事件的文字相关功能类 + */ +class MyURLSpan extends URLSpan { + private OnClickListener mListener; + + public MyURLSpan(String url) { + super(url); + } + + public void setOnClickListener(OnClickListener listenr) { + // TODO Auto-generated method stub + mListener = listenr; + } + + @Override + public void onClick(View widget) { + if (mListener != null) { + mListener.onClick(widget); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/PageNavigationHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/PageNavigationHelper.java new file mode 100644 index 0000000..edf0f0d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/PageNavigationHelper.java @@ -0,0 +1,842 @@ +package com.mm.android.deviceaddmodule.helper; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.p_ap.ApBindSuccessFragment; +import com.mm.android.deviceaddmodule.p_ap.ApPairFragment; +import com.mm.android.deviceaddmodule.p_ap.GatewayListFragment; +import com.mm.android.deviceaddmodule.p_ap.TipApLightFragment; +import com.mm.android.deviceaddmodule.p_ap.TipApPowerFragment; +import com.mm.android.deviceaddmodule.p_ap.hubap.HubapGuide1Fragment; +import com.mm.android.deviceaddmodule.p_ap.hubap.HubapGuide2Fragment; +import com.mm.android.deviceaddmodule.p_ap.hubap.HubapGuide3Fragment; +import com.mm.android.deviceaddmodule.p_bindsuccess.BindSuccessFragment; +import com.mm.android.deviceaddmodule.p_cloudconnect.CloudConnectFragment; +import com.mm.android.deviceaddmodule.p_devicelocal.TipDeviceLocalFragment; +import com.mm.android.deviceaddmodule.p_devlogin.DevLoginFragment; +import com.mm.android.deviceaddmodule.p_devlogin.DevSecCodeFragment; +import com.mm.android.deviceaddmodule.p_errortip.ErrorTipFragment; +import com.mm.android.deviceaddmodule.p_init.InitFragment; +import com.mm.android.deviceaddmodule.p_init.SecurityCheckFragment; +import com.mm.android.deviceaddmodule.p_inputsn.DeviceDispatchFragment; +import com.mm.android.deviceaddmodule.p_inputsn.IMEIInputFragment; +import com.mm.android.deviceaddmodule.p_inputsn.ManualInputFragment; +import com.mm.android.deviceaddmodule.p_inputsn.ScanFragment; +import com.mm.android.deviceaddmodule.p_nb.TipNBFragment; +import com.mm.android.deviceaddmodule.p_offlineconfig.OfflineConfigFragment; +import com.mm.android.deviceaddmodule.p_softap.DevWifiListFragment; +import com.mm.android.deviceaddmodule.p_softap.HiddenWifiPwdFragment; +import com.mm.android.deviceaddmodule.p_softap.SoftApWifiPwdFragment; +import com.mm.android.deviceaddmodule.p_softap.TipSoftApConnectWifiFragment; +import com.mm.android.deviceaddmodule.p_softap.TipSoftApStep1Fragment; +import com.mm.android.deviceaddmodule.p_softap.TipSoftApStep2Fragment; +import com.mm.android.deviceaddmodule.p_softap.TipSoftApStep3Fragment; +import com.mm.android.deviceaddmodule.p_softap.TipSoftApStep4Fragment; +import com.mm.android.deviceaddmodule.p_softap.oversea.SoftApResultFragment; +import com.mm.android.deviceaddmodule.p_typechoose.TypeChooseFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.SmartConfigFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipLightFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipNetCablePluginFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipPowerFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipSameNetworkFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipSoundFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.TipWifiConnectFragment; +import com.mm.android.deviceaddmodule.p_wiredwireless.WifiPwdFragment; + +/** + * 设备添加页面跳转帮助类 + **/ +public class PageNavigationHelper { + public static final String TIP_POWER_FRAGMENT_TAG = "tip_power_fragment"; + public static final String WIFI_PWD_TAG = "wifi_pwd_fragment"; + public static final String SOFT_AP_TIP_TAG = "soft_ap_tip_fragment"; + public static final String AP_TIP_TAG = "ap_tip_fragment"; + public static final String SECURITY_CHECK_TAG = "security_check_fragment"; + + private static void setFragmentAnimations(FragmentTransaction transaction, boolean anim) { + if (anim) { + transaction.setCustomAnimations(R.anim.slide_in_right, + R.anim.slide_out_left, + R.anim.slide_left_back_in, + R.anim.slide_right_back_out); + } + } + + private static void setFragmentAnimations(FragmentTransaction transaction) { + setFragmentAnimations(transaction, true); + } + + /** + * 跳转至二维码扫描页 + * + * @param fragmentActivity + */ + public static void gotoScanPage(FragmentActivity fragmentActivity) { + if (fragmentActivity == null || fragmentActivity.getSupportFragmentManager() == null) { + return; + } + ScanFragment fragment = ScanFragment.newInstance(); + FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.content, fragment); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至二维码扫描页 + * + * @param fragmentActivity + */ + public static void gotoDispatchPage(FragmentActivity fragmentActivity) { + if (fragmentActivity == null || fragmentActivity.getSupportFragmentManager() == null) { + return; + } + DeviceDispatchFragment fragment = DeviceDispatchFragment.newInstance(); + FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.content, fragment); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至手动输入序列号页 + * + * @param from + */ + public static void gotoManualInputPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + ManualInputFragment fragment = ManualInputFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至输入imei页 + * + * @param from + */ + public static void gotoIMEIInputPage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + IMEIInputFragment fragment = IMEIInputFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoIMEIInputPage(Fragment from) { + gotoIMEIInputPage(from, true); + } + + /** + * 跳转至设备类型选择页 + * + * @param from + */ + public static void gotoTypeChoosePage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TypeChooseFragment fragment = TypeChooseFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoTypeChoosePage(Fragment from) { + gotoTypeChoosePage(from, true); + } + + /** + * 跳转至电源提示页 + * + * @param from + * @param isWirelessConfig + */ + public static void gotoPowerTipPageNoAnim(Fragment from, boolean isWirelessConfig) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipPowerFragment fragment = TipPowerFragment.newInstance(isWirelessConfig); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(TIP_POWER_FRAGMENT_TAG); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至电源提示页 + * + * @param from + * @param isWirelessConfig + */ + public static void gotoPowerTipPage(Fragment from, boolean isWirelessConfig) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipPowerFragment fragment = TipPowerFragment.newInstance(isWirelessConfig); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(TIP_POWER_FRAGMENT_TAG); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至网线提示页 + * + * @param from + */ + public static void gotoNetCableTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipNetCablePluginFragment fragment = TipNetCablePluginFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至同一网络提示页 + * + * @param from + */ + public static void gotoSameNetworkTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSameNetworkFragment fragment = TipSameNetworkFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至wifi连接提示页 + * + * @param from + */ + public static void gotoWifiConnectTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipWifiConnectFragment fragment = TipWifiConnectFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转至wifi密码输入页 + * + * @param parent 父fragment + * @param from + */ + public static void gotoWifiPwdPage(Fragment parent, Fragment from) { + if (parent == null || parent.getFragmentManager() == null) { + return; + } + WifiPwdFragment fragment = WifiPwdFragment.newInstance(); + FragmentTransaction transaction = parent.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + + transaction.addToBackStack(WIFI_PWD_TAG); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转设备灯光提示页 + * + * @param from + */ + public static void gotoLightTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipLightFragment fragment = TipLightFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转设备声音提示页 + * + * @param from + */ + public static void gotoSoundTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoundFragment fragment = TipSoundFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转设备声音提示页 + * + * @param from + */ + public static void gotoSmartConfigPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + SmartConfigFragment fragment = SmartConfigFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + + /** + * 跳转到安全检查页 + * + * @param from + */ + public static void gotoSecurityCheckPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + SecurityCheckFragment fragment = SecurityCheckFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(SECURITY_CHECK_TAG); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到设备初始化页 + * + * @param from + */ + public static void gotoInitPage(Fragment from, DEVICE_NET_INFO_EX device_net_info_ex) { + if (from == null || from.getFragmentManager() == null) { + return; + } + InitFragment fragment = InitFragment.newInstance(device_net_info_ex); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到云平台连接页 + * + * @param from + */ + public static void gotoCloudConnectPage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + CloudConnectFragment fragment = CloudConnectFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + } + + public static void gotoCloudConnectPage(Fragment from) { + gotoCloudConnectPage(from, true); + } + + /** + * 跳转到设备登录页 + * + * @param from + */ + public static void gotoDevLoginPage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + DevLoginFragment fragment = DevLoginFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + //离线进入的都认为走过初始化检查流程了,都默认上报 + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + } + + public static void gotoDevLoginPage(Fragment from) { + gotoDevLoginPage(from, true); + } + + /** + * 跳转到设备安全码验证页 + * + * @param from + */ + public static void gotoDevSecCodePage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + DevSecCodeFragment fragment = DevSecCodeFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoDevSecCodePage(Fragment from) { + gotoDevSecCodePage(from, true); + } + + /** + * 跳转到绑定设备连接页 + * + * @param from + */ + public static void gotoDeviceBindPage(Fragment from, boolean anim) { + if (from == null || from.getFragmentManager() == null) { + return; + } + CloudConnectFragment fragment = CloudConnectFragment.newInstance(true); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoDeviceBindPage(Fragment from) { + gotoDeviceBindPage(from, true); + } + + /** + * 跳转到绑定成功提示页 + * + * @param from + */ + public static void gotoBindSuccessPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + BindSuccessFragment fragment = BindSuccessFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + } + + /** + * @param from + */ + public static void gotoErrorTipPage(Fragment from, int errorCode, boolean anim) { + ErrorTipFragment fragment = ErrorTipFragment.newInstance(errorCode); + if (from == null || from.getFragmentManager() == null) { + return; + } + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction, anim); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoErrorTipPage(Fragment from, int errorCode) { + gotoErrorTipPage(from, errorCode, true); + } + + /** + * 跳转到到软Ap添加引导页 + * + * @param from + */ + public static void gotoSoftApTipPage(Fragment from) { + gotoSoftApTip1Page(from); + } + + public static void gotoSoftApTip1Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApStep1Fragment fragment = TipSoftApStep1Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(SOFT_AP_TIP_TAG); + transaction.commitAllowingStateLoss(); + + } + + public static void gotoSoftApTipPageNoAnim(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApStep1Fragment fragment = TipSoftApStep1Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + transaction.replace(R.id.content, fragment, TipSoftApStep1Fragment.class.getName()); + transaction.addToBackStack(SOFT_AP_TIP_TAG); + transaction.commitAllowingStateLoss(); + + } + + public static void gotoSoftApTip2Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApStep2Fragment fragment = TipSoftApStep2Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + + } + + public static void gotoSoftApTip3Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApStep3Fragment fragment = TipSoftApStep3Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + + } + + public static void gotoSoftApTip4Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApStep4Fragment fragment = TipSoftApStep4Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + public static void gotoSoftApTipConnectWifiPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipSoftApConnectWifiFragment fragment = TipSoftApConnectWifiFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到软Ap添加wifi列表 + * + * @param from + */ + public static void gotoSoftApWifiListPage(Fragment from, boolean isNotNeedLogin) { + if (from == null || from.getFragmentManager() == null) { + return; + } + + DevWifiListFragment fragment = DevWifiListFragment.newInstance(isNotNeedLogin); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到软Ap添加wifi列表 + * + * @param from + */ + public static void gotoSoftApWifiListPage(Fragment from) { + gotoSoftApWifiListPage(from, false); + } + + /** + * 跳转到到软Ap添加wifi密码输入页 + * + * @param from + */ + public static void gotoSoftApWifiPwdPage(Fragment from, WlanInfo wlanInfo, boolean isNotNeedLogin) { + if (from == null || from.getFragmentManager() == null) { + return; + } + SoftApWifiPwdFragment fragment = SoftApWifiPwdFragment.newInstance(wlanInfo, isNotNeedLogin); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到软Ap添加wifi密码输入页 + * + * @param from + */ + public static void gotoHiddenWifiPwdPage(Fragment from, boolean isNotNeedLogin) { + if (from == null || from.getFragmentManager() == null) { + return; + } + HiddenWifiPwdFragment fragment = HiddenWifiPwdFragment.newInstance(isNotNeedLogin); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到软Ap添加wifi连接结果页(海外) + * + * @param from + */ + public static void gotoSoftApResultdPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + SoftApResultFragment fragment = SoftApResultFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到配件添加网关列表页 + * + * @param from + */ + public static void gotoGatewayListPage(Fragment from, boolean hasSelectGateway) { + if (from == null || from.getFragmentManager() == null) { + return; + } + GatewayListFragment fragment = GatewayListFragment.newInstance(hasSelectGateway); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到配件电源引导页 + * + * @param from + */ + public static void gotoApPowerTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipApPowerFragment fragment = TipApPowerFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(AP_TIP_TAG); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到配件电源引导页 + * + * @param from + */ + public static void gotoApLightPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipApLightFragment fragment = TipApLightFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到配件配对页 + * + * @param from + */ + public static void gotoApPairPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + ApPairFragment fragment = ApPairFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到到配件绑定成功页 + * + * @param from + */ + public static void gotoApBindSuccessPage(Fragment from, AddApResult addApResult) { + if (from == null || from.getFragmentManager() == null) { + return; + } + ApBindSuccessFragment fragment = ApBindSuccessFragment.newInstance(addApResult); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到电池相机配对引导页 + * + * @param fragmentActivity + */ + public static void gotoHubGuide1Page(FragmentActivity fragmentActivity, String sn, String hubType) { + if (fragmentActivity == null || fragmentActivity.getSupportFragmentManager() == null) { + return; + } + HubapGuide1Fragment fragment = HubapGuide1Fragment.newInstance(sn, hubType); + FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.content, fragment); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到电池相机配对引导页 + * + * @param from + */ + public static void gotoHubGuide2Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + HubapGuide2Fragment fragment = HubapGuide2Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到hub灯提示页 + * + * @param from + */ + public static void gotoHubGuide3Page(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + HubapGuide3Fragment fragment = HubapGuide3Fragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到NB设备添加引导页 + * + * @param from + */ + public static void gotoNBTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipNBFragment fragment = TipNBFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到离线配网 + * + * @param fragmentActivity + * @param sn + * @param devModelName + */ + public static void gotoOfflineConfigPage(FragmentActivity fragmentActivity, String sn, String devModelName, String imei) { + if (fragmentActivity == null || fragmentActivity.getSupportFragmentManager() == null) { + return; + } + OfflineConfigFragment fragment = OfflineConfigFragment.newInstance(sn, devModelName, imei); + FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.content, fragment); + transaction.commitAllowingStateLoss(); + } + + public static void gotoDeviceSharePage(FragmentActivity fragmentActivity, String deviceSn) { + Bundle bundle = new Bundle(); + bundle.putString(LCConfiguration.Device_ID, deviceSn); + ProviderManager.getAppProvider().goDeviceSharePage(fragmentActivity, bundle); + } + + /** + * 跳转到设备本地配网引导页面 + * + * @param from + */ + public static void gotoLocationTipPage(Fragment from) { + if (from == null || from.getFragmentManager() == null) { + return; + } + TipDeviceLocalFragment fragment = TipDeviceLocalFragment.newInstance(); + FragmentTransaction transaction = from.getFragmentManager().beginTransaction(); + setFragmentAnimations(transaction); + transaction.replace(R.id.content, fragment); + transaction.addToBackStack(null); + transaction.commitAllowingStateLoss(); + } + + /** + * 跳转到蓝牙模块 + */ + public static void gotoAddBleLockPage(Bundle bundle) { + //TODO 不会有逻辑进入 + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/Utils4AddDevice.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/Utils4AddDevice.java new file mode 100644 index 0000000..437c1e6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/helper/Utils4AddDevice.java @@ -0,0 +1,376 @@ +package com.mm.android.deviceaddmodule.helper; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.support.v4.app.Fragment; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.View.OnClickListener; +import android.widget.TextView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.nostra13.universalimageloader.core.DisplayImageOptions; + +import java.util.Hashtable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 设备添加相关工具类 + * + */ +public class Utils4AddDevice { + public static final int NETWORK_NONE = -1; // 无网络 + public static final int NETWORK_WIFI = 0; // wifi + public static final int NETWORK_MOBILE = 1; // 数据网络 + + public static String strRegCodeFilter(String str) { + + if (TextUtils.isEmpty(str)) { + return str; + } + String strEx = "[0-9A-Za-z]"; + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (!temp.matches(strEx)) { + str = str.replace(temp, ""); + return strRegCodeFilter(str); + } + } + return str; + } + + public static String wifiPwdFilter(String str) { + + if (TextUtils.isEmpty(str)) { + return str; + } + // TD:20780 + String chinese1 = "[\u2E80-\uA4CF]"; + String chinese2 = "[\uF900-\uFAFF]"; + String chinese3 = "[\uFE30-\uFE4F]"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (temp.matches(chinese1) || temp.matches(chinese2) || temp.matches(chinese3)) { + str = str.replace(temp, ""); + return wifiPwdFilter(str); + } + } + return str; + } + + public static boolean isNetworkAvailable(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); // 获取系统网络连接管理�? + if (connectivity == null) { // 如果网络管理器为null + return false; // 返回false表明网络无法连接 + } else { + NetworkInfo[] info = connectivity.getAllNetworkInfo(); // 获取�?��的网络连接对�? + if (info != null) { // 网络信息不为null + for (NetworkInfo anInfo : info) { // 遍历网路连接对象 + if (anInfo.isConnected()) { // 当有�?��网络连接对象连接上网络时 + return true; // 返回true表明网络连接正常 + } + } + } + } + return false; + } + + public static boolean isWifi(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity == null) { + return false; + } else { + NetworkInfo curNetwork = connectivity.getActiveNetworkInfo(); + if (curNetwork != null && curNetwork.getType() == ConnectivityManager.TYPE_WIFI) { + return true; + } + } + return false; + } + + public static int getNetWorkState(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if(connectivity != null) { + NetworkInfo curNetwork = connectivity.getActiveNetworkInfo(); + if (curNetwork != null && curNetwork.isConnected()) { + if (curNetwork.getType() == ConnectivityManager.TYPE_WIFI) { + return NETWORK_WIFI; + } else if (curNetwork.getType() == ConnectivityManager.TYPE_MOBILE) { + return NETWORK_MOBILE; + } + } + } + return NETWORK_NONE; + } + + public static boolean isWifiEnabled(Context context) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + boolean wifi= (wifiInfo.getSSID()==null) || wifiInfo.getSSID().equalsIgnoreCase(""); + return !wifi; + } + + public static boolean isWifiConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (mConnectivityManager == null){ + return false; + } + NetworkInfo mWiFiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (mWiFiNetworkInfo != null) { + return mWiFiNetworkInfo.isAvailable(); + } + } + return false; + } + /** + * 判断是否只包含数字或大小写字母 + * + * @param str + * @return + */ + public static boolean checkString(String str) { + String regEx = "[0-9A-Za-z]*"; // 只能是数字以及个别字符 + Pattern p = Pattern.compile(regEx); + Matcher m = p.matcher(str); + if (m.matches()) { + return true; + } else { + return false; + } + } + + public static String filterInvalidString(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + String numberAndAbc = "[a-zA-Z0-9]"; + StringBuilder buffer = new StringBuilder(); + int len = str.length(); + for (int i = 0; i < len; ++i) { + String temp = str.substring(i, i + 1); + if (temp.matches(numberAndAbc)) { + buffer.append(temp); + } + } + return buffer.toString(); + } + + public static String filterInvalidString4Type(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + String numberAndAbc = "[a-zA-Z0-9-/\\\\]"; + StringBuilder buffer = new StringBuilder(); + int len = str.length(); + for (int i = 0; i < len; ++i) { + String temp = str.substring(i, i + 1); + if (temp.matches(numberAndAbc)) { + buffer.append(temp); + } + } + return buffer.toString(); + } + + /** + * 是否是乐盒设备 + * + * @param deviceMode + * @return + */ + public static boolean isDeviceTypeBox(String deviceMode) { + if (deviceMode == null || TextUtils.isEmpty(deviceMode)) { + return false; + } + if (deviceMode.equalsIgnoreCase("G10")) { + return true; + } else { + return false; + } + } + + /** + * 设置下划线字体 + */ + public static SpannableString setSpannableString(Context context, int showResId, int showUnderLineResId) { + + String showResourceTip = context.getResources().getString(showResId); + String showUnderLineResTip = context.getResources().getString(showUnderLineResId); + String tip = showResourceTip + showUnderLineResTip; + SpannableString ss = new SpannableString(tip); + int start = showResourceTip.length(); + int end = showUnderLineResTip.length() + start; + int flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; + MyURLSpan mus = new MyURLSpan(context.getResources().getString(R.string.assetfont_html));// 字体 + ForegroundColorSpan fcs = new ForegroundColorSpan(context.getResources() + .getColor(R.color.lc_color_4ea7f2)); + ss.setSpan(mus, start, end, flag); + ss.setSpan(fcs, start, end, flag); + return ss; + } + + /** + *

+ * 设置下划线字体及点击事件 + *

+ */ + public static void setSpannableString(int showResId, int showUnderLineResId, OnClickListener listener, TextView view) { + String showResourceTip = ""; + if (showResId != 0) { + showResourceTip = view.getContext().getResources().getString(showResId); + } + String showUnderLineResTip = view.getContext().getResources().getString(showUnderLineResId); + String tip = showResourceTip + showUnderLineResTip; + SpannableString ss = new SpannableString(tip); + int start = showResourceTip.length(); + int end = showUnderLineResTip.length() + start; + int flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; + MyURLSpan mus = new MyURLSpan(view.getContext().getResources().getString(R.string.assetfont_html));// 字体 + mus.setOnClickListener(listener); + ForegroundColorSpan fcs = new ForegroundColorSpan(view.getContext().getResources() + .getColor(R.color.lc_color_4ea7f2)); + ss.setSpan(mus, start, end, flag); + ss.setSpan(fcs, start, end, flag); + view.setText(ss); + view.setMovementMethod(LinkMovementMethod.getInstance()); + } + + /** + *

+ * 设置下划线字体及点击事件 + *

+ */ + public static void setSpannableString(int showResId, String showUnderLineResTip, OnClickListener listener, TextView view) { + String showResourceTip = ""; + if (showResId != 0) { + showResourceTip = view.getContext().getResources().getString(showResId); + } + if (showUnderLineResTip == null) { + showUnderLineResTip = ""; + } + String tip = showResourceTip + showUnderLineResTip; + SpannableString ss = new SpannableString(tip); + int start = showResourceTip.length(); + int end = showUnderLineResTip.length() + start; + int flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; + MyURLSpan mus = new MyURLSpan(view.getContext().getResources().getString(R.string.assetfont_html));// 字体 + mus.setOnClickListener(listener); + ForegroundColorSpan fcs = new ForegroundColorSpan(view.getContext().getResources() + .getColor(R.color.lc_color_4ea7f2)); + ss.setSpan(mus, start, end, flag); + ss.setSpan(fcs, start, end, flag); + view.setText(ss); + view.setMovementMethod(LinkMovementMethod.getInstance()); + } + + private static DisplayImageOptions mDeviceModeImageOptions; + + + /** + * 是否为TP1等设备,包括TP1 TC1 TK1 TC3 TK3 TC4 TC5 TC5S TP6、TP6C、TC6、TC6C、TP7 + */ + public static boolean isTp1And(String deviceModelName) { + return LCConfiguration.TYPE_TC1.equals(deviceModelName) || LCConfiguration.TYPE_TK1.equals(deviceModelName) + || LCConfiguration.TYPE_TC3.equals(deviceModelName) || LCConfiguration.TYPE_TK3.equals(deviceModelName) + || LCConfiguration.TYPE_TC4.equals(deviceModelName) || LCConfiguration.TYPE_TC5.equals(deviceModelName) + || LCConfiguration.TYPE_TC5S.equals(deviceModelName) || LCConfiguration.TYPE_TP1.equals(deviceModelName) + || LCConfiguration.TYPE_TP6.equals(deviceModelName) || LCConfiguration.TYPE_TP6C.equals(deviceModelName) + || LCConfiguration.TYPE_TC6.equals(deviceModelName) || LCConfiguration.TYPE_TC6C.equals(deviceModelName) + || LCConfiguration.TYPE_TP7.equals(deviceModelName); + } + + + //根据域名获取 + public static String getAddDeviceHelpUrl(String host) { + if (host.contains(":443")) { + host = host.split(":")[0]; + } + return "http://" + host + "/bindhelp.html"; + } + + + /** + *  * 检测设备新老版本, ture 表示新版本并且DHCP打开走单播流程, false 老版本/DHCP关闭走组播加单播流程。 + *  * @return + *   + */ + public static boolean checkDeviceVersion(DEVICE_NET_INFO_EX deviceInfo) { + if(deviceInfo==null) + return false; + int flag = (deviceInfo.bySpecialAbility >> 2) & 0x03; + return 0x00 != flag && 0x03 != flag; + } + + + /** + *  * 检测设备获取的IP是否有效, ture 有效 + *  * @param deviceInfo + *  * @return + *   + */ + public static boolean checkEffectiveIP(DEVICE_NET_INFO_EX deviceInfo) { + if(deviceInfo==null) + return false; + int flag = (deviceInfo.bySpecialAbility >> 2) & 0x03; + return 0x02 == flag; + } + + /** + * 生成二维码 + * @param url + * @param width + * @param height + * @return + */ + public static Bitmap creatQRImage(String url, final int width, final int height) { + try { + if(TextUtils.isEmpty(url)) { + return null; + } + Hashtable hints = new Hashtable<>(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + hints.put(EncodeHintType.MARGIN, "0"); // 不要边距 + // 图像数据变换,使用矩阵转换 + BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints); + int[] pixels = new int[width * height]; + // 下面这里按照二维码的算法,逐个生成二维码的图片 + // 两个for循环是图片横列扫描的结果 + for(int y = 0; y < height; y++) { + for(int x = 0; x mHandler; + + public BusinessRunnable(Handler handle) { + mHandler = new WeakReference<>(handle); + Handler handler = getHander(); + if (handler != null && handler instanceof DHBaseHandler) { + ((DHBaseHandler) handler).onStart(); + } + ThreadPool.submit(this); + } + + public Handler getHander() { + return mHandler.get(); + } + + @Override + public void run() { + try { + doBusiness(); + } catch (BusinessException e) { + Handler handler = getHander(); + LogUtil.debugLog("BusinessRunnable", "hander == null ? " + (handler == null)); + if (handler != null) { + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION, + e.errorCode, e.errorCode, e).sendToTarget(); + + } + + } catch (Exception e) { + LogUtil.debugLog("HsviewResponse Exception", e.getMessage()); + Handler handler = getHander(); + if (handler != null) { + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION, + BusinessErrorCode.BEC_COMMON_UNKNOWN, + BusinessErrorCode.BEC_COMMON_UNKNOWN,new BusinessException(e)).sendToTarget(); + } + } + } + + public abstract void doBusiness() throws BusinessException; +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/Callback.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/Callback.java new file mode 100644 index 0000000..b89a636 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/Callback.java @@ -0,0 +1,8 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +public interface Callback { + + public void onSuccess(T t); + + public void onFail(String code, String message); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DHBaseHandler.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DHBaseHandler.java new file mode 100644 index 0000000..1ddea23 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DHBaseHandler.java @@ -0,0 +1,32 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.os.Message; + +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.base.mvp.IBaseView; + +import java.lang.ref.WeakReference; + +public abstract class DHBaseHandler extends LCBusinessHandler { + + WeakReference mView; + public DHBaseHandler(WeakReference view){ + super(); + mView=view; + } + public abstract void onStart(); + protected abstract void onCompleted(); + protected abstract void handleBusinessFinally(Message msg); + + @Override + public void handleBusiness(Message msg) { + if(mView==null + || mView.get()==null + ||!mView.get().isViewActive()){ + return; + } + onCompleted(); + handleBusinessFinally(msg); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceAddCustomImpl.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceAddCustomImpl.java new file mode 100644 index 0000000..4ae8672 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceAddCustomImpl.java @@ -0,0 +1,47 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.app.Activity; +import android.content.Context; + +import com.mm.android.deviceaddmodule.helper.ActivityHelper; +import com.mm.android.deviceaddmodule.utils.SDsolutionUtility; + + +public class DeviceAddCustomImpl implements IDeviceAddCustom { + + private volatile static DeviceAddCustomImpl deviceAddCustom; + + public static DeviceAddCustomImpl newInstance() { + if (deviceAddCustom == null) { + synchronized (DeviceAddCustomImpl.class) { + if (deviceAddCustom == null) { + deviceAddCustom = new DeviceAddCustomImpl(); + } + } + } + return deviceAddCustom; + } + + @Override + public void goFAQWebview(Context context) { + + } + + @Override + public void goHomePage(Context context) { + Activity activity=ActivityHelper.getCurrentActivity(); + if (activity!=null){ + activity.finish(); + } + } + + @Override + public String getDevAddCachePath() { + return SDsolutionUtility.getCachePath(); + } + + @Override + public void uninit() { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceHelper.java new file mode 100644 index 0000000..cedd875 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/DeviceHelper.java @@ -0,0 +1,12 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.text.TextUtils; + +/** + * 设备模块帮助类 + **/ +public class DeviceHelper { + public static boolean isH1G(String deviceModelName){ + return !TextUtils.isEmpty(deviceModelName) && "H1G".equalsIgnoreCase(deviceModelName); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/EnvironmentConfig.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/EnvironmentConfig.java new file mode 100644 index 0000000..56dc632 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/EnvironmentConfig.java @@ -0,0 +1,265 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.app.Application; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; + +import java.io.File; + +/** + * 业务必要属性 + * + * App配置文件必须要配置的 推送ID + * {@code meta_data4project} App配置文件必须要配置的 项目名称 {@code meta_data4Type} + * App配置文件必须要配置的 协议发起方 + */ +public final class EnvironmentConfig { + public static final String meta_data4Type = "meta-data4type"; + public static final String meta_data4AppId = "meta-data4appid"; + public static final String meta_isHttps = "meta-ishttps"; + + /** + * 1.clientType:客户端类型(必填),"phone"-手机,"web"-浏览器,"box"-盒子。 + * {@link } 环境配置属性。 + */ + private String clientType; + + /** + * 2.clientMac:客户端MAC地址(必填),用于唯一标识这个客户端。 + */ + private String clientMac; + + /** + * 服务端地址 + */ + private String host; + + /** + * 是否是走https协议 + */ + private boolean isHttps; + + /** + * 缓存文件名 + */ + private String userAgent = "volley/0"; + + /** + * 缓存路径 + */ + private File cacheDir; + + /** + * 应用ID + */ + private String appId; + + /** + * Application + */ + private Context application; + + /** + * 版本名 + */ + private String versionName; + + private String language = null; + + public static Context mContext;// applicationContext + + public EnvironmentConfig(Builder b) { + this.clientMac = b.clientMac; + this.clientType = b.clientType; + userAgent = b.userAgent; + cacheDir = b.cacheDir; + appId = b.appId; + host = b.host; + this.isHttps = b.isHttps; + application = b.applicationContext; + versionName = b.versionName; + language = b.language; + } + + public String getHost() { + return host; + } + + public String getClientType() { + return clientType; + } + + public void setHost(String host) { + this.host = host; + } + + public String getClientMacAddress() { + return clientMac; + } + + public Context getContext() { + return application; + } + + public String getVersionName() { + return versionName; + } + + public String getLanguage() { + return language; + } + + public static class Builder { + private String clientType; + private String clientMac; + private String project; + private String userAgent; + private File cacheDir; + private String appId; + private String host; + private boolean isHttps; + private Context applicationContext; + private String versionName; + private String language = null; + + public Builder setContext(Context context) throws Exception { + if (!(context instanceof Application)) { + throw new Exception("context must instance application"); + } + applicationContext = context; + mContext = applicationContext.getApplicationContext(); + return this; + } + + public Builder setClientType(String clientType) { + this.clientType = clientType; + return this; + } + + private void setVersionName(Context context) { + PackageManager pm = context.getPackageManager(); + PackageInfo pi = null; + try { + pi = pm.getPackageInfo(context.getPackageName(), 0); + versionName = pi.versionName; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + } + + private void setClientMac(Context context) { + try { + // FIXME:Mac地址可能为空 IMEI 未识别信息,如果未发现,则功能不正常使用 + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + String imei = telephonyManager.getDeviceId(); + LogUtil.debugLog("lechange", "imei : " + imei); + if (imei == null) { + WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiInfo info = (null == wifiMgr ? null : wifiMgr.getConnectionInfo()); + String mac = info != null ? info.getMacAddress() : ""; + LogUtil.debugLog("lechange", "mac : " + mac); + if (mac != null) { + mac = mac.replace(":", ""); + } else { + mac = ""; + } + clientMac = mac; + } else { + clientMac = imei; + } + LogUtil.debugLog("lechange", "clientMac : " + clientMac); + } catch (Exception e) { + clientMac = ""; + } + } + + public Builder setProject(String project) { + this.project = project; + return this; + } + + private void setCacheFile(Context context) { + cacheDir = context.getCacheDir(); + userAgent = "volley/0"; + try { + String packageName = context.getPackageName(); + PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + userAgent = packageName + "/" + info.versionCode; + } catch (NameNotFoundException e) { + + } + } + + public Builder setHost(String host) { + this.host = host; + String historyHost = PreferencesHelper.getInstance(applicationContext).getString(PreferencesConfig.HOST_HELP); + if (!TextUtils.isEmpty(historyHost)) {// 如果历史记录Host 不是nil + // 则设置历史Host,用于测试服务器 + this.host = historyHost; + } + return this; + } + + private void setDefaultHost(String host) { + this.host = host; + String historyHost = PreferencesHelper.getInstance(applicationContext).getString(PreferencesConfig.HOST_HELP); + if (!TextUtils.isEmpty(historyHost)) {// 如果历史记录Host 不是nil + // 则设置历史Host,用于测试服务器 + this.host = historyHost; + } + } + + public Builder setLanguage(String language) { + this.language = language; + return this; + } + + private void setLanguage(Context context) { + this.language = context.getResources().getConfiguration().locale.getLanguage(); + } + + public EnvironmentConfig build() { + + if (versionName == null || versionName.equals("")) { + setVersionName(applicationContext); + } + + if (cacheDir == null) { + setCacheFile(applicationContext); + } + + if (clientMac == null || clientMac.equals("")) { + setClientMac(applicationContext); + } + + if (language == null || language.equals("")) { + setLanguage(applicationContext); + } + + try { + ApplicationInfo appInfo = applicationContext.getPackageManager().getApplicationInfo(applicationContext.getPackageName(), PackageManager.GET_META_DATA); + + if (clientType == null || clientType.equals("")) { + clientType = appInfo.metaData.getString(meta_data4Type); + } + + isHttps = appInfo.metaData.getBoolean(meta_isHttps); + + } catch (NameNotFoundException e) { + + e.printStackTrace(); + } + return new EnvironmentConfig(this); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IApp.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IApp.java new file mode 100644 index 0000000..6070b5e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IApp.java @@ -0,0 +1,30 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.mobilecommon.base.IBaseProvider; + +/** + * App通用接口类 + */ + +public interface IApp extends IBaseProvider { + /*设备App使用类型,0表示国内,1表示海外*/ + public void setAppType(int type); + + public int getAppType(); //APP类型(0:乐橙/1:Easy4ip) + + public Context getAppContext(); //获取App上下文 + + + public void goDeviceSharePage(Activity activity , Bundle bundle); //进入设备分享页 + + void goBuyCloudPage(Activity activity , Bundle bundle); + + //跳转修改设备密码引导页 + void goModifyDevicePwdGuidePage(Activity activity); + + String getAppLanguage(); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAdd.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAdd.java new file mode 100644 index 0000000..8b4dfb6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAdd.java @@ -0,0 +1,12 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseHandler; +import com.mm.android.deviceaddmodule.mobilecommon.base.IBaseProvider; + +/** + * 设备添加对外接口,外部模块可调用的功能 + */ +public interface IDeviceAdd extends IBaseProvider { + void stopSearchDevicesAsync(long ret, BaseHandler handler); //异步停止设备搜索 + boolean stopSearchDevices(long ret, String requestId); //同步停止设备搜索 +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAddCustom.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAddCustom.java new file mode 100644 index 0000000..fc89b40 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/IDeviceAddCustom.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.content.Context; + +import com.mm.android.deviceaddmodule.mobilecommon.base.IBaseProvider; + + +/** + * 设备添加模块,App需不同实现的接口 + **/ +public interface IDeviceAddCustom extends IBaseProvider { + void goFAQWebview(Context context); //调整至FAQ + void goHomePage(Context context);//回到设备列表页 + String getDevAddCachePath(); //设备添加文件缓存路径 + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/OneColonScanResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/OneColonScanResult.java new file mode 100644 index 0000000..558e430 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/OneColonScanResult.java @@ -0,0 +1,21 @@ + +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; +import static com.mm.android.deviceaddmodule.mobilecommon.AppConsume.PseudoJsonScanResult.filterInvalidString; +import static com.mm.android.deviceaddmodule.mobilecommon.AppConsume.PseudoJsonScanResult.filterInvalidString4Type; + + +public class OneColonScanResult extends ScanResult { + + /** + * 创建一个新的实例OneColonScanResult. + * + * @param scanString + */ + public OneColonScanResult(String scanString) { + super(scanString); + String[] resultStrings = scanString.split(":"); + this.setSn(filterInvalidString(resultStrings[0])); + this.setMode(filterInvalidString4Type(resultStrings[1])); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PreferencesConfig.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PreferencesConfig.java new file mode 100644 index 0000000..ab32d9a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PreferencesConfig.java @@ -0,0 +1,6 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +public class PreferencesConfig { + public static final String HOST_HELP = "HOST_HELP_V2"; + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ProviderManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ProviderManager.java new file mode 100644 index 0000000..833d262 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ProviderManager.java @@ -0,0 +1,22 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + + +import com.mm.android.deviceaddmodule.provider.DeviceAddProvider; + +/** + * 功能接口管理类 + */ + +public class ProviderManager { + + public static IApp getAppProvider() { + return AppProvider.newInstance(); + } + public static IDeviceAdd getDeviceAddProvider() { + return DeviceAddProvider.newInstance(); + } + + public static IDeviceAddCustom getDeviceAddCustomProvider() { + return DeviceAddCustomImpl.newInstance(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonNcScanResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonNcScanResult.java new file mode 100644 index 0000000..29daa02 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonNcScanResult.java @@ -0,0 +1,99 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.json.JSONObject; + +/** + *

+ * 伪json格式的二维码扫描结果(带NC) + *

+ */ +public class PseudoJsonNcScanResult extends ScanResult { + + private static final String TAG = "JsonScanResult"; + private static final String[] SN_TAGS = new String[]{"SN", "sN", "Sn", "sn"}; + private static final String[] DT_TAGS = new String[]{"DT", "dT", "Dt", "dt"}; + private static final String[] RD_TAGS = new String[]{"RD", "rD", "Rd", "rd"}; + private static final String[] RC_TAGS = new String[]{"RC", "rC", "Rc", "rc"}; + private static final String[] NC_TAGS = new String[]{"NC", "nC", "Nc", "nc"}; + private static final String[] SC_TAGS = new String[]{"SC", "sC", "Sc", "sc"}; + private static final String[] IMEI_TAGS = new String[]{"IMEI", "imei"}; + + /** + * 创建一个新的实例JsonScanResult. + * + * @param scanString + */ + public PseudoJsonNcScanResult(String scanString) { + super(scanString); + + //解析伪Json 类似{SN:DVRP2P00LJL0028,DT:DH/HCVR1604HG-SFD-V4/-AF-DVR-II-A/16-16,NC:QR,RC:SQ93W5} + + //替换中文":" + scanString = scanString.replace(':', ':'); + + // 补充"{" "}" + int first = scanString.indexOf("{"); + if (first < 0) { + scanString = "{" + scanString; + } + int last = scanString.indexOf("}"); + if (last < 0) { + scanString = scanString + "}"; + } + + // 补充引号""" + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < scanString.length(); i++) { + char c = scanString.charAt(i); + if(c == '{') { + buffer.append(c).append("\""); + }else if(c == ':' || c == ',' || c == ';') { + buffer.append("\"").append(c).append("\""); + } else if(c == '}') { + buffer.append("\"").append(c); + } else { + buffer.append(c); + } + } + + String sn = ""; + String dt = ""; + String rd = ""; + String nc = ""; + String sc = ""; + String imeiCode = ""; + + try { + JSONObject jsonObject = new JSONObject(buffer.toString()); + sn = getValue(jsonObject, SN_TAGS, ""); + dt = getValue(jsonObject, DT_TAGS, ""); + rd = getValue(jsonObject, RD_TAGS, ""); + rd = getValue(jsonObject, RC_TAGS, ""); + nc = getValue(jsonObject, NC_TAGS, ""); + sc = getValue(jsonObject, SC_TAGS, ""); + imeiCode = getValue(jsonObject, IMEI_TAGS, ""); + } catch (Exception e) { + e.printStackTrace(); + } + this.setSn(sn); + this.setRegcode(rd); + this.setMode(dt); + this.setNc(nc); + this.setSc(sc); + this.setImeiCode(imeiCode); + LogUtil.debugLog("PseudoJsonNcScanResult", this.toString()); + } + + private String getValue(JSONObject json, String[] tags, String defaultStr) { + for (String tag : tags) { + if (json.has(tag)) { + return json.optString(tag, defaultStr); + } + } + return defaultStr; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonScanResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonScanResult.java new file mode 100644 index 0000000..7fac391 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/PseudoJsonScanResult.java @@ -0,0 +1,157 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.text.TextUtils; + +/** + *

+ * 伪json格式的二维码扫描结果 + *

+ */ +public class PseudoJsonScanResult extends ScanResult { + + private static final String TAG = "JsonScanResult"; + private static final String[] SN_TAGS = new String[]{"SN:", "sN:", "Sn:", "sn:", "SN:", "sN:", "Sn:", "sn:"}; + private static final String[] DT_TAGS = new String[]{"DT:", "dT:", "Dt:", "dt:", "DT:", "dT:", "Dt:", "dt:"}; + private static final String[] RD_TAGS = new String[]{"RD:", "rD:", "Rd:", "rd:", "RD:", "rD:", "Rd:", "rd:"}; + private static final String[] RC_TAGS = new String[]{"RC:", "rC:", "Rc:", "rc:", "RC:", "rC:", "Rc:", "rc:"}; + + /** + * 创建一个新的实例JsonScanResult. + * + * @param scanString + */ + public PseudoJsonScanResult(String scanString) { + super(scanString); + + //解析伪Json 类似{SN:DVRP2P00LJL0028,DT:DH/HCVR1604HG-SFD-V4/-AF-DVR-II-A/16-16,RC:SQ93W5} + + String jsonStr; + int firstIndex = scanString.indexOf("{"); + if (firstIndex >= 0 && firstIndex <= scanString.length() - 1) { + jsonStr = scanString.substring(firstIndex, scanString.length()); + } else { + jsonStr = scanString; + } + + int snEndIndex = -1; + int dtEndIndex = -1; + int rdEndIndex = -1; + int snStartIndex = getStartIndex(jsonStr, SN_TAGS, -1); + int dtStartIndex = getStartIndex(jsonStr, DT_TAGS, -1); + int rdStartIndex = getStartIndex(jsonStr, RD_TAGS, -1); + rdStartIndex = getStartIndex(jsonStr, RC_TAGS, rdStartIndex); + + if (snStartIndex == -1) { + this.setSn(""); + return; + } + + + if (snStartIndex > dtStartIndex && snStartIndex > rdStartIndex) { // sn在最后 + if (dtStartIndex == -1 && rdStartIndex == -1) { // {sn:} + snEndIndex = jsonStr.length() - 1; + + } else if (dtStartIndex == -1 && rdStartIndex != -1) { // {rd:,sn:} + rdEndIndex = snStartIndex - 1; + snEndIndex = jsonStr.length() - 1; + } else if (dtStartIndex != -1 && rdStartIndex == -1) { // {dt:,sn:} + dtEndIndex = snStartIndex - 1; + snEndIndex = jsonStr.length() - 1; + } else { + if (dtStartIndex > rdStartIndex) { // {rd:,dt:,sn:} + rdEndIndex = dtStartIndex - 1; + dtEndIndex = snStartIndex - 1; + snEndIndex = jsonStr.length() - 1; + } else { // {dt:,rd:,sn:} + dtEndIndex = rdStartIndex - 1; + rdEndIndex = snStartIndex - 1; + snEndIndex = jsonStr.length() - 1; + } + } + } else if (dtStartIndex > snStartIndex && dtStartIndex > rdStartIndex) { // dt在最后 + if (rdStartIndex == -1) { + snEndIndex = dtStartIndex - 1; + dtEndIndex = jsonStr.length() - 1; + } else if (snStartIndex > rdStartIndex) { + rdEndIndex = snStartIndex - 1; + snEndIndex = dtStartIndex - 1; + dtEndIndex = jsonStr.length() - 1; + + } else if (snStartIndex < rdStartIndex) { + snEndIndex = rdStartIndex - 1; + rdEndIndex = dtStartIndex - 1; + dtEndIndex = jsonStr.length() - 1; + } + } else if (rdStartIndex > snStartIndex && rdStartIndex > dtStartIndex) { // rd在最后 + if (dtStartIndex == -1) { + snEndIndex = rdStartIndex - 1; + rdEndIndex = jsonStr.length() - 1; + } else if (snStartIndex > dtStartIndex) { + dtEndIndex = snStartIndex - 1; + snEndIndex = rdStartIndex - 1; + rdEndIndex = jsonStr.length() - 1; + + } else if (snStartIndex < dtStartIndex) { + snEndIndex = dtStartIndex - 1; + dtEndIndex = rdStartIndex - 1; + rdEndIndex = jsonStr.length() - 1; + } + } + + if (rdStartIndex != -1) { + this.setRegcode(filterInvalidString(jsonStr.substring(rdStartIndex + 2, rdEndIndex))); + } else { + this.setRegcode(""); + } + + if (dtStartIndex != -1) { + this.setMode(filterInvalidString4Type(jsonStr.substring(dtStartIndex + 2, dtEndIndex))); + } else { + this.setMode(""); + } + this.setSn(filterInvalidString(jsonStr.substring(snStartIndex + 2, snEndIndex))); + + } + + private int getStartIndex(String jsonStr, String[] tags, int startIndex) { + for (String dttag : tags) { + if (jsonStr.contains(dttag)) { + return jsonStr.indexOf(dttag) + 1; + } + } + return startIndex; + } + + public static String filterInvalidString(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + String numberAndAbc = "[a-zA-Z0-9]"; + StringBuilder buffer = new StringBuilder(); + int len = str.length(); + for (int i = 0; i < len; ++i) { + String temp = str.substring(i, i + 1); + if (temp.matches(numberAndAbc)) { + buffer.append(temp); + } + } + return buffer.toString(); + } + + public static String filterInvalidString4Type(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + String numberAndAbc = "[a-zA-Z0-9-/\\\\]"; + StringBuilder buffer = new StringBuilder(); + int len = str.length(); + for (int i = 0; i < len; ++i) { + String temp = str.substring(i, i + 1); + if (temp.matches(numberAndAbc)) { + buffer.append(temp); + } + } + return buffer.toString(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResult.java new file mode 100644 index 0000000..8d3c2e9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResult.java @@ -0,0 +1,124 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +/** + *

+ * 二维码扫描结果基类 + *

+ */ +public class ScanResult { + /** + * 设备序列号 + */ + private String sn = ""; + + /** + * 设备型号 + */ + private String mode = ""; + + /** + * 设备验证码、设备安全码 + */ + private String regcode = ""; + + /** + * 设备随机码,备用 + */ + private String rd = ""; + + /** + * 设备能力 + */ + private String nc = ""; + + /** + * 设备安全验证码 + */ + private String sc = ""; + + private String imeiCode = ""; + + /** + * 创建一个新的实例ScanResult. + * + * @param scanString + */ + public ScanResult(String scanString) { + // TODO Auto-generated constructor stub + } + + /** + * 创建一个新的实例ScanResult. + */ + public ScanResult() { + // TODO Auto-generated constructor stub + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getRegcode() { + return regcode; + } + + public void setRegcode(String regcode) { + this.regcode = regcode; + } + + public String getRd() { + return rd; + } + + public void setRd(String rd) { + this.rd = rd; + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + + public String getNc() { + return nc; + } + + public void setNc(String nc) { + this.nc = nc; + } + + public String getSc() { + return sc; + } + + public void setSc(String sc) { + this.sc = sc; + } + + public String getImeiCode() { + return imeiCode; + } + + public void setImeiCode(String imeiCode) { + this.imeiCode = imeiCode; + } + + @Override + public String toString() { + return "ScanResult{" + + "sn='" + sn + '\'' + + ", mode='" + mode + '\'' + + ", regcode='" + regcode + '\'' + + ", nc='" + nc + '\'' + + ", sc='" + sc + '\'' + + ", imeiCode='" + imeiCode + '\'' + + '}'; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResultFactory.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResultFactory.java new file mode 100644 index 0000000..8dff8d4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ScanResultFactory.java @@ -0,0 +1,140 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

+ * 根据二维码扫描结果生成相应的类 + *

+ */ +public class ScanResultFactory { + // 工厂方法.注意 返回类型为抽象产品角色 + private static String tag = "www.hsview.com"; + private static String tag_lc = "www.lechange.cn"; + + public static ScanResult scanResult(String scanString) { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) {//海外二维码规则 + // 带NC标签的 + final String[] NC_ARRAYS = new String[]{"NC:", "nC:", "Nc:", "nc:", "NC:", "nC:", "Nc:", "nc:"}; + // 带SC标签的 + final String[] SC_ARRAYS = new String[]{"SC:", "sC:", "Sc:", "Sc:", "SC:", "sC:", "Sc:", "sc:"}; + boolean hasNc = hasTag(scanString, NC_ARRAYS); + boolean hasSc = hasTag(scanString, SC_ARRAYS); + if((hasNc || hasSc) && scanString.contains("{")) { + return new PseudoJsonNcScanResult(scanString); + } else { + String deviceSN = ""; + String deviceSerial = ""; + if (scanString.contains(",")) { //逗号分割,{SN:2J021B3PAK00120,DT:IPC-HFW1120SP-W-0280B,RC:564897} + scanString = scanString.substring(1, scanString.length() - 1); //去掉收尾花括号 + String[] array = scanString.split(","); + for (String strArray : array) { + if (strArray.contains("SN:")) { + deviceSN = strArray.substring(strArray.indexOf("SN:") + 3, strArray.length()); + } + if (strArray.contains("DT:")) { + deviceSerial = strArray.substring(strArray.indexOf("DT:") + 3, strArray.length()); + } + } + } else if (scanString.contains(";")) {//分号分割,{SN:2J021B3PAK00120;DT:IPC-HFW1120SP-W-0280B;RC:564897} + scanString = scanString.substring(1, scanString.length() - 1); //去掉收尾花括号 + String[] array = scanString.split(";"); + for (String strArray : array) { + if (strArray.contains("SN:")) { + deviceSN = strArray.substring(strArray.indexOf("SN:") + 3, strArray.length()); + } + if (strArray.contains("DT:")) { + deviceSerial = strArray.substring(strArray.indexOf("DT:") + 3, strArray.length()); + } + } + } else if (scanString.contains(":")) { //2M047C9PAN00005:DHI-ARD1611-W:PJ0V46 + String[] array = scanString.split(":"); + deviceSN = array[0]; + deviceSerial = array[1]; + } else { + deviceSN = scanString; + } + // 兼容 俄语区Q4的订单采用标签二维码内容异常 格式为:DH-IPC-C35P,4K002C6PAJA49A7 + if(TextUtils.isEmpty(deviceSN)) { + String[] array = scanString.split(","); + if(array != null && array.length == 2) { + deviceSN = array[1]; + } + } + + ScanResult scanResult = new ScanResult(); + scanResult.setSn(deviceSN); + scanResult.setMode(deviceSerial); + return scanResult; + } + } else {//国内二维码规则 + if(scanString.contains(tag) || scanString.contains(tag_lc)){ + if(scanString.contains("{")){ + // 兼容TC1 + ScanResult scanResult = new PseudoJsonScanResult(scanString); + return scanResult; + } + // 兼容老乐橙设备 + int index = scanString.indexOf('='); + String sn = scanString.substring(index + 1, scanString.length()); + ScanResult scanResult = new ScanResult(); + scanResult.setSn(sn); + return scanResult; + } else if (scanString.contains("{")) { + ScanResult result = new PseudoJsonNcScanResult(scanString); + return result; + } else if (!scanString.contains("SN:") || !scanString.contains("SN=") || !scanString.contains("SN =") || + !scanString.contains("sn:") || !scanString.contains("sn=") || !scanString.contains("sn =")) { + if (!checkString(scanString)) { + String[] strings = scanString.split(":"); + if (strings != null && !scanString.startsWith("http://") && strings.length == 3) { + return new TwoColonsScanResult(scanString); + + } else if (strings != null && !scanString.startsWith("http://") && strings.length == 2) { + return new OneColonScanResult(scanString); + } + } else { + ScanResult scanResult = new ScanResult(); + scanResult.setSn(scanString); + return scanResult; + } + } + } + return new ScanResult(); + } + + // 判断是否有tag + private static boolean hasTag(String scanString, String[] tagArrays) { + boolean hasTag = false; + for (String tag : tagArrays) { + if (scanString.contains(tag)) { + hasTag = true; + break; + } + } + return hasTag; + } + + /** + * 判断是否只包含数字或大小写字母 + * + * @param str + * @return + */ + public static boolean checkString(String str) { + String regEx = "[0-9A-Za-z]*"; // 只能是数字以及个别字符 + Pattern p = Pattern.compile(regEx); + Matcher m = p.matcher(str); + if (m.matches()) { + return true; + } else { + return false; + } + } + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ThreadPool.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ThreadPool.java new file mode 100644 index 0000000..565d1dc --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/ThreadPool.java @@ -0,0 +1,60 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; + +import android.os.Process; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; + +public class ThreadPool { + private volatile static ExecutorService cachedThreadPool; + + // 提交线程 + public static Future submit(Runnable mRunnable) { + + if (cachedThreadPool == null) { + synchronized (ExecutorService.class) { + if (cachedThreadPool == null) { + cachedThreadPool = Executors.newFixedThreadPool(Runtime + .getRuntime().availableProcessors() * 2,new DefaultFactory()); + } + } + } + return cachedThreadPool.submit(mRunnable); + } + + // 关闭 + public static void shutdown() { + if (cachedThreadPool != null && !cachedThreadPool.isShutdown()) + cachedThreadPool.shutdown(); + cachedThreadPool = null; + } + + static class DefaultFactory implements ThreadFactory { + + @Override + public Thread newThread(Runnable r) { + + Thread thread = new Thread(new FactoryRunnable(r)); + + return thread; + } + } + + static class FactoryRunnable implements Runnable { + Runnable runnable; + + public FactoryRunnable(Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + runnable.run(); + } + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/TwoColonsScanResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/TwoColonsScanResult.java new file mode 100644 index 0000000..409fac8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/AppConsume/TwoColonsScanResult.java @@ -0,0 +1,25 @@ +package com.mm.android.deviceaddmodule.mobilecommon.AppConsume; +import static com.mm.android.deviceaddmodule.mobilecommon.AppConsume.PseudoJsonScanResult.filterInvalidString; +import static com.mm.android.deviceaddmodule.mobilecommon.AppConsume.PseudoJsonScanResult.filterInvalidString4Type; + +/** + *

+ * xxx:xxx:xxx格式二维码 + *

+ */ +public class TwoColonsScanResult extends ScanResult { + + /** + * 创建一个新的实例TwoColonsScanResult. + * + * @param scanString + */ + public TwoColonsScanResult(String scanString) { + super(scanString); + String[] resultStrings = scanString.split(":"); + this.setSn(filterInvalidString(resultStrings[0])); + this.setMode(filterInvalidString4Type(resultStrings[1])); + this.setRegcode(filterInvalidString(resultStrings[2])); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceAbility.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceAbility.java new file mode 100644 index 0000000..2a87b43 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceAbility.java @@ -0,0 +1,164 @@ +package com.mm.android.deviceaddmodule.mobilecommon.annotation; + +import android.support.annotation.StringDef; + +import java.lang.annotation.Retention; + +import static com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility.*; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +@Retention(SOURCE) +@StringDef({WLAN, AlarmPIR, AlarmMD, AudioTalk, AudioTalkV1, VVP2P, DHP2P, PTZ, PT, HSEncrypt, CloudStorage, AGW, BreathingLight, + PlaybackByFilename, LocalStorage, RegCode, RemoteControl, Panorama, RD, SLAlarm, CK, AudioEncodeOff, MDS, MDW, HeaderDetect, + SR, AGWDisarm, CollectionPoint, TimedCruise, SmartTrack, ZoomFocus, SmartLocate, LocalRecord, XUpgrade, Auth, NumberStat, + + HoveringAlarm, BeOpenedDoor, NonAccessoriesAdd, CloseCamera, MobileDetect, Siren, LinkageSiren, WhiteLight, WLV2, Dormant, + /*NoVA, */NoAccessories, UnsupportLiveShare, RTSV1, PBSV1, SearchLight, CallByRtsp, SirenTime,NVM, LEDS, TimingGraphics, HumanDetect, AlarmPIRV2, HUBAlarmPIRV2, + AlarmPIRV3, AlarmPIRV4, LocalStorageEnable, DaySummerTime, WeekSummerTime,SummerTimeOffset, AiHuman, AiCar, Electric, WIFI, DLOCS, OpenDoorByFace, OpenDoorByTouch, + PlaySoundModify, WideDynamic, TalkSoundModify, LinkDevAlarm, LinkAccDevAlarm, AbAlarmSound, CheckAbDecible, Reboot, PlaySound, + AudioEncodeControl, SceneMode, SIMCA, TimeFormat, SASQ, MGOCS, ModifyName, ElecInfo, SigInfo, ACT, AlarmSound, DDT, OnlyArmed, TSV1, NoPlan, ChnLocalStorage, + AccessoryAlarmSound, RingAlarmSound, SCCode, CustomRing, InfraredLight, AudioEncodeControlV2, InstantDisAlarm,IDAP, RDV2,RDV3, DeviceAlarmSound, FaceDetect, + CallAbility, CAV2, HAV2, Ring, RTSV2, PBSV2, TSV2, PT1, AX, HAV3, VideoMotionSMD, TLSEnable, TCM, CLDA, ChnWhiteLight, ChnSiren, LED, + CCR, CLS, CLW, ""}) + +public @interface DeviceAbility { + String WLAN = "WLAN"; // 设备支持接入无线局域网 + String AlarmPIR = "AlarmPIR"; // 设备支持人体红外报警 + String AlarmMD = "AlarmMD"; // 设备支持动检报警 + String AudioTalk = "AudioTalk"; // 设备支持语音对讲 + String AudioTalkV1 = "AudioTalkV1"; // 通道支持语音对讲 + String VVP2P = "VVP2P"; // 设备支持威威网络P2P服务 + String DHP2P = "DHP2P"; // 设备支持大华P2P服务 + String PTZ = "PTZ"; // 设备支持云台方向操作,及云台缩放 + String PT = "PT"; // 设备支持云台方向操作 + String PT1 = "PT1"; // 设备支持云台四方向操作 + String HSEncrypt = "HSEncrypt"; // 设备支持华视微讯码流加密 + String CloudStorage = "CloudStorage"; // 设备支持华视微讯平台云存储 + String CloudUpdate = "CloudUpdate"; // easy4ip支持云升级,自己本地判断使用 + String AGW = "AGW"; // 设备支持网关功能 + String BreathingLight = "BreathingLight"; // 设备有呼吸灯 + String PlaybackByFilename = "PlaybackByFilename"; // 设备支持根据文件名回放 + String LocalStorage = "LocalStorage"; // 支持设备本地存储,如有SD卡或硬盘 + String RegCode = "RegCode"; // 设备添加需要支持验证码 + String RemoteControl = "RemoteControl"; // 支持远程联动 + String Panorama = "Panorama"; //支持全景图 + String RD = "RD"; //设备具有远程调试能力(Remote Debug) + String RDV2 = "RDV2"; //支持RD能力,支持数据埋点控制,支持调试日志上传 对应设备体验计划开关 + String RDV3 = "RDV3"; //支持RD能力,支持数据埋点控制,支持级别控制 + String SLAlarm = "SLAlarm"; //设备支持声光告警(sound and light alarm) + String CK = "CK"; // 设备视频加密 + String AudioEncodeOff = "AudioEncodeOff"; //支持音频编码关闭(无伴音) AudioEncode:支持音频编码(伴音) 老设备不上报,因此只需要使用AudioEncodeOff进行判断即可 + String MDS = "MDS"; //通道 motion-detect-sensitive支持动检灵敏度设置 + String MDW = "MDW"; //通道 motion-detect-window支持动检窗口设置 + String HeaderDetect = "HeaderDetect"; //通道 支持人头检测 + String SR = "SR"; ////设备,设备支持语音识别 + String AGWDisarm = "AGWDisarm"; // 网关告警解除配置(APP2.8,网关支持布撤防(过滤配件告警,但保留告警配置)功能) + String CollectionPoint = "CollectionPoint"; //支持收藏点 + String TimedCruise = "TimedCruise"; //支持定时巡航 + String SmartTrack = "SmartTrack"; //智能追踪 + String ZoomFocus = "ZoomFocus"; //支持变倍聚焦 变焦相机能力集 + String SmartLocate = "SmartLocate"; //听声辨位 + String LocalRecord = "LocalRecord"; //支持设备设备录像设置 + String XUpgrade = "XUpgrade"; // 云升级 + String Auth = "Auth"; // 设备端环回RTSP需认证 + String NumberStat = "NumberStat"; // 客流量数据采集 + String HoveringAlarm = "HoveringAlarm"; //徘徊报警 + String BeOpenedDoor = "BeOpenedDoor"; //普通开门,即成功开门(K5电池门锁) + String NonAccessoriesAdd = "NonAccessoriesAdd"; //表示不支持C端信令添加方式 + String CloseCamera = "CloseCamera"; //支持关闭摄像头 + String MobileDetect = "MobileDetect"; //动检+PIR + String Siren = "Siren"; //警笛 + String LinkageSiren = "LinkageSiren"; //报警联动警笛 + String WhiteLight = "WhiteLight"; //白光灯 + String WLV2 = "WLV2"; // 白光灯,不支持亮度调节能力 + String Dormant = "Dormant"; //可休眠,具有唤醒、休眠状态 + // String NoVA = "NoVA"; //不支持语音播报(Voice Announcements) + String NoAccessories = "NoAccessories"; //不支持配件使能(不支持布撤防) + String UnsupportLiveShare = "UnsupportLiveShare"; //是否支持直播分享,easy4ip独有, 客户端自己的能力级,相当于控制开关 + String RTSV1 = "RTSV1";//实时流支持私有协议拉流 + String PBSV1 = "PBSV1";//回放流支持私有协议拉流 + String TSV1 = "TSV1"; //对讲支持私有协议拉流 + String RTSV2 = "RTSV2";//实时流支持私有协议拉流(TLS) + String PBSV2 = "PBSV2";//回放流支持私有协议拉流(TLS) + String TSV2 = "TSV2"; //对讲支持私有协议拉流(TLS) + String TimingGraphics = "TimingGraphics"; //人形录像服务能力 + String HumanDetect = "HumanDetect"; //人形检测(海外) + String AlarmPIRV2 = "AlarmPIRV2"; //支持PIR开关 + String HUBAlarmPIRV2 = "HUBAlarmPIRV2"; //支持Hub PIR开关 + String AlarmPIRV3 = "AlarmPIRV3"; //支持PIR扇形区域,同时支持PIR使能开关 + String AlarmPIRV4 = "AlarmPIRV4"; //支持PIR扇形区域 + String LocalStorageEnable = "LocalStorageEnable"; //支持录像存储开关 + String SearchLight = "SearchLight"; //探照灯 + String CallByRtsp = "CallByRtsp"; //表示接听、挂断可直接基于RTSP协议实现 + String SirenTime = "SirenTime"; //支持警笛时长设置 + String NVM = "NVM"; //支持夜视模式设置 + String LEDS = "LEDS"; //支持补光灯灵敏度 + String DaySummerTime = "DaySummerTime"; //按日夏令时 + String WeekSummerTime = "WeekSummerTime";//按周夏令时 + String SummerTimeOffset = "SummerTimeOffset"; //支持夏令时偏移量设置 + String TimeFormat = "TimeFormat";//支持时间格式设置 + String SceneMode = "SceneMode"; //支持布撤防情景模式设置 + String SIMCA = "SIMCA"; //支持SIM卡相关配置 + String SASQ = "SASQ";//配件防拆状态能力集 + String MGOCS = "MGOCS";//支持门磁开关状态获取 + String ModifyName = "ModifyName";//配件支持修改名称 + String ElecInfo = "ElecInfo";//支持电量信息查询上报 + String SigInfo = "SigInfo";//支持信号信息查询上报 + String ACT = "ACT";//支持报警持续时间配置 + String AlarmSound = "AlarmSound"; //支持报警音设置 + String AiHuman = "AiHuman";//人形智能 TF8P + String AiCar = "AiCar";//车辆智能 TF8P + String Electric = "Electric";//设备支持电池电量能力 + String WIFI = "WIFI";//设备支持获取WIFI信号强度能力 + String DLOCS = "DLOCS";//门锁开关状态 + + String DDT = "DDT"; //支持布防延时能力 + String OnlyArmed = "OnlyArmed"; //只支持布防(永久布防) + String NoPlan = "NoPlan";//不支持布防计划 + String OpenDoorByFace = "OpenDoorByFace";//人脸开门 + String OpenDoorByTouch = "OpenDoorByTouch";// 触摸开门 + String PlaySoundModify = "PlaySoundModify";// 设备提示音调节能力 + String TalkSoundModify = "TalkSoundModify";//对讲音量调节 + String WideDynamic = "WideDynamic";// 宽动态 + String LinkDevAlarm = "LinkDevAlarm";//关联设备报警 + String LinkAccDevAlarm = "LinkAccDevAlarm";//关联配件报警 + String AbAlarmSound = "AbAlarmSound";//异常报警音 + String CheckAbDecible = "CheckAbDecible";//异常检测音分贝阈值 + String Reboot = "Reboot";//设备重启 + String PlaySound = "PlaySound"; //设备提示音开关能力 + String AudioEncodeControl = "AudioEncodeControl"; //支持音频编码控制(开或关) + String AudioEncodeControlV2 = "AudioEncodeControlV2";//支持音频编码控制(开或关),只影响实时视频、录像音频,不影响对讲音频控制 + String AccessoryAlarmSound = "AccessoryAlarmSound";//支持报警网关配件报警音效设置 + String DeviceAlarmSound = "DeviceAlarmSound"; //设备报警音效设置 + String RingAlarmSound = "RingAlarmSound";//支持门铃音量设置 + String ChnLocalStorage = "ChnLocalStorage";//支持通道本地存储 + + String SCCode = "SCCode"; // 设备支持SC安全码 + String CustomRing = "CustomRing";//自定义铃声 + String InfraredLight = "InfraredLight";//红外灯能力集 + String InstantDisAlarm = "InstantDisAlarm";//支持一键撤防能力 + String IDAP = "IDAP";//支持一键撤防能力 + String FaceDetect = "FaceDetect"; //支持人脸检测 + + String CallAbility = "CallAbility"; //支持呼叫能力 + String CAV2 = "CAV2"; //支持呼叫能力,且拒接时可选择播放自定义铃声 + String HAV2 = "HAV2"; //徘徊报警V2,支持统一的检测距离设置及逗留时长设置 + String Ring = "Ring"; //仅支持铃声设置 LoginAfter DS11,去除根据设备型号兼容逻辑 2019-4-3 + String AX = "AX"; // 安消一体机 + String HAV3 = "HAV3"; // 徘徊报警V3,V2降级版,不支持逗留时长立即设置 + String VideoMotionSMD = "VideoMotionSMD";//包含人形和车辆能力 + + /*3.15.0*/ + String TCM = "TCM"; //支持3码合一(Three code megre) + String TLSEnable = "TLSEnable";// 2019-8-20 支持拉流、图片和云录像链路加密传输 + + /*5.0.0*/ + String CLW = "CLW"; //通道报警联动白光灯 + String CLS = "CLS"; //通道报警联动警笛 + String CCR = "CCR"; //通道自定义铃声 + String LED = "LED"; //补光灯 + String ChnSiren = "ChnSiren"; //警笛 + String ChnWhiteLight = "ChnWhiteLight"; //通道白光灯 + String CLDA = "CLDA"; //通道关联设备报警 + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceState.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceState.java new file mode 100644 index 0000000..f11f214 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/annotation/DeviceState.java @@ -0,0 +1,24 @@ +package com.mm.android.deviceaddmodule.mobilecommon.annotation; + +import android.support.annotation.StringDef; + +import java.lang.annotation.Retention; + +import static com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceState.OFFLINE; +import static com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceState.ONLINE; +import static com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceState.SLEEP; +import static com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceState.UPGRADE; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * 设备在离线状态枚举值 + */ +@Retention(SOURCE) +@StringDef({ONLINE, OFFLINE, SLEEP,UPGRADE, ""}) +public @interface DeviceState { + String ONLINE = "online"; + String OFFLINE = "offline"; + String SLEEP = "sleep"; + String UPGRADE = "upgrading"; + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ActivityManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ActivityManager.java new file mode 100644 index 0000000..ede087b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ActivityManager.java @@ -0,0 +1,71 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.app.Activity; + +import java.util.Stack; + +/** + *

+ * activity 栈管理 + *

+ */ +public class ActivityManager { + private static Stack activityStack; + + private static ActivityManager instance; + + private ActivityManager() { + } + + public static ActivityManager getScreenManager() { + if (instance == null) { + instance = new ActivityManager(); + } + return instance; + } + + // 退出栈顶Activity + public void popActivity(Activity activity) { + if (activity != null) { + // 在从自定义集合中取出当前Activity时,也进行了Activity的关闭操作 + //activity.finish(); + activityStack.remove(activity); + activity = null; + } + } + + // 获得当前栈顶Activity + public Activity currentActivity() { + Activity activity = null; + try{ + if (activityStack != null && !activityStack.empty()){ + activity = activityStack.lastElement(); + } + }catch (Exception e){ + return activity; + } + return activity; + } + + // 将当前Activity推入栈中 + public void pushActivity(Activity activity) { + if (activityStack == null) { + activityStack = new Stack<>(); + } + activityStack.add(activity); + } + + // 退出栈中所有Activity + public void popAllActivityExceptOne(Class cls) { + while (true) { + Activity activity = currentActivity(); + if (activity == null) { + break; + } + if (activity.getClass().equals(cls)) { + break; + } + popActivity(activity); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseActivity.java new file mode 100644 index 0000000..f40100e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseActivity.java @@ -0,0 +1,190 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.annotation.CallSuper; +import android.view.Gravity; +import android.widget.TextView; +import android.widget.Toast; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +public class BaseActivity extends Activity implements IActivityResultDispatch { + + private Toast mToast; + private ProgressDialog mProgressDialog; + private boolean isDestroyed = false; + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(BaseEvent event) { + } + + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this); + mProgressDialog = new ProgressDialog(this, R.style.mobile_common_custom_dialog); + mProgressDialog.setCanceledOnTouchOutside(false); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + dissmissProgressDialog(); + isDestroyed = true; + mProgressDialog = null; + } + + protected void showProgressDialog(int layoutId) { + if (mProgressDialog != null && !mProgressDialog.isShowing()) { + mProgressDialog.show(); + mProgressDialog.setContentView(layoutId); + } + } + + protected void dissmissProgressDialog() { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + } + } + + public boolean isActivityDestory() { + return isDestroyed; + } + + protected void toast(int res) { + String content = ""; + try { + content = getString(res); + } catch (Resources.NotFoundException e) { + LogUtil.debugLog("toast", "resource id not found!!!"); + } + + toast(content); + } + + protected void toast(String content) { + if (mToast == null) { + mToast = Toast.makeText(this, content, Toast.LENGTH_SHORT); + } else { + mToast.setText(content); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.show(); + } + + /** + * 带错误码的toast + * + * @param errorCode + */ + public void toast(int res, int errorCode) { + if (mToast == null) { + mToast = Toast.makeText(this, getString(res) + "(" + errorCode + ")", + Toast.LENGTH_SHORT); + } else { + mToast.setText(getString(res) + "(" + errorCode + ")"); + } + mToast.show(); + } + + + protected void toastInCenter(int res) { + String content = ""; + try { + content = getString(res); + } catch (Resources.NotFoundException e) { + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toastInCenter(content); + + } + + protected void toastInCenter(String content) { + if (mToast == null) { + mToast = Toast.makeText(this, content, Toast.LENGTH_SHORT); + mToast.setGravity(Gravity.CENTER, 0, 0); + TextView tv = mToast.getView().findViewById(android.R.id.message); + tv.setGravity(Gravity.CENTER); + } else { + mToast.setText(content); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.show(); + } + + @Override + public void startActivity(Intent intent) { + super.startActivity(intent); + overridePendingTransition(R.anim.mobile_common_slide_in_right, R.anim.mobile_common_slide_out_left); + } + + public void startActivityNoAnimation(Intent intent) { + super.startActivity(intent); + } + + + @Override + public void startActivityForResult(Intent intent, int requestCode) { + super.startActivityForResult(intent, requestCode); +// + } + + public void startActivityForResultWithAnimation(Intent intent, int requestCode) { + super.startActivityForResult(intent, requestCode); + overridePendingTransition(R.anim.mobile_common_slide_in_right, R.anim.mobile_common_slide_out_left); + } + + @Override + public void finish() { + + super.finish(); + overridePendingTransition(R.anim.mobile_common_slide_left_back_in + , R.anim.mobile_common_slide_right_back_out); + } + + public void finishNoAnimation() { + super.finish(); + } + + + @Override + @CallSuper + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (listeners == null) return; + synchronized (listeners) { + for (OnActivityResultListener listener : listeners) { + if (listener != null) { + listener.onActivityResult(requestCode, resultCode, data); + } + } + + } + } + + private final List listeners = new ArrayList<>(); + + public void addOnActivityResultListener(IActivityResultDispatch.OnActivityResultListener listener) { + listeners.add(listener); + } + + public void removeOnActivityResultListener(IActivityResultDispatch.OnActivityResultListener listener) { + if (listener != null) { + listeners.remove(listener); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseDialogFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseDialogFragment.java new file mode 100644 index 0000000..7cc3b94 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseDialogFragment.java @@ -0,0 +1,109 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.content.Context; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.widget.Toast; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + + +public class BaseDialogFragment extends DialogFragment{ + + private Toast mToast; + @Override + public void onAttach(Context context) { + super.onAttach(context); + if( getActivity() instanceof BaseFragmentActivity){ + ((BaseFragmentActivity) getActivity()).addBaseDialogFragment(this); + } + } + + @Override + public void onDetach() { + if( getActivity() instanceof BaseFragmentActivity){ + ((BaseFragmentActivity) getActivity()).removeBaseDialogFragment(this); + } + super.onDetach(); + + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public int show(FragmentTransaction transaction, String tag) { + + return show(transaction, tag, true); + } + + int mBackStackId; + + public int show(FragmentTransaction transaction, String tag, boolean allowStateLoss) { + + if (this.isAdded()) {//防止重复 + transaction.remove(this); + } + transaction.add(this, tag); + mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit(); + return mBackStackId; + } + + @Override + public void show(FragmentManager manager, String tag) { + + show(manager.beginTransaction(), tag, true); + } + + protected void toast(int res) { + if (getActivity() != null && !getActivity().isFinishing()) { + String content =""; + try { + content = getActivity().getString(res); + }catch (Resources.NotFoundException e){ + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toast(content); + } + } + + protected void toast(String content) { + if (getActivity() != null && !getActivity().isFinishing()) { + if (mToast == null) { + mToast = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + mToast.setText(content); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.show(); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + @Override + public void dismissAllowingStateLoss() { + if(getActivity() == null || getFragmentManager() == null || getFragmentManager().isDestroyed()){ + return; + } + + super.dismissAllowingStateLoss(); + } + + @Override + public void dismiss() { + if(getActivity() == null|| getFragmentManager() == null || getFragmentManager().isDestroyed() ){ + return; + } + super.dismissAllowingStateLoss(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragment.java new file mode 100644 index 0000000..130cbaf --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragment.java @@ -0,0 +1,392 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + + +import android.app.ProgressDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.Fragment; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.view.Window; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.api.IProgressDialogControlView; +import com.mm.android.deviceaddmodule.mobilecommon.common.HandlerManager; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.lang.reflect.Field; + +/** + * 基类,不加其他功能 + */ +public class BaseFragment extends Fragment implements IProgressDialogControlView { + private static String TAG = "BaseFragment"; + private ProgressDialog mProgressDialog; + private Toast mToast; + private Toast mToastInCenter; + private Toast mToastWithImg; + protected HandlerManager mHandlerManager; + + public BaseFragment() { + + } + + public boolean isCurrentPageView() { + return false; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(BaseEvent event) { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + registerBroadCast(); + mProgressDialog = new ProgressDialog(getActivity(), R.style.mobile_common_custom_dialog); + Window window = mProgressDialog.getWindow(); + if (window != null) { + window.setWindowAnimations(R.style.mobile_common_dialog_anima); + } + + mProgressDialog.setCanceledOnTouchOutside(false); + if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this); + mHandlerManager = new HandlerManager(); + } + + @Override + public void showProgressDialog(int layoutId) { + if (isDialogEnable() && !mProgressDialog.isShowing()) { + mProgressDialog.show(); + mProgressDialog.setContentView(layoutId); + } + } + + @Override + public void dissmissProgressDialog() { + if (isDialogEnable() && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + } + } + + @Override + public void cancleProgressDialog() { + if (isDialogEnable() && mProgressDialog.isShowing()) { + mProgressDialog.cancel(); + } + } + + @Override + public void setProgressDialogCancelable(boolean flag) { + if (isDialogEnable()) { + mProgressDialog.setCancelable(flag); + } + } + + @Override + public void setProgressDialogCancelListener(DialogInterface.OnCancelListener cancelListener) { + if (isDialogEnable()) { + mProgressDialog.setOnCancelListener(cancelListener); + } + } + + private boolean isDialogEnable() { + return getActivity() != null && !getActivity().isFinishing() && mProgressDialog != null; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (getActivity() instanceof BaseFragmentActivity) { + ((BaseFragmentActivity) getActivity()).addBaseFragment(this); + } + } + + @Override + public void onDetach() { + if (getActivity() instanceof BaseFragmentActivity) { + ((BaseFragmentActivity) getActivity()).removeBaseFragment(this); + } + super.onDetach(); + try { + Field childFragment = Fragment.class.getDeclaredField("mChildFragmentManager"); + childFragment.setAccessible(true); + childFragment.set(this, null); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onDestroyView() { + dissmissProgressDialog(); + mProgressDialog = null; + super.onDestroyView(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + unRegisterBroadCast(); + dissmissProgressDialog(); + mProgressDialog = null; + if (EventBus.getDefault().isRegistered(this)) EventBus.getDefault().unregister(this); + mHandlerManager.clearHandlers(); + } + + protected void toast(int res) { + if (getActivity() != null && !getActivity().isFinishing()) { + String content = ""; + try { + content = getActivity().getString(res); + } catch (Resources.NotFoundException e) { + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toast(content); + } + } + + protected void toast(String content) { + if (!isAdded()) { + return; + } + if (getActivity() != null && !getActivity().isFinishing()) { + //系统版本大于等于android 9.0之后的版本 + if (Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT) { + Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT).show(); + } else { + if (mToast == null) { + mToast = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + mToast.setText(content); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.show(); + } + } + } + + protected void toastInCenter(int res) { + if (getActivity() != null && !getActivity().isFinishing()) { + String content = ""; + try { + content = getActivity().getString(res); + } catch (Resources.NotFoundException e) { + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toastInCenter(content); + } + } + + protected void toastInCenter(String content) { + if (!isAdded()) { + return; + } + if (getActivity() != null && !getActivity().isFinishing()) { + Toast toastInCenter = null; + //系统版本大于等于android 9.0之后的版本 + if (Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT) { + toastInCenter = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + if (mToastInCenter == null) { + mToastInCenter = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + mToastInCenter.setText(content); + mToastInCenter.setDuration(Toast.LENGTH_SHORT); + } + toastInCenter = mToastInCenter; + } + if (toastInCenter == null) return; + ViewGroup toastView = (ViewGroup) toastInCenter.getView(); + View imageCodeProject = toastView.getChildAt(0); + if (imageCodeProject != null && (imageCodeProject instanceof ImageView)) { + ((ImageView) imageCodeProject).setImageResource(0); + } + toastInCenter.show(); + } + } + + protected void toastWithImg(int strResId, int imgId) { + if (getActivity() != null && !getActivity().isFinishing()) { + String content = ""; + try { + content = getActivity().getString(strResId); + } catch (Resources.NotFoundException e) { + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toastWithImg(content, imgId); + } + } + + protected void toastWithImg(String content, int imgId) { + if (!isAdded()) { + return; + } + if (getActivity() != null && !getActivity().isFinishing()) { + Toast toastInCenter = null; + //系统版本大于等于android 9.0之后的版本 + if (Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT) { + toastInCenter = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + if (mToastWithImg == null) { + mToastWithImg = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); + } else { + mToastWithImg.setText(content); + mToastWithImg.setDuration(Toast.LENGTH_SHORT); + } + toastInCenter = mToastWithImg; + } + if (toastInCenter == null) return; + + toastInCenter.setGravity(Gravity.CENTER, 0, 0); + TextView tv = toastInCenter.getView().findViewById(android.R.id.message); + tv.setGravity(Gravity.CENTER); + tv.setTextColor(Color.WHITE); + tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17); + tv.setLineSpacing(0, 1.2f); + tv.setBackgroundResource(0); + // set padding + int paddingHorizontal = (int) getResources().getDimension(R.dimen.mobile_common_dp_10); + int paddingVertical = (int) getResources().getDimension(R.dimen.mobile_common_dp_10); + ViewGroup toastView = (ViewGroup) toastInCenter.getView(); + toastView.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); + toastView.setBackgroundResource(R.drawable.mobile_common_shape_round_bg); + if (imgId > 0) { + View imageCodeProject = toastView.getChildAt(0); + if (imageCodeProject == null || !(imageCodeProject instanceof ImageView)) { + imageCodeProject = new ImageView(getActivity()); + toastView.addView(imageCodeProject, 0); + } + ((ImageView) imageCodeProject).setImageResource(imgId); + } else { + View imageCodeProject = toastView.getChildAt(0); + if (imageCodeProject == null || !(imageCodeProject instanceof ImageView)) { + imageCodeProject = new ImageView(getActivity()); + toastView.addView(imageCodeProject, 0); + } + ((ImageView) imageCodeProject).setImageResource(0); + } + toastInCenter.show(); + } + + } + + + public boolean onBackPressed() { + return false; + } + + /********************** 注册广播 ****************************/ + private BroadcastReceiver broadcastReceiver = null; + + private void registerBroadCast() { + IntentFilter mIntentFilter = createBroadCast(); + if (mIntentFilter != null && mIntentFilter.countActions() > 0) { + broadcastReceiver = new BaseBroadcast(); + if (getActivity() != null) + getActivity().registerReceiver(broadcastReceiver, mIntentFilter); + } + } + + protected void unRegisterBroadCast() { + + if (broadcastReceiver != null) { + if (getActivity() != null) getActivity().unregisterReceiver(broadcastReceiver); + broadcastReceiver = null; + + } + } + + protected IntentFilter createBroadCast() { + return null; + } + + protected void onReceive(Context context, Intent intent) { + + } + + private class BaseBroadcast extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + BaseFragment.this.onReceive(context, intent); + } + } + + + protected final E getView(View rootView, int id) { + try { + return (E) rootView.findViewById(id); + } catch (ClassCastException e) { + LogUtil.errorLog("getView", "Cloud not cast view to concrete class.", e); + throw e; + } catch (NullPointerException e) { + LogUtil.errorLog("getView", "rootView is null.", e); + throw e; + } + } + + protected Handler addHandler(Handler handler) { + return mHandlerManager.addHandler(handler); + } + + protected V inflateViewStub(ViewStub viewStub, Class clz) { + V view; + if (viewStub.getParent() != null) { + view = (V) viewStub.inflate(); + viewStub.setTag(view); + } else { + view = (V) viewStub.getTag(); + } + return view; + } + + /** + * 是否已经inflate + * + * @param viewStub + * @return true表示已经inflate + */ + protected boolean isViewStubInflate(ViewStub viewStub) { + return viewStub.getParent() == null; + } + + /** + * 更新ViewStub是否可见 + * @param viewStub + * @param visible + */ + protected void updateViewStubVisibility(ViewStub viewStub, int visible) { + switch (visible) { + case View.VISIBLE: + inflateViewStub(viewStub, View.class).setVisibility(View.VISIBLE); + break; + default: + if (isViewStubInflate(viewStub)) { + inflateViewStub(viewStub, View.class).setVisibility(visible); + } + break; + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragmentActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragmentActivity.java new file mode 100644 index 0000000..835c218 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseFragmentActivity.java @@ -0,0 +1,366 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.app.ProgressDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.SystemClock; +import android.support.annotation.CallSuper; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.widget.TextView; +import android.widget.Toast; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.common.HandlerManager; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +public class BaseFragmentActivity extends FragmentActivity implements IActivityResultDispatch { + + private static final String TAG = "BaseFragmentActivity"; + private long mLastOnClickTime = 0; + protected Context mContext; + private ProgressDialog mProgressDialog; + private boolean onDetachedFromWindow = false; + private Toast mToastInCenter; + private Toast mToast; + private List mFragments = new ArrayList<>(); + private List mDialogFragments = new ArrayList<>(); + protected HandlerManager mHandlerManager; + private boolean isDestroyed = false; + + public synchronized List getBaseFragments() { + return mFragments; + } + protected synchronized void addBaseFragment(BaseFragment fragment){ + if(mFragments.contains(fragment)){ + return; + } + mFragments.add(fragment); + } + protected synchronized void removeBaseFragment(BaseFragment fragment){ + if(mFragments.contains(fragment)){ + mFragments.add(fragment); + } + } + + public synchronized List getDialogFragments() { + return mDialogFragments; + } + + protected synchronized void addBaseDialogFragment(BaseDialogFragment fragment){ + if(mDialogFragments.contains(fragment)){ + return; + } + mDialogFragments.add(fragment); + } + + protected synchronized void removeBaseDialogFragment(BaseDialogFragment fragment){ + if(mDialogFragments.contains(fragment)){ + mDialogFragments.remove(fragment); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(BaseEvent event){} + + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + mContext = this; + mProgressDialog = new ProgressDialog(mContext, R.style.mobile_common_custom_dialog); + Window window = mProgressDialog.getWindow(); + if(window != null){ + window.setWindowAnimations(R.style.mobile_common_dialog_anima); + } + mProgressDialog.setCanceledOnTouchOutside(false); + registerBroadCast(); + ActivityManager.getScreenManager().pushActivity(this); + getWindow().setBackgroundDrawable(null); + if(!EventBus.getDefault().isRegistered(this)){ + EventBus.getDefault().register(this); + } + mHandlerManager = new HandlerManager(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + onDetachedFromWindow = true; + } + + public boolean isDetachedFromWindow() { + return onDetachedFromWindow; + } + + public boolean isActivityDestory() { + return isDestroyed; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + isDestroyed = true; + unRegisterBroadCast(); + // 退出该页面时,手动清理内存缓存 + dissmissProgressDialog(); + mProgressDialog = null; + // ImageLoader.getInstance().clearMemoryCache(); + ActivityManager.getScreenManager().popActivity(this); + if(EventBus.getDefault().isRegistered(this)){ + EventBus.getDefault().unregister(this); + } + mHandlerManager.clearHandlers(); + listeners.clear(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + /********************** 注册广播 ****************************/ + private BroadcastReceiver broadcastReceiver = null; + + private void registerBroadCast() { + IntentFilter mIntentFilter = createBroadCast(); + if (mIntentFilter != null && mIntentFilter.countActions() > 0) { + broadcastReceiver = new BaseBroadcast(); + registerReceiver(broadcastReceiver, mIntentFilter); + } + } + + private void unRegisterBroadCast() { + if (broadcastReceiver != null) { + unregisterReceiver(broadcastReceiver); + broadcastReceiver = null; + } + } + + protected IntentFilter createBroadCast() { + return null; + } + + protected void onReceive(Context context, Intent intent) { + + } + + @Override + public void addOnActivityResultListener(IActivityResultDispatch.OnActivityResultListener listener) { + listeners.add(listener); + } + + @Override + public void removeOnActivityResultListener(IActivityResultDispatch.OnActivityResultListener listener) { + listeners.remove(listener); + } + + private class BaseBroadcast extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + BaseFragmentActivity.this.onReceive(context, intent); + } + } + + /** + *

+ * 检测快速双击事件 + *

+ * + * @return + */ + public Boolean isWindowLocked() { + long current = SystemClock.elapsedRealtime(); + if (current - mLastOnClickTime > 500) { + mLastOnClickTime = current; + return false; + } + return true; + } + + protected void dissmissProgressDialog() { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + } + } + + protected void showProgressDialog(int layoutId) { + if (mProgressDialog != null && !mProgressDialog.isShowing()) { + mProgressDialog.show(); + mProgressDialog.setContentView(layoutId); + } + } + + protected void cancleProgressDialog() { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.cancel(); + } + } + + protected void setProgressDialogCancle(boolean flag) { + if (mProgressDialog != null) { + mProgressDialog.setCancelable(flag); + } + } + + protected void toast(int res) { + String content =""; + try { + content = getString(res); + }catch (Resources.NotFoundException e){ + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toast(content); + } + + protected void toast(String content) { + //系统版本大于等于android 9.0之后的版本 + if(Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT){ + Toast.makeText(mContext,content,Toast.LENGTH_SHORT).show(); + }else{ + if (mToast == null) { + mToast = Toast.makeText(mContext, content, Toast.LENGTH_SHORT); + } else { + mToast.setText(content); + mToast.setDuration(Toast.LENGTH_SHORT); + } + mToast.show(); + } + } + + /** + * 带错误码的toast + * @param errorCode + */ + public void toast(int res, int errorCode) { + //系统版本大于等于android 9.0之后的版本 + if(Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT){ + Toast.makeText(mContext,getString(res) + "(" + errorCode + ")",Toast.LENGTH_SHORT).show(); + }else { + if (mToast == null) { + mToast = Toast.makeText(mContext, getString(res) + "(" + errorCode + ")", Toast.LENGTH_SHORT); + } else { + mToast.setText(getString(res) + "(" + errorCode + ")"); + } + mToast.show(); + } + } + + protected void toastInCenter(int res) { + String content =""; + try { + content = getString(res); + }catch (Resources.NotFoundException e){ + LogUtil.debugLog("toast", "resource id not found!!!"); + } + toastInCenter(content); + + } + + protected void toastInCenter(String content) { + //系统版本大于等于android 9.0之后的版本 + if(Build.VERSION_CODES.O_MR1 < Build.VERSION.SDK_INT){ + Toast toastInCenter = Toast.makeText(mContext, content, Toast.LENGTH_SHORT); + toastInCenter.setGravity(Gravity.CENTER, 0, 0); + TextView tv = toastInCenter.getView().findViewById(android.R.id.message); + tv.setGravity(Gravity.CENTER); + toastInCenter.show(); + + }else{ + if (mToastInCenter == null) { + mToastInCenter = Toast.makeText(mContext, content, Toast.LENGTH_SHORT); + mToastInCenter.setGravity(Gravity.CENTER, 0, 0); + TextView tv = mToastInCenter.getView().findViewById(android.R.id.message); + tv.setGravity(Gravity.CENTER); + } else { + mToastInCenter.setText(content); + mToastInCenter.setDuration(Toast.LENGTH_SHORT); + } + mToastInCenter.show(); + } + } + + @Override + public void startActivity(Intent intent) { + super.startActivity(intent); + overridePendingTransition(R.anim.mobile_common_slide_in_right, R.anim.mobile_common_slide_out_left); + } + + public void startActivityNoAnimation(Intent intent){ + super.startActivity(intent); + } + + @Override + public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { + super.startActivityFromFragment(fragment, intent, requestCode); + overridePendingTransition(R.anim.mobile_common_slide_in_right, R.anim.mobile_common_slide_out_left); + } + + @Override + public void startActivityForResult(Intent intent, int requestCode) { + super.startActivityForResult(intent, requestCode); + } + + public void startActivityForResultWithAnimation(Intent intent, int requestCode){ + super.startActivityForResult(intent, requestCode); + overridePendingTransition(R.anim.mobile_common_slide_in_right, R.anim.mobile_common_slide_out_left); + } + + @Override + public void finish() { + super.finish(); + overridePendingTransition( + R.anim.mobile_common_slide_left_back_in, + R.anim.mobile_common_slide_right_back_out); + } + + public void finishNoAnimation(){ + super.finish(); + } + + protected final E getView(int id){ + try{ + return (E) findViewById(id); + }catch (ClassCastException e){ + LogUtil.errorLog("getView","Cloud not cast view to concrete class.",e); + throw e; + } + } + + protected Handler addHandler(Handler handler){ + return mHandlerManager.addHandler(handler); + } + + @Override + @CallSuper + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + synchronized (listeners) { + for (OnActivityResultListener listener : listeners) { + if (listener != null) { + listener.onActivityResult(requestCode, resultCode, data); + } + } + + } + } + + private final List listeners = new ArrayList<>(); + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseHandler.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseHandler.java new file mode 100644 index 0000000..9be2335 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseHandler.java @@ -0,0 +1,76 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.utils.BusinessAuthUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 文件描述:文件名、类名 功能说明: 版权申明: + * + */ + +public abstract class BaseHandler extends Handler { + + private final static String TAG = "LeChange.BaseHandler"; + + private AtomicBoolean isCancled = new AtomicBoolean(false); + + public BaseHandler(){ + super(); + } + public BaseHandler(Looper looper){ + super(looper); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (!isCancled.get()) { + if (msg.what == HandleMessageCode.HMC_EXCEPTION) { + LogUtil.debugLog(TAG, "base hander throw exception. what =" + msg.what); + + if (BusinessAuthUtil.isAuthFailed(msg.arg1)) { + authError(msg); + return ; + } + } + handleBusiness(msg); + } + } + + /** + * 回调信息 + * + * @param msg + */ + public abstract void handleBusiness(Message msg); + + /** + * 鉴权信息失败 + */ + public void authError(Message msg) { + + } + + /** + * 取消数据回调 + */ + public void cancle() { + isCancled.set(true); + } + + /** + * 是否继续运行 + * + * @return + */ + public boolean isCanceled() { + return isCancled.get(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseMemoryCacheUseMap.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseMemoryCacheUseMap.java new file mode 100644 index 0000000..8289025 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseMemoryCacheUseMap.java @@ -0,0 +1,37 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 内存缓存 + */ + +public abstract class BaseMemoryCacheUseMap implements ICacheUseMap { + public Map cache= new ConcurrentHashMap<>(); + + @Override + public void clear(T1 key){ + cache.remove(key); + } + + @Override + public void put(T1 key, T2 data) { + cache.put(key, data); + } + + @Override + public void remove(T1 key) { + cache.remove(key); + } + + @Override + public void clearAll(){ + cache.clear(); + } + + @Override + public Map getList(){ + return cache; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseProvider.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseProvider.java new file mode 100644 index 0000000..604ddb8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseProvider.java @@ -0,0 +1,12 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +public class BaseProvider implements IBaseProvider { + public static final String TAG = "BaseProvider"; + @Override + public void uninit() { + LogUtil.debugLog(TAG,"unint"); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseSingleFragmentActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseSingleFragmentActivity.java new file mode 100644 index 0000000..7a8a9cf --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/BaseSingleFragmentActivity.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; + +import com.mm.android.deviceaddmodule.R; + +/** + * 只包含一个Fragment的Activity + */ +public abstract class BaseSingleFragmentActivity extends BaseFragmentActivity { + protected T mFragment; + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + setContentView(R.layout.mobile_common_comment); + if (arg0 == null) { + initContent(); + } + } + + protected abstract T createFragment(); + + protected void initContent() { + Bundle bundle = getIntent().getExtras(); + mFragment = createFragment(); + if(mFragment == null){ + return; + } + mFragment.setArguments(bundle); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.comment, mFragment); + transaction.commitAllowingStateLoss(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/DefaultPermissionListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/DefaultPermissionListener.java new file mode 100644 index 0000000..19157b7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/DefaultPermissionListener.java @@ -0,0 +1,19 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; + +/** + * 动态权限回调的默认实现类 + */ +public abstract class DefaultPermissionListener implements PermissionHelper.IPermissionListener { + + @Override + public boolean onDenied() { + return false; + } + + @Override + public void onGiveUp() { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IActivityResultDispatch.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IActivityResultDispatch.java new file mode 100644 index 0000000..f65fad2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IActivityResultDispatch.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.content.Intent; + +public interface IActivityResultDispatch { + public interface OnActivityResultListener { + /** + * callBack + * + * @param requestCode requestCode + * @param resultCode resultCode + * @param data data + */ + void onActivityResult(int requestCode, int resultCode, Intent data); + } + + public void addOnActivityResultListener(OnActivityResultListener listener); + + public void removeOnActivityResultListener(OnActivityResultListener listener); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IBaseProvider.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IBaseProvider.java new file mode 100644 index 0000000..ef76f1a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/IBaseProvider.java @@ -0,0 +1,8 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +public interface IBaseProvider{ + + //反初始化的 + public void uninit(); + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ICacheUseMap.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ICacheUseMap.java new file mode 100644 index 0000000..c3e49d5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ICacheUseMap.java @@ -0,0 +1,11 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import java.util.Map; + +public interface ICacheUseMap { + void put(T1 key, T2 data); //更新数据 + void clearAll(); //清除全部数据 + void clear(T1 key); //清除数据 + Map getList(); //获取数据 + void remove(T1 key); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/LCBusinessHandler.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/LCBusinessHandler.java new file mode 100644 index 0000000..ee16bc2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/LCBusinessHandler.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.os.Looper; +import android.os.Message; + +/** + * 网络请求基类,处理登出业务 + */ +public abstract class LCBusinessHandler extends BaseHandler{ + public LCBusinessHandler(){ + super(); + } + public LCBusinessHandler(Looper looper){ + super(looper); + } + @Override + public void authError(Message msg) { + super.authError(msg); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ProgressActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ProgressActivity.java new file mode 100644 index 0000000..cb10bde --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/ProgressActivity.java @@ -0,0 +1,25 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CloseProgressWindow; + +public class ProgressActivity extends BaseFragmentActivity { + + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + setContentView(R.layout.mobile_common_progressdialog_layout); + + setFinishOnTouchOutside(false); + } + + @Override + public void onMessageEvent(BaseEvent event) { + if(event instanceof CloseProgressWindow){ + finish(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonAdapter.java new file mode 100644 index 0000000..b6b0494 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonAdapter.java @@ -0,0 +1,91 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; + +import java.util.List; + +/** + *

+ * 适配器的基类 + *

+ */ +public abstract class CommonAdapter extends BaseAdapter { + protected List list; + + protected int layout; + + protected Context mContext; + + private int firstPosition;// 从头部插入的位置 + + public CommonAdapter(int layout, List list, Context mContext) { + this.list = list; + this.layout = layout; + this.mContext = mContext; + notifyDataSetChanged(); + } + + @Override + public int getCount() { + + return list.size(); + } + + @Override + public T getItem(int position) { + + return list.get(position); + } + + @Override + public long getItemId(int position) { + + return position; + } + + public void addFirstData(List list) { + this.list.addAll(firstPosition, list); + firstPosition = firstPosition + list.size(); + } + + public void addData(List list) { + if (list != null) { + this.list.addAll(list); + } + } + + public void removeData(List list) { + this.list.removeAll(list); + } + + public void clearData() { + this.list.clear(); + firstPosition = 0; + } + + public List getData() { + return list; + } + + public void replaceData(List list2) { + if (list2 != list) { + clearData(); + addData(list2); + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder = ViewHolder.getViewHolder(layout, convertView, mContext, parent); + convert(viewHolder, getItem(position), position, parent); + return viewHolder.getView(); + } + + public abstract void convert(ViewHolder viewHolder, T item, int position, ViewGroup parent); + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewAdapter.java new file mode 100644 index 0000000..c49dcb4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewAdapter.java @@ -0,0 +1,108 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +public abstract class CommonRecyclerViewAdapter extends RecyclerView.Adapter { + protected RecyclerView mRecyclerView; + protected List mList; //数据源集合 + protected Context mContext; + protected int mLayout; + protected RecyclerViewItemClickListener mRecylerViewItemClickListener; + + public CommonRecyclerViewAdapter(RecyclerView recyclerView, int layout) { + mRecyclerView = recyclerView; + mContext = mRecyclerView.getContext(); + mLayout = layout; + mList = new ArrayList<>(); + } + + /** + * 设置全新数据源 + * + * @param data + */ + public void setData(List data) { + if (data != null && !data.isEmpty()) { + mList = data; + } else {//传入的数据为空,则清空数据 + mList.clear(); + } + notifyDataSetChanged(); + } + + public void addData(List list) { + if (list != null) { + this.mList.addAll(list); + } + } + + public void clearData() { + this.mList.clear(); + } + + public void replaceData(List list2) { + if (list2 != mList) { + clearData(); + addData(list2); + } + notifyDataSetChanged(); + } + + public void setRecylerViewItemClickListener(RecyclerViewItemClickListener listener) { + mRecylerViewItemClickListener = listener; + } + + @Override + public CommonRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(mContext).inflate(viewType, parent, false); + CommonRecyclerViewHolder viewHolder = new CommonRecyclerViewHolder(mRecyclerView, itemView, mRecylerViewItemClickListener); + return viewHolder; + } + + @Override + public int getItemViewType(int position) { + if (mLayout == 0) { + throw new RuntimeException("no layout id"); + } + return mLayout; + } + + @Override + public void onBindViewHolder(CommonRecyclerViewHolder holder, int position) { + convert(holder, getItem(position), position); + } + + @Override + public int getItemCount() { + return mList.size(); + } + + + //填充数据 + public abstract void convert(CommonRecyclerViewHolder viewHolder, T item, int pos); + + public interface RecyclerViewItemClickListener { + void onRecylerViewItemClick(ViewGroup parent, View itemView, int position); + } + + public T getItem(int pos) { + return mList.get(pos); + } + + /** + * 获取数据源 + * + * @return + */ + public List getData() { + return mList; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewHolder.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewHolder.java new file mode 100644 index 0000000..86adc32 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/adapter/CommonRecyclerViewHolder.java @@ -0,0 +1,40 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.adapter; + +import android.support.v7.widget.RecyclerView; +import android.util.SparseArray; +import android.view.View; + +public class CommonRecyclerViewHolder extends RecyclerView.ViewHolder { + RecyclerView mRecylerView; + private SparseArray mViewArray; //控件集合 + + View mConvertView; + + public CommonRecyclerViewHolder(RecyclerView recyclerView, final View itemView, final CommonRecyclerViewAdapter.RecyclerViewItemClickListener listener) { + super(itemView); + mRecylerView = recyclerView; + mConvertView = itemView; + mViewArray = new SparseArray<>(); + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getId() == itemView.getId() && listener != null) { + listener.onRecylerViewItemClick(mRecylerView, itemView, getAdapterPosition()); + } + } + }); + } + + public T findViewById(int id) { + View view = mViewArray.get(id); + if (view == null) { + view = mConvertView.findViewById(id); + mViewArray.put(id, view); + } + return (T) view; + } + + public View getConvertView() { + return mConvertView; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/api/IProgressDialogControlView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/api/IProgressDialogControlView.java new file mode 100644 index 0000000..7747832 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/api/IProgressDialogControlView.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.api; + +import android.content.DialogInterface; +import android.support.annotation.LayoutRes; + +/** + * 控制显示等待框的接口 + */ + +public interface IProgressDialogControlView { + + /** + * 根据 id 显示 等待 + * @param layoutId + */ + void showProgressDialog(@LayoutRes int layoutId); + /** + * 隐藏等待 + */ + void dissmissProgressDialog(); + + /** + * 取消弹框 + */ + void cancleProgressDialog(); + + /** + * 设置是否可以取消 + * @param flag + */ + void setProgressDialogCancelable(boolean flag); + + void setProgressDialogCancelListener(DialogInterface.OnCancelListener cancelListener); + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseManagerFragmentActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseManagerFragmentActivity.java new file mode 100644 index 0000000..1bedc72 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseManagerFragmentActivity.java @@ -0,0 +1,99 @@ + +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.views.popwindow.BasePopWindow; +import com.mm.android.deviceaddmodule.views.popwindow.PopWindowFactory; + +/** + * 设备管理的FragmentActivity基类,主要重写全局等待框 + * 注:initView()需要手动实现 + */ + +public abstract class BaseManagerFragmentActivity extends BaseMvpFragmentActivity { + private BasePopWindow mLoadingPopWindow; + private PopWindowFactory mPopWindowFactory; + private View mTitle; + + protected abstract View initTitle(); + + @Override + protected void initView() { + mTitle = initTitle(); + } + + /** + * 修改时是否弹框提示未保存 + * @return + */ + protected boolean showUnSaveAlertDialog(){ + return false; + } + + private void showAlertDialog() { + LCAlertDialog.Builder builder = new LCAlertDialog.Builder(this); + LCAlertDialog alertDialog = builder + .setTitle(R.string.device_manager_not_saved_tip) + .setConfirmButton(R.string.device_manager_exit, + new LCAlertDialog.OnClickListener() { + + @Override + public void onClick(LCAlertDialog dialog, + int which, boolean isChecked) { + finish(); + } + }).setCancelButton(R.string.common_cancel, null) + .create(); + alertDialog.show(getSupportFragmentManager(), ""); + + } + + @Override + public void showProgressDialog() { + if (mTitle == null) { + super.showProgressDialog(); + } else { + if (mLoadingPopWindow != null) { + mLoadingPopWindow.dismiss(); + } + if (mPopWindowFactory == null) + mPopWindowFactory = new PopWindowFactory(); + try{ + mLoadingPopWindow = mPopWindowFactory.createLoadingPopWindow(this, mTitle); + }catch (Exception e){ + e.printStackTrace(); + } + } + } + + @Override + public void cancelProgressDialog() { + if (mLoadingPopWindow == null) { + super.cancelProgressDialog(); + } else { + mLoadingPopWindow.dismiss(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mLoadingPopWindow != null) { + mLoadingPopWindow.dismiss(); + mLoadingPopWindow = null; + mPopWindowFactory = null; + } + } + + @Override + public void onBackPressed() { + if(showUnSaveAlertDialog()){ + showAlertDialog(); + }else{ + super.onBackPressed(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpActivity.java new file mode 100644 index 0000000..b42820c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpActivity.java @@ -0,0 +1,85 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseActivity; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; + +/** + * 暂无需求。 + * MVP模式Activity基类,继承自common模块基类Acitivity,实现BaseView中通用接口,所有MVP模式的Activity需继承自此类。 + */ +public abstract class BaseMvpActivity extends BaseActivity implements IBaseView { + protected abstract void initLayout(); //初始化布局 + protected abstract void initView(); //初始化控件 + protected abstract void initData(); //初始化数据 + protected T mPresenter; + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initLayout(); + initView(); + initPresenter(); + initData(); + } + + @Override + protected void onDestroy() { + if(mPresenter != null) mPresenter.unInit(); + super.onDestroy(); + } + + public Context getContextInfo() { + return this; + } + + + public boolean isViewActive() { + return !isActivityDestory(); + } + + public void showToastInfo(String msg) { + toast(msg); + } + + public void showToastInfo(int msgId) { + toast(msgId); + } + + public void showToastInfo(int msgId, String errorDesc) { + if (!TextUtils.isEmpty(errorDesc)) { + toast(errorDesc); + } else { + toast(msgId); + } + } + + public void showProgressDialog() { + showProgressDialog(R.layout.mobile_common_progressdialog_layout); + } + + public void cancelProgressDialog() { + dissmissProgressDialog(); + } + + @Override + public void unInit() { + + } + + @Override + public void onMessageEvent(BaseEvent event) { + + } + + @Override + public void initPresenter() { + + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpFragmentActivity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpFragmentActivity.java new file mode 100644 index 0000000..670a16f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/BaseMvpFragmentActivity.java @@ -0,0 +1,89 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseFragmentActivity; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; + +/** + * MVP模式FragmentActivity基类,继承自common模块基类FragmentAcitivity,实现BaseView中通用接口,所有MVP模式的FragmentActivity需继承自此类。 + **/ +public abstract class BaseMvpFragmentActivity extends BaseFragmentActivity implements IBaseView { + + protected abstract void initLayout(); //初始化布局 + protected abstract void initView(); //初始化控件 + protected abstract void initData(); //初始化数据 + protected T mPresenter; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initPresenter(); + initData(); + initLayout(); + initView(); + } + + @Override + protected void onDestroy() { + if(mPresenter != null) mPresenter.unInit(); + super.onDestroy(); + } + + @Override + public Context getContextInfo() { + return this; + } + + @Override + public boolean isViewActive() { + return !isActivityDestory(); + } + + @Override + public void showToastInfo(String msg) { + toast(msg); + } + + @Override + public void showToastInfo(int msgId) { + toast(msgId); + } + + @Override + public void showToastInfo(int msgId, String errorDesc) { + if (!TextUtils.isEmpty(errorDesc)) { + toast(errorDesc); + } else { + toast(msgId); + } + } + + @Override + public void showProgressDialog() { + showProgressDialog(R.layout.mobile_common_progressdialog_layout); + } + + @Override + public void onMessageEvent(BaseEvent event) { + + } + + @Override + public void unInit() { + + } + + @Override + public void initPresenter() { + + } + + public void cancelProgressDialog() { + dissmissProgressDialog(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseModel.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseModel.java new file mode 100644 index 0000000..8262c7f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseModel.java @@ -0,0 +1,5 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +public interface IBaseModel { + void unInit(); //反初始化,以是否相关资源 +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBasePresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBasePresenter.java new file mode 100644 index 0000000..c9d54e0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBasePresenter.java @@ -0,0 +1,11 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +import android.content.Intent; + +/** + * MVP模式P层基类接口 + */ +public interface IBasePresenter { + void dispatchIntentData(Intent intent); //处理intent数据 + void unInit(); //反初始化,以释放相关资源 +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseView.java new file mode 100644 index 0000000..8267aff --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/base/mvp/IBaseView.java @@ -0,0 +1,31 @@ +package com.mm.android.deviceaddmodule.mobilecommon.base.mvp; + +import android.content.Context; + +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; + +/** + * MVP模式V层基类接口 + **/ +public interface IBaseView { + Context getContextInfo(); //获取上下文信息 + + boolean isViewActive(); //View层是否处于活动状态,是否已销毁 + + void showToastInfo(String msg); //Toast + + void showToastInfo(int msgId); //Toast + + void showToastInfo(int msgId, String errorDesc); //Toast + + void showProgressDialog(); //显示加载框 + void cancelProgressDialog(); //隐藏加载框 + + void onMessageEvent(BaseEvent event);//eventBus 消息通知 + + void unInit(); //反初始化,以释放相关资源 + + void initPresenter(); // 初始化presenter + + void finish(); //退出当前页 +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorCode.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorCode.java new file mode 100644 index 0000000..e85de83 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorCode.java @@ -0,0 +1,24 @@ +package com.mm.android.deviceaddmodule.mobilecommon.businesstip; + +public class BusinessErrorCode { + private final static int BEC_COMMON_BASE = 0; // 通用 + + private final static int BEC_DEVICE_BASE = 3000; // 设备管理模块 + + /** + * 未知错误 + */ + public final static int BEC_COMMON_UNKNOWN = BEC_COMMON_BASE + 1; // 未知错误 + + /** + * 业务空指针异常 + */ + public final static int BEC_COMMON_NULL_POINT = BEC_COMMON_BASE + 9; + + /** + * 连接超时异常 + */ + public final static int BEC_COMMON_TIME_OUT = BEC_COMMON_BASE + 11; + + public static final int BEC_DEVICE_ADD_AP_UPPER_LIMIT = BEC_DEVICE_BASE + 65; +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorTip.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorTip.java new file mode 100644 index 0000000..40f898c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/BusinessErrorTip.java @@ -0,0 +1,31 @@ +package com.mm.android.deviceaddmodule.mobilecommon.businesstip; + +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; + +public class BusinessErrorTip { + + public static String getErrorTip(Message message) { + String errorDesc = ""; + + if (message.obj != null && message.obj instanceof BusinessException) { + BusinessException exception = (BusinessException)message.obj; + if (!TextUtils.isEmpty(exception.errorDescription)) { + errorDesc = exception.errorDescription; + } + } + + return errorDesc; + } + + public static Throwable throwError(Message message) { + BusinessException exception=new BusinessException(); + if (message.obj != null && message.obj instanceof BusinessException) { + exception = (BusinessException)message.obj; + } + return new Throwable(exception.errorDescription); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/HandleMessageCode.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/HandleMessageCode.java new file mode 100644 index 0000000..d639c04 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/HandleMessageCode.java @@ -0,0 +1,9 @@ +package com.mm.android.deviceaddmodule.mobilecommon.businesstip; + +public class HandleMessageCode { + + private final static int HMC_EXCEPTION_BASE= 0; // 异常 + public final static int HMC_SUCCESS = HMC_EXCEPTION_BASE + 1;//执行成功 + public final static int HMC_EXCEPTION = HMC_EXCEPTION_BASE + 2;//执行失败 + public final static int HMC_BATCH_MIDDLE_RESULT = HMC_EXCEPTION_BASE + 3;//批量操作中间结果 +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/SMBErrorCode.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/SMBErrorCode.java new file mode 100644 index 0000000..ab22a58 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/businesstip/SMBErrorCode.java @@ -0,0 +1,13 @@ +package com.mm.android.deviceaddmodule.mobilecommon.businesstip; + + +public class SMBErrorCode { + public static final int SUCCESS = 10000; //成功 + + //踢出相关错误码 + public static final int REQUEST_AUTHORITY_ERROR = 10001; //鉴权服务异常 + public static final int REQUEST_INVALID_TOKEN = 10003; //无效的登录信息 + public static final int REQUEST_LOGIN_EXPIRED = 10005; //登录过期 + public static final int REQUEST_SIGNATURE_FORMAT_ERROR = 10015; //接口签名类型不合规 + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/Constants.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/Constants.java new file mode 100644 index 0000000..592ba1b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/Constants.java @@ -0,0 +1,7 @@ +package com.mm.android.deviceaddmodule.mobilecommon.common; + +public interface Constants { + + public static final int PERMISSION_REQUEST_ID = 11; + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/HandlerManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/HandlerManager.java new file mode 100644 index 0000000..38811ba --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/HandlerManager.java @@ -0,0 +1,69 @@ +package com.mm.android.deviceaddmodule.mobilecommon.common; + +import android.os.Handler; +import android.os.Message; +import android.support.annotation.NonNull; + +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseHandler; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +/** + * Handler管理类,方便界面创建匿名Handler,防止内存泄露 + */ +public class HandlerManager { + public static final String TAG = "HandlerManager"; + private List mHandlers; + + public HandlerManager(){ + mHandlers = new ArrayList<>(); + } + + public static class WrapHandler extends Handler{ + //真正外部使用的Handler,强引用防止回收,等处理之后解除引用 + private Handler mTarget; + private WeakReference> mHandlers; + public WrapHandler(Handler target,WeakReference> handlers){ + mTarget = target; + mHandlers = handlers; + } + + public Handler getTartgetHandler(){ + return mTarget; + } + + @Override + public void handleMessage(Message msg) { + if(mTarget != null){ + mTarget.handleMessage(msg); + } + List handlers = mHandlers.get(); + if(handlers != null){ + //执行结束删除对应Handler + handlers.remove(this); + } + } + } + + private WrapHandler wrapHandler(@NonNull Handler handler){ + return new WrapHandler(handler, new WeakReference<>(mHandlers)); + } + + public Handler addHandler(@NonNull final Handler handler){ + WrapHandler wrapHandler = wrapHandler(handler); + mHandlers.add(wrapHandler); + return wrapHandler; + } + + public void clearHandlers(){ + //取消数据回调 + for(Handler h : mHandlers){ + if(h instanceof BaseHandler){ + ((BaseHandler) h).cancle(); + } + } + mHandlers.clear(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/LCConfiguration.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/LCConfiguration.java new file mode 100644 index 0000000..84cce2d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/LCConfiguration.java @@ -0,0 +1,79 @@ +package com.mm.android.deviceaddmodule.mobilecommon.common; + + +public class LCConfiguration { + + public static final int APP_LECHANGE = 0; + public static final int APP_LECHANGE_OVERSEA = 1; + + public static final String SHOW_ADD_BOX_TIP = "show_add_box_tip"; + + public static final String TYPE = "TYPE"; + + public static final String TYPE_TP1 = "TP1"; + + public static final String TYPE_TC1 = "TC1"; + + public static final String TYPE_TK1 = "TK1"; + + public static final String TYPE_TC3 = "TC3"; + + public static final String TYPE_TK3 = "TK3"; + + public static final String TYPE_TC4 = "TC4"; + + public static final String TYPE_TC5 = "TC5"; + + public static final String TYPE_TC5S = "TC5S"; + + public static final String TYPE_TP6 = "TP6"; + + public static final String TYPE_TP6C = "TP6C"; + + public static final String TYPE_TC6 = "TC6"; + + public static final String TYPE_TC6C = "TC6C"; + + public static final String TYPE_TP7 = "TP7"; + + public static final String DEVICE_SNCODE = "DEVICE_SNCODE"; + + public static final String DEVICE_MODEL = "DEVICE_MODEL"; + + public static final String CHANNEL_INDEX = "CHANNEL_INDEX"; + + public static final String CONNECTIVITY_CHAGET_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; + + + public static final String DEVICESN_PARAM = "device_param"; + public static final String DEVICE_IMEI_PARAM = "device_imei_param"; + public static final String HUB_PAIR_PARAM = "hub_pair_param"; + public static final String HUB_TYPE_PARAM = "hub_type_param"; //hub配对 + public static final String OFFLINE_CONFIG_TYPE_PARAM = "offline_config_param";//离线配置 + public static final String SC_CODE_PARAM = "sc_code_param"; + public static final String DEVICE_PWD_PARAM = "device_pwd_param"; + + public static final String DEVICE_MODEL_NAME_PARAM = "device_model_name_param"; //设备市场型号 + public static final String IS_DEVICE_DETAIL_PARAM = "is_device_detail_param"; // 是否为中间页添加 + + public static final String TAG = "STEP"; + + public static final String DEVICE_NET_INFO_EX = "DEVICE_NET_INFO_EX"; + + public static final String Device_ID = "device_id"; + public final static String SUPPORT_5G = "SUPPORT_5G"; //支持5Gwifi + + public static final String AP_ID = "ap_id"; + + public static final String COMMON_SOURCE_INFO = "commonSourceInfo"; + public static final String COMMON_CURRENT_SELECTED_INDEX = "commonCurrentSelectedIndex"; + public static final String COMMON_SELECT_DIALOG_TITLE = "commonSelectDialogTitle"; + public static final String COMMON_SELECT_DIALOG_DESCRIPTION = "commonSelectDialogDescription"; + + public static final String UNKNOWN_SSID = ""; + public static final String SSID = "SSID"; + + + public final static String BUNDLE_DEVICE_ADD_INFO ="BUNDLE_DEVICE_ADD_INFO";//蓝牙锁添加设备传对象到蓝牙锁模块 + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/PermissionHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/PermissionHelper.java new file mode 100644 index 0000000..c301eb6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/PermissionHelper.java @@ -0,0 +1,214 @@ +package com.mm.android.deviceaddmodule.mobilecommon.common; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.mobilecommon.utils.AppUtils; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * 动态权限二次封装帮助类,切记不可在onResume里使用 + */ +public class PermissionHelper { + public static final int REQUEST_CODE_PERMISSION = 0X123; + private FragmentActivity mActivity; + + public PermissionHelper(FragmentActivity activity) { + mActivity = activity; + } + + /** + * 如果在fragment使用,必须传fragment,而非getActivity + * + * @param fragment + */ + public PermissionHelper(Fragment fragment) { + mActivity = fragment.getActivity(); + } + + /** + * 是否有指定权限 + * + * @param permission + * @return + */ + public boolean hasPermission(String permission) { + if (TextUtils.isEmpty(permission)) { + return false; + } + return ContextCompat.checkSelfPermission(mActivity, permission) == PackageManager.PERMISSION_GRANTED; + } + + /** + * 是否始终允许位置权限,兼容Q系统 + * + * @return + */ + /*public boolean hasAlawaysLocationPermission() { + if (CommonHelper.isAndroidQOrLater()) { + return hasPermission(Manifest.permission.ACCESS_FINE_LOCATION) && hasPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION); + } else { + return hasPermission(Manifest.permission.ACCESS_FINE_LOCATION); + } + }*/ + + public void requestPermissions(String[] permissions, final IPermissionListener listener) { + //存放待授权的权限 + List permissionList = new ArrayList<>(); + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(mActivity, permission) != PackageManager.PERMISSION_GRANTED) { + permissionList.add(permission); + } + } + if (permissionList.isEmpty()) { //集合为空,则都已授权 + if (listener != null) { + listener.onGranted(); + return; + } + } else { //不为空,去授权 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (AppUtils.getTargetSdkVersion(mActivity) >= Build.VERSION_CODES.M) { + mActivity.requestPermissions(permissionList.toArray(new String[permissionList.size()]), Constants.PERMISSION_REQUEST_ID); + } + } + } + } + + public void gotoSettingPage(String[] permission, final IPermissionListener listener) { + LCAlertDialog.Builder builder = new LCAlertDialog.Builder(mActivity); + builder.setTitle(R.string.mobile_common_permission_apply) + .setCancelable(false) + .setMessage(getExplain(permission[0])) + .setCancelButton(R.string.mobile_common_common_ignore, new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, boolean isChecked) { + if (listener != null) { + listener.onGiveUp(); + } + } + }) + .setConfirmButton(R.string.go_to_setting, + new LCAlertDialog.OnClickListener() { + + @Override + public void onClick(LCAlertDialog dialog, + int which, boolean isChecked) { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", mActivity.getPackageName(), null)); + mActivity.startActivityForResult(intent, REQUEST_CODE_PERMISSION); + dialog.dismiss(); + } + }); + LCAlertDialog dialog = builder.create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(mActivity.getSupportFragmentManager(), null); + } + + /** + * 自定义提示信息框 + * + * @param tip + */ + public void showCustomTip(String tip, LCAlertDialog.OnClickListener listener) { + LCAlertDialog.Builder builder = new LCAlertDialog.Builder(mActivity); + builder.setTitle(R.string.mobile_common_permission_apply) + .setCancelable(false) + .setMessage(tip) + .setCancelButton(R.string.mobile_common_common_ignore, listener) + .setConfirmButton(R.string.go_to_setting, + new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, boolean isChecked) { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", mActivity.getPackageName(), null)); + mActivity.startActivityForResult(intent, REQUEST_CODE_PERMISSION); + dialog.dismiss(); + } + }); + LCAlertDialog dialog = builder.create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(mActivity.getSupportFragmentManager(), null); + } + + /** + * 根据不同的权限提示不同的文案内容 + * + * @param permission + * @return + */ + public String getExplain(String permission) { + String explain = mActivity.getString(R.string.mobile_common_lack_permission_then_exit); + switch (permission) { + case Manifest.permission.READ_CONTACTS: + explain = mActivity.getString(R.string.mobile_common_permission_explain_get_accounts); + break; + + case Manifest.permission.WRITE_CONTACTS: + explain = mActivity.getString(R.string.mobile_common_permission_explain_write_accounts); + break; + + case Manifest.permission.CALL_PHONE: + explain = mActivity.getString(R.string.mobile_common_permission_explain_read_phone_state); + break; + + case Manifest.permission.CAMERA: + explain = mActivity.getString(R.string.mobile_common_permission_explain_camera); + break; + + case Manifest.permission.ACCESS_FINE_LOCATION: + explain = mActivity.getString(R.string.mobile_common_permission_explain_access_location_usage); + break; + + case Manifest.permission.ACCESS_COARSE_LOCATION: + explain = mActivity.getString(R.string.mobile_common_permission_explain_access_location_usage); + break; + + case Manifest.permission.WRITE_EXTERNAL_STORAGE: + explain = mActivity.getString(R.string.mobile_common_permission_explain_external_storage); + break; + + case Manifest.permission.RECORD_AUDIO: + explain = mActivity.getString(R.string.mobile_common_permission_explain_record_audio); + break; + + /*case Manifest.permission.ACCESS_BACKGROUND_LOCATION: + explain = mActivity.getString(R.string.geofence_backgroud_location_permission_explain); + break;*/ + } + return explain; + } + + public interface IPermissionListener { + /** + * 授权成功 + */ + void onGranted(); + + /** + * 授权失败 + * + * @return true:调用者自己处理 false:默认处理,弹出需要权限的原因,引导用户跳转到设置页面 + */ + boolean onDenied(); + + /** + * 引导用户跳转到设置页时,用户点击取消 + */ + void onGiveUp(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/ViewHolder.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/ViewHolder.java new file mode 100644 index 0000000..6cfffbf --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/common/ViewHolder.java @@ -0,0 +1,40 @@ +package com.mm.android.deviceaddmodule.mobilecommon.common; + +import android.content.Context; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class ViewHolder { + private View mContent; + + private SparseArray sparseArray; + + public static ViewHolder getViewHolder(int layout, View mContent, Context mContext, ViewGroup parent) { + ViewHolder viewHolder; + if (mContent == null) { + viewHolder = new ViewHolder(); + mContent = LayoutInflater.from(mContext).inflate(layout, parent, false); + mContent.setTag(viewHolder); + viewHolder.mContent = mContent; + viewHolder.sparseArray = new SparseArray<>(); + } else { + viewHolder = (ViewHolder) mContent.getTag(); + } + return viewHolder; + } + + public T findViewById(int id) { + T view = (T) sparseArray.get(id); + if (view == null) { + view = mContent.findViewById(id); + sparseArray.put(id, view); + } + return view; + } + + public View getView() { + return mContent; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/CommonRollSelectDialog.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/CommonRollSelectDialog.java new file mode 100644 index 0000000..8dc9543 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/CommonRollSelectDialog.java @@ -0,0 +1,162 @@ +package com.mm.android.deviceaddmodule.mobilecommon.dialog; + +import android.content.DialogInterface; +import android.content.DialogInterface.OnKeyListener; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.AnticipateOvershootInterpolator; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseDialogFragment; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.AbstractWheel; +import com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.OnWheelChangedListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters.ArrayWheelAdapter; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +/** + * 单项选择框建议使用SingleWheelPickerDialog(优化滚轮体验) + */ +@Deprecated +public class CommonRollSelectDialog extends BaseDialogFragment implements OnKeyListener { + + private TextView mTitle; + private TextView mConfirmBtn; + private AbstractWheel mVerticalWheel; + private TextView mDescription; + private OnClickListener mConfirmListener; + private int mSelectedIndex; + private String[] mWheelData;// wheel 数据源 + + public static CommonRollSelectDialog newInstance(String dialogTitle, int selectIndex, String description, TreeMap choiceMap) { + CommonRollSelectDialog dialog = new CommonRollSelectDialog(); + Bundle bundle = new Bundle(); + bundle.putString(LCConfiguration.COMMON_SELECT_DIALOG_TITLE,dialogTitle); + bundle.putSerializable(LCConfiguration.COMMON_SOURCE_INFO, choiceMap); + bundle.putSerializable(LCConfiguration.COMMON_CURRENT_SELECTED_INDEX, selectIndex); + bundle.putString(LCConfiguration.COMMON_SELECT_DIALOG_DESCRIPTION, description); + dialog.setArguments(bundle); + return dialog; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(STYLE_NORMAL, R.style.mobile_common_checks_dialog); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.mobile_common_roll_select_dialog, null); + initView(view); + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getDialog().setCanceledOnTouchOutside(true); + + Window win = getDialog().getWindow(); + if (win != null) { + win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams localLayoutParams = win.getAttributes(); + localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + localLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + localLayoutParams.gravity = Gravity.BOTTOM; + getDialog().getWindow().setAttributes(localLayoutParams); + } + } + + private void initView(View rootView) { + + mTitle = rootView.findViewById(R.id.center_title); + mVerticalWheel = rootView.findViewById(R.id.wheel_vertical_view); + mDescription = rootView.findViewById(R.id.description); + mConfirmBtn = rootView.findViewById(R.id.confirm_btn); + TextView cancelButton = rootView.findViewById(R.id.cancel_btn); + + cancelButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + + mConfirmBtn.setOnClickListener(mConfirmListener); + initData(); + } + + private void initData() { + Bundle bundle = getArguments(); + if (bundle == null) return; + + TreeMap map = (TreeMap) bundle.getSerializable(LCConfiguration.COMMON_SOURCE_INFO); + mSelectedIndex = bundle.getInt(LCConfiguration.COMMON_CURRENT_SELECTED_INDEX, -1); + String description = bundle.getString(LCConfiguration.COMMON_SELECT_DIALOG_DESCRIPTION, ""); + if (map == null || map.size() == 0 || mSelectedIndex == -1) return; + + String title = bundle.getString(LCConfiguration.COMMON_SELECT_DIALOG_TITLE, ""); + + List keyList = new ArrayList<>(map.keySet()); + mWheelData = new String[keyList.size()]; + for (int i = 0; i < keyList.size(); i++) { + Integer key = keyList.get(i); + if (map.get(key) != null) { + mWheelData[i] = map.get(key); + } + } + + mTitle.setText(title); + mDescription.setText(description); + + initWheels(); + } + + private void initWheels() { + + mVerticalWheel.setViewAdapter(new ArrayWheelAdapter(getActivity(), mWheelData, R.layout.wheel_text, R.id.text)); + mVerticalWheel.setCyclic(false); + mVerticalWheel.setInterpolator(new AnticipateOvershootInterpolator()); + mVerticalWheel.addChangingListener(new OnWheelChangedListener() { + + @Override + public void onChanged(AbstractWheel wheel, int oldValue, int newValue) { + mSelectedIndex = newValue; + } + }); + mVerticalWheel.setCurrentItem(mSelectedIndex); + + } + + public void setConfirmButtonClickListener(OnClickListener listener) { + mConfirmListener = listener; + } + + public int getCurrentSelectedIndex() { + return mSelectedIndex; + } + + @Override + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { + dismissAllowingStateLoss(); + return false; + } + return false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/LCAlertDialog.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/LCAlertDialog.java new file mode 100644 index 0000000..d9f9ab7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/dialog/LCAlertDialog.java @@ -0,0 +1,485 @@ +package com.mm.android.deviceaddmodule.mobilecommon.dialog; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.res.Configuration; +import android.graphics.Paint; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseDialogFragment; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; + +public class LCAlertDialog extends BaseDialogFragment implements OnClickListener { + + public static final int CANCEL_BUTTON = 0; + + public static final int CONFIRM_BUTTON = 1; + + public static final int MESSAGE2_TEXT = 2; + + private CharSequence mMessage; + + private CharSequence mMessage2; + + private String mTitle; + + private int mTitleColor = -1; + + private String mNagativeBtnName; + + private String mPositiveBtnName; + + private boolean mIsCheckBoxEnable = false; + + private String mCheckBoxText; + + private OnClickListener mMessage2BtnListener; + + private OnClickListener mNagativeBtnListener; + + private OnClickListener mPositiveBtnListener; + + private OnDismissListener mDismissListener; + + private TextView mTitleTv; + + private TextView mMessageTv; + + private TextView mMessageTv2; + + private CheckBox mNeverRemindBtn; + + private TextView mLeftBtn; + + private TextView mRightBtn; + + private LinearLayout mTwoButtonLayout; + + private TextView mSingleBtn; + + public interface DialogShowListener { + public void onShow(); + } + + private DialogShowListener mDialogShowListener; + + public interface OnClickListener { + public void onClick(LCAlertDialog dialog, int which, boolean isChecked); + } + + boolean canCanceledOnTouchOutside = false; + + public void setCanceledOnTouchOutside(boolean canCanceledDialogOnTouchOutside) { + canCanceledOnTouchOutside = canCanceledDialogOnTouchOutside; + } + + private void setMessage(CharSequence message) { + mMessage = message; + } + + private void setMessage2(CharSequence message2, OnClickListener listener) { + mMessage2 = message2; + mMessage2BtnListener = listener; + } + + private void setTitle(String message) { + mTitle = message; + } + + private void setTitleColor(int titleColor) { + mTitleColor = titleColor; + } + + private void setNegativeButton(String name, OnClickListener l) { + mNagativeBtnName = name; + + mNagativeBtnListener = l; + } + + private void setPositiveButton(String name, OnClickListener l) { + mPositiveBtnName = name; + + mPositiveBtnListener = l; + } + + private void setOnDismissListener(OnDismissListener l) { + mDismissListener = l; + } + + private void setDialogShowListener(DialogShowListener l) { + mDialogShowListener = l; + } + + private void setCheckBoxEnable(boolean isEnable) { + mIsCheckBoxEnable = isEnable; + } + + private void setCheckBoxText(String name) { + mCheckBoxText = name; + } + + public static LCAlertDialog newInstance() { + return new LCAlertDialog(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NORMAL, R.style.mobile_common_checks_dialog); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.mobile_common_lc_alert_dialog_layout, null); + initView(view); + if (mDialogShowListener != null) { + mDialogShowListener.onShow(); + } + return view; + } + + @Override + public void onResume() { + super.onResume(); + translationUp(); + } + + private void translationUp() { + if (getActivity() != null && !getActivity().isFinishing()) { + WindowManager.LayoutParams params = null; + try { + params = getDialog().getWindow().getAttributes(); + } catch (Exception e) { + } + if (params != null) { + params.y = (int) -(100 * UIUtils.getScreenDensity(getActivity()) / 3.0f); + DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); + int configure = getResources().getConfiguration().orientation; + if (configure == Configuration.ORIENTATION_PORTRAIT) { + params.width = metrics.widthPixels * 4 / 5; + } else if (configure == Configuration.ORIENTATION_LANDSCAPE) { + params.width = metrics.heightPixels * 4 / 5; + } else { + params.width = metrics.widthPixels * 4 / 5; + } + + getDialog().getWindow().setAttributes(params); + } + + } + + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getDialog().setCanceledOnTouchOutside(canCanceledOnTouchOutside); + } + + private void initView(View rootView) { + // rootView.setMinimumWidth(UIUtils.getDefaultDialogWidth(getActivity())); + mTitleTv = rootView.findViewById(R.id.tv_title); + mMessageTv = rootView.findViewById(R.id.tv_message); + mMessageTv2 = rootView.findViewById(R.id.tv_message2); + mMessageTv2.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); //下划线 + mMessageTv2.getPaint().setAntiAlias(true);//抗锯齿 + mMessageTv2.setTextColor(getActivity().getResources().getColor(R.color.c5)); + mLeftBtn = rootView.findViewById(R.id.tv_left_btn); + mRightBtn = rootView.findViewById(R.id.tv_right_btn); + mSingleBtn = rootView.findViewById(R.id.tv_single_btn); + mNeverRemindBtn = rootView.findViewById(R.id.rb_never_remind); + + mMessageTv2.setOnClickListener(this); + mNeverRemindBtn.setOnClickListener(this); + mLeftBtn.setOnClickListener(this); + mRightBtn.setOnClickListener(this); + mSingleBtn.setOnClickListener(this); + + mTwoButtonLayout = rootView.findViewById(R.id.two_button_layout); + + if (!TextUtils.isEmpty(mTitle)) { + mTitleTv.setVisibility(View.VISIBLE); + mTitleTv.setText(mTitle); + } else { + mTitleTv.setVisibility(View.GONE); + } + + if (mTitleColor != -1) { + mTitleTv.setTextColor(mTitleColor); + } + + if (!TextUtils.isEmpty(mMessage)) { + mMessageTv.setVisibility(View.VISIBLE); + mMessageTv.setText(mMessage); + } else { + mMessageTv.setVisibility(View.GONE); + } + + if (!TextUtils.isEmpty(mMessage2)) { + mMessageTv2.setVisibility(View.VISIBLE); + mMessageTv2.setText(mMessage2); + } else { + mMessageTv2.setVisibility(View.GONE); + } + + if (!TextUtils.isEmpty(mNagativeBtnName) && !TextUtils.isEmpty(mPositiveBtnName)) { + mTwoButtonLayout.setVisibility(View.VISIBLE); + mSingleBtn.setVisibility(View.GONE); + + mLeftBtn.setText(mNagativeBtnName); + mRightBtn.setText(mPositiveBtnName); + + } else { + mTwoButtonLayout.setVisibility(View.GONE); + mSingleBtn.setVisibility(View.VISIBLE); + mSingleBtn.setOnClickListener(this); + if (!TextUtils.isEmpty(mNagativeBtnName)) { + mSingleBtn.setText(mNagativeBtnName); + } else if (!TextUtils.isEmpty(mPositiveBtnName)) { + mSingleBtn.setText(mPositiveBtnName); + } + } + + if (mIsCheckBoxEnable) { + mNeverRemindBtn.setVisibility(View.VISIBLE); + } + + if (!TextUtils.isEmpty(mCheckBoxText)) { + mNeverRemindBtn.setText(mCheckBoxText); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (mDismissListener != null) { + mDismissListener.onDismiss(dialog); + } + if (mNeverRemindBtn != null) mNeverRemindBtn.setOnClickListener(null); + if (mLeftBtn != null) mLeftBtn.setOnClickListener(null); + if (mRightBtn != null) mRightBtn.setOnClickListener(null); + if (mSingleBtn != null) mSingleBtn.setOnClickListener(null); + mDismissListener = null; + mDialogShowListener = null; + mPositiveBtnListener = null; + mNagativeBtnListener = null; + mMessage2BtnListener = null; + } + + @Override + public void onClick(View v) { + + int i = v.getId(); + if (i == R.id.tv_left_btn) { + + if (mNagativeBtnListener != null) { + mNagativeBtnListener.onClick(this, CANCEL_BUTTON, mNeverRemindBtn.isChecked()); + } + dismissAllowingStateLoss(); + + } else if (i == R.id.tv_right_btn) { + + if (mPositiveBtnListener != null) { + mPositiveBtnListener.onClick(this, CONFIRM_BUTTON, mNeverRemindBtn.isChecked()); + } + dismissAllowingStateLoss(); + + } else if (i == R.id.tv_single_btn) { + + if (!TextUtils.isEmpty(mNagativeBtnName)) { + if (mNagativeBtnListener != null) { + mNagativeBtnListener.onClick(this, CANCEL_BUTTON, mNeverRemindBtn.isChecked()); + } + } else if (!TextUtils.isEmpty(mPositiveBtnName)) { + if (mPositiveBtnListener != null) { + mPositiveBtnListener.onClick(this, CONFIRM_BUTTON, mNeverRemindBtn.isChecked()); + } + } + dismissAllowingStateLoss(); + } else if (i == R.id.rb_never_remind) {// mNeverRemindBtn.setChecked(!mNeverRemindBtn.isChecked()); + + } else if (i == R.id.tv_message2) { + if (mMessage2BtnListener != null) { + mMessage2BtnListener.onClick(this, MESSAGE2_TEXT, mNeverRemindBtn.isChecked()); + } + } + } + + public static class Builder { + + private Context mContext; + + private CharSequence mMessage; + + private CharSequence mMessage2; + + private String mTitle; + + private int mTitleColor = -1; + + private String mNagativeBtnName; + + private String mPositiveBtnName; + + private String mCheckBoxText; + + private boolean mIsCheckBoxEnable = false; + + private OnClickListener mMessage2TextListener; + + private OnClickListener mNagativeBtnListener; + + private OnClickListener mPositiveBtnListener; + + private OnDismissListener mDismissListener; + private DialogShowListener mDialogShowListener; + + //点击返回键默认可以取消弹框 + private boolean mCancelable = true; + + public Builder(Context context) { + mContext = context; + } + + public Builder setCancelable(boolean cancelable) { + this.mCancelable = cancelable; + return this; + } + + public Builder setMessage(int resId) { + mMessage = mContext.getResources().getString(resId); + return this; + } + + public Builder setMessage(CharSequence message) { + mMessage = message; + return this; + } + + public Builder setMessage2(int resId, OnClickListener l) { + mMessage2 = mContext.getResources().getString(resId); + mMessage2TextListener = l; + return this; + } + + public Builder setMessage2(CharSequence message) { + mMessage2 = message; + return this; + } + + public Builder setTitle(int resId) { + mTitle = mContext.getResources().getString(resId); + return this; + } + + public Builder setTitle(String message) { + mTitle = message; + return this; + } + + public Builder setTitleColor(int resId) { + mTitleColor = mContext.getResources().getColor(resId); + return this; + } + + public Builder setCancelButton(int resId, OnClickListener l) { + mNagativeBtnName = mContext.getResources().getString(resId); + + mNagativeBtnListener = l; + + return this; + } + + public Builder setConfirmButton(int resId, OnClickListener l) { + mPositiveBtnName = mContext.getResources().getString(resId); + + mPositiveBtnListener = l; + + return this; + } + + public Builder setConfirmButton(String resText, OnClickListener l) { + mPositiveBtnName = resText; + mPositiveBtnListener = l; + + return this; + } + + public Builder setOnDismissLisenter(OnDismissListener l) { + mDismissListener = l; + return this; + } + + public Builder setDialogShowListener(DialogShowListener showListener) { + mDialogShowListener = showListener; + return this; + } + + public Builder setCheckBoxEnable(boolean isEnable) { + mIsCheckBoxEnable = isEnable; + + return this; + } + + public Builder setCheckBoxText(int resId) { + mCheckBoxText = mContext.getResources().getString(resId); + mIsCheckBoxEnable = true; + return this; + } + + public LCAlertDialog create() { + LCAlertDialog dialog = LCAlertDialog.newInstance(); + if (mDismissListener != null) { + dialog.setOnDismissListener(mDismissListener); + } + if (!TextUtils.isEmpty(mTitle)) { + dialog.setTitle(mTitle); + } + if (mTitleColor != -1) { + dialog.setTitleColor(mTitleColor); + } + + if (!TextUtils.isEmpty(mMessage)) { + dialog.setMessage(mMessage); + } + + if (!TextUtils.isEmpty(mMessage2)) { + dialog.setMessage2(mMessage2, mMessage2TextListener); + } + + if (!TextUtils.isEmpty(mNagativeBtnName)) { + dialog.setNegativeButton(mNagativeBtnName, mNagativeBtnListener); + } + + if (!TextUtils.isEmpty(mPositiveBtnName)) { + dialog.setPositiveButton(mPositiveBtnName, mPositiveBtnListener); + } + if (mDialogShowListener != null) { + dialog.setDialogShowListener(mDialogShowListener); + } + if (!TextUtils.isEmpty(mCheckBoxText)) { + dialog.setCheckBoxText(mCheckBoxText); + } + + dialog.setCheckBoxEnable(mIsCheckBoxEnable); + + dialog.setCancelable(mCancelable); + + return dialog; + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddApResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddApResult.java new file mode 100644 index 0000000..a6a573b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddApResult.java @@ -0,0 +1,76 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity; + +public class AddApResult extends DataInfo{ + private boolean isExist; //配件是否存在(配件是否上报了硬件信息) + private String apName; //配件名称 + private String apType; //配件的类型 + private String apModel; //配件的型号 + private String apVersion; //配件的版本号 + private int apStatus; //配件的在线状态:1-在线 0-离线 + private String apEnable; //配件的使能:on-使能开启 ,off-使能关闭 + private int ioType; //配件输入输出类型,-1:未知 0-输入 1-输出 + + public boolean isExist() { + return isExist; + } + + public void setExist(boolean exist) { + isExist = exist; + } + + public String getApName() { + return apName; + } + + public void setApName(String apName) { + this.apName = apName; + } + + public String getApType() { + return apType; + } + + public void setApType(String apType) { + this.apType = apType; + } + + public String getApModel() { + return apModel; + } + + public void setApModel(String apModel) { + this.apModel = apModel; + } + + public String getApVersion() { + return apVersion; + } + + public void setApVersion(String apVersion) { + this.apVersion = apVersion; + } + + public int getApStatus() { + return apStatus; + } + + public void setApStatus(int apStatus) { + this.apStatus = apStatus; + } + + public String getApEnable() { + return apEnable; + } + + public void setApEnable(String apEnable) { + this.apEnable = apEnable; + } + + public int getIoType() { + return ioType; + } + + public void setIoType(int ioType) { + this.ioType = ioType; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddContact.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddContact.java new file mode 100644 index 0000000..30e8997 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/AddContact.java @@ -0,0 +1,38 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity; + +import java.util.List; + +public class AddContact extends DataInfo { + + private String name; + private List numbers; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getNumbers() { + return numbers; + } + + public void setNumbers(List numbers) { + this.numbers = numbers; + } + + public static class NumbersBean extends DataInfo{ + + private String phone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/DataInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/DataInfo.java new file mode 100644 index 0000000..2d533ea --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/DataInfo.java @@ -0,0 +1,78 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity; + +import java.io.Serializable; +import java.util.Hashtable; +import java.util.UUID; + + +/** + * 文件描述:实体基类,支持克隆、序列化 + */ + +public class DataInfo implements Cloneable, Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + protected String uuid = UUID.randomUUID().toString(); // 对象唯一标示 + public Hashtable getExtandAttributeTable() { + if(extandAttributeTable == null){ + extandAttributeTable = new Hashtable<>(); + } + return extandAttributeTable; + } + protected Hashtable extandAttributeTable = null; // 扩展属性列表 + + + // 获得扩展属性值 + public Object getExtandAttributeValue(String name) + { + if (extandAttributeTable == null + || !extandAttributeTable.containsKey(name)) + { + return null; + } + + return extandAttributeTable.get(name); + } + + // 设置扩展属性 + public void setExtandAttributeValue(String name, Object value) + { + if (extandAttributeTable == null) + { + extandAttributeTable = new Hashtable<>(); + } + if(value != null){ + extandAttributeTable.put(name, value); + } + } + + public String getUuid() { + return uuid; + } + + @Override + public String toString() { + return uuid; + } + + + @Override + protected Object clone() throws CloneNotSupportedException + { + DataInfo dataInfo = null; + + dataInfo = (DataInfo) super.clone(); + + if (extandAttributeTable != null) { + dataInfo.extandAttributeTable = new Hashtable<>(); + dataInfo.extandAttributeTable.putAll(extandAttributeTable); + + } + + return dataInfo; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/device/DHDevice.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/device/DHDevice.java new file mode 100644 index 0000000..ceb16f9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/device/DHDevice.java @@ -0,0 +1,78 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity.device; + +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceState; +import com.mm.android.deviceaddmodule.mobilecommon.entity.DataInfo; + +/** + * 设备结构体 + */ +public class DHDevice extends DataInfo implements Cloneable { + private String deviceId; // 设备序列号 + private String name; // 设备名称 + private String status; // online-在线 offline-在线 upgrading-升级中 sleep-休眠 + private String wifiTransferMode; + + public String getWifiTransferMode() { + return wifiTransferMode; + } + + public void setWifiTransferMode(String wifiTransferMode) { + this.wifiTransferMode = wifiTransferMode; + } + + public DHDevice() { + status = DeviceState.OFFLINE; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isOnline() { + return !DeviceState.OFFLINE.equalsIgnoreCase(status); + } + + public String getStatus() { + return status; + } + + public void setStatus(@DeviceState String status) { + this.status = status; + } + + // 设备接入类型 + public enum AccessType { + PaaS, // 表示Paas程序接入 + Lechange, // 表示乐橙非PaaS设备 + Easy4IP, // 表示Easy4IP程序设备 + P2P // 表示P2P程序设备 + } + + @Override + public DHDevice clone() { + DHDevice dhDevice = null; + + try { + dhDevice = (DHDevice) super.clone(); + + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return dhDevice; + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceAddInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceAddInfo.java new file mode 100644 index 0000000..f3392ae --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceAddInfo.java @@ -0,0 +1,614 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd; + +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.entity.DataInfo; + +import java.io.Serializable; + + +/** + * 设备添加模块设备信息存储类 + */ +public class DeviceAddInfo extends DataInfo { + public static final int NC_TYPE_SOUND_WAVE_V2 = 1; // 新声波 + + + public static class GatewayInfo implements Serializable { //若是添加配件,存储对应的网关信息 + String sn; + String ability; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getAbility() { + return ability; + } + + public void setAbility(String ability) { + this.ability = ability; + } + + @Override + public String toString() { + return "GatewayInfo{" + + "sn='" + sn + '\'' + + ", ability='" + ability + '\'' + + '}'; + } + } + + public class WifiInfo implements Serializable { + String ssid = ""; + String pwd = ""; + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getPwd() { + return pwd; + } + + public void setPwd(String pwd) { + this.pwd = pwd; + } + + @Override + public String toString() { + return "WifiInfo{" + + "ssid='" + ssid + '\'' + + ", pwd='" + pwd + '\'' + + '}'; + } + } + + public class GPSInfo implements Serializable { + String longitude; + String latitude; + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + @Override + public String toString() { + return "GPSInfo{" + + "longitude='" + longitude + '\'' + + ", latitude='" + latitude + '\'' + + '}'; + } + } + + //设备配网模式 + public enum ConfigMode { + SmartConfig, // SmartConfig方式 + SoundWave, // 声波方式 + SoftAP, // 软AP方式 + LAN, // 有线局域网 + // SIMCard, // SIMCARD方式 + QRCode, // 二维码 + SoundWaveV2, // 声波V2版本,优化声波算法 + Location, //设备本地配网 + Bluetooth, //设备本地配网 + NBIOT //NB配网 + } + + //设备绑定状态 + public enum BindStatus { + bindByMe, //被当前帐户绑定 + bindByOther, //被其他帐户绑定 + unbind //未被绑定 + } + + //设备状态 + public enum Status { + online, //在线 + offline, //离线 + upgrading, //升级中 + sleep //休眠 + } + + //设备类型 + public enum DeviceType { + ap, //配件 + device //配件外的设备 + } + + public enum DeviceAddType { + SOFTAP, //软AP添加 + AP, //配件添加 + // SIMCARD, //SIM卡添加 + HUB, //HUB配对 + WLAN, //无线 + LAN, //有线 + ONLINE, //在线 + LOCAL, //设备本地配网 + NBIOT, //NB配网 + Bluetooth; //设备本地配网 + } + + boolean support = true; //是否支持绑定 + String deviceSn; //设备序列号 + String deviceCodeModel; //二维码中扫描得到的设备型号 + boolean deviceExist; //设备是否在服务上注册 + String bindStatus; //设备绑定状态 + String bindAcount; //设备绑定帐号 + String accessType = "PaaS"; //设备接入类型 PaaS-表示Paas程序接入、Lechange-表示乐橙非PaaS设备、Easy4IP表示Easy4IP程序设备、P2P表示P2P程序设备 + String status; //设备状态 + String configMode; //配对模式SmartConfig,SoundWave,SoftAP,LAN,SIMCard + boolean wifiConfigModeOptional = false; //true,表示可让用户自行选择可用的配网模式 小微这边没有这个配置功能,默认false + String wifiTransferMode; //wifi频段2.4Ghz,5Ghz + + String imeiCode = ""; // iot设备唯一标识码 + String deviceDefaultName; //设备默认名,绑定成功后服务返回 + String regCode; //设备安全码,国内乐橙乐盒设备才有 + String nc; // 设备二维码上的能力,之前的QR(二维码配网)不在支持,目前使用为新声波使用 + WifiInfo wifiInfo = new WifiInfo(); //无线配置当前wifi信息 + String curConfigMode = ConfigMode.SmartConfig.name(); //当前配对模式 + String devicePwd; //设备密码 + + String recordSaveDays; // 录像保存天数(免费套餐信息,设备有可赠送免费套餐时返回) + String streamType; // 码流类型:main:主码流extra1:辅码流(免费套餐信息,设备有可赠送免费套餐时返回) + String serviceTime; //服务时长(秒)(免费套餐信息,设备有可赠送免费套餐时返回) + + boolean isWifiOfflineMode = false; //是否为wifi离线配置 + GPSInfo gpsInfo = new GPSInfo(); + GatewayInfo gatewayInfo; + DeviceAddType curDeviceAddType = DeviceAddType.WLAN; //当前添加流程类型 + + DeviceIntroductionInfo mDevIntroductionInfo; //设备添加引导信息 + + boolean isDeviceDetail = false; // 是否为中间页添加 + + private String sc; // 设备安全验证码 + + private String requestId; + + private boolean isManualInput; // 手动输入序列号进入 + + private String ssid; //软ap添加时,设备的SSID + + private String previousSsid; //连接软ap之前的ssid,方便退出软ap流程时恢复网络 + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + private long startTime; // + + //TODO SMB这里字段的默认值和上层判断逻辑需要处理 + //**********************网络获取缺失的字段********************************// + String brand; //设备品牌信息lechange-乐橙设备,general-通用设备, 海外:dahua-大华设备,general-通用设备 + String family; //设备系列 + String deviceModel; //设备型号 + String modelName; //型号名称 + String catalog; //设备大类 + String ability; //设备能力项 + String type; //设备分类,ap配件device设备 + int channelNum; //视频通道的总数量(包含未接入的通道),网关的通道数可能为0 + private String watchSetupVideoUrl; //String 可选 视频地址,海外3.100新增 + private String port; // String 可选 设备私有协议端口,海外使用 + //**********************网络获取缺失的字段********************************// + + + public String getDeviceSn() { + return deviceSn == null ? "" : deviceSn; + } + + public void setDeviceSn(String deviceSn) { + this.deviceSn = deviceSn; + } + + public String getDeviceCodeModel() { + return deviceCodeModel == null ? "" : deviceCodeModel; + } + + public void setDeviceCodeModel(String deviceCodeModel) { + this.deviceCodeModel = deviceCodeModel; + } + + public boolean isDeviceInServer() { + return deviceExist; + } + + public boolean isP2PDev() { //是否为P2P设备 + return "p2p".equalsIgnoreCase(accessType); + } + + public boolean isEasy4ipP2PDev() { //是否为Easy4ip及P2P设备 + return "p2p".equalsIgnoreCase(accessType) + || "easy4ip".equalsIgnoreCase(accessType); + } + + public boolean getDeviceExist() { + return deviceExist; + } + + public void setDeviceExist(boolean deviceExist) { + this.deviceExist = deviceExist; + } + + public String getBindStatus() { + return bindStatus == null ? "" : bindStatus; + } + + public void setBindStatus(String bindStatus) { + this.bindStatus = bindStatus; + } + + public String getBindAcount() { + return bindAcount == null ? "" : bindAcount; + } + + public void setBindAcount(String bindAcount) { + this.bindAcount = bindAcount; + } + + public String getAccessType() { + return accessType == null ? "" : accessType; + } + + public void setAccessType(String accessType) { + this.accessType = accessType; + } + + public String getStatus() { + return status == null ? "" : status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getConfigMode() { + return configMode == null ? "" : configMode; + } + + public void setConfigMode(String configMode) { + this.configMode = configMode; + } + + public String getBrand() { + return brand == null ? "" : brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public String getFamily() { + return family == null ? "" : family; + } + + public void setFamily(String family) { + this.family = family; + } + + public String getDeviceModel() { + return deviceModel == null ? "" : deviceModel; + } + + public void setDeviceModel(String deviceModel) { + this.deviceModel = deviceModel; + } + + public String getModelName() { + return modelName == null ? "" : modelName; + } + + public void setModelName(String modelName) { + this.modelName = modelName; + } + + public String getCatalog() { + return catalog == null ? "" : catalog; + } + + public void setCatalog(String catalog) { + this.catalog = catalog; + } + + public String getType() { + return type == null ? "" : type; + } + + public void setType(String type) { + this.type = type; + } + + public String getWifiTransferMode() { + return wifiTransferMode == null ? "" : wifiTransferMode; + } + + public void setWifiTransferMode(String wifiTransferMode) { + this.wifiTransferMode = wifiTransferMode; + } + + public String getRegCode() { + return regCode == null ? "" : regCode; + } + + public void setRegCode(String regCode) { + this.regCode = regCode; + } + + public String getNc() { + return nc; + } + + public void setNc(String nc) { + this.nc = nc; + } + + public DeviceIntroductionInfo getDevIntroductionInfo() { + return mDevIntroductionInfo; + } + + public void setDevIntroductionInfos(DeviceIntroductionInfo devIntroductionInfo) { + this.mDevIntroductionInfo = devIntroductionInfo; + } + + public WifiInfo getWifiInfo() { + return wifiInfo; + } + + public void setWifiInfo(WifiInfo wifiInfo) { + this.wifiInfo = wifiInfo; + } + + public String getCurConfigMode() { + return curConfigMode == null ? "" : curConfigMode; + } + + public void setCurConfigMode(String curConfigMode) { + this.curConfigMode = curConfigMode; + } + + public String getDevicePwd() { + return devicePwd == null ? "" : devicePwd; + } + + public void setDevicePwd(String devicePwd) { + this.devicePwd = devicePwd; + } + + public boolean isWifiOfflineMode() { + return isWifiOfflineMode; + } + + public void setWifiOfflineMode(boolean wifiOfflineMode) { + isWifiOfflineMode = wifiOfflineMode; + } + + public String getImeiCode() { + return imeiCode; + } + + public void setImeiCode(String imeiCode) { + this.imeiCode = imeiCode; + } + + public int getChannelNum() { + return channelNum; + } + + public void setChannelNum(int channelNum) { + this.channelNum = channelNum; + } + + public GPSInfo getGpsInfo() { + return gpsInfo; + } + + public String getAbility() { + return ability == null ? "" : ability; + } + + public void setAbility(String ability) { + this.ability = ability; + } + + public GatewayInfo getGatewayInfo() { + return gatewayInfo; + } + + public void setGatewayInfo(GatewayInfo gatewayInfo) { + this.gatewayInfo = gatewayInfo; + } + + public String getDeviceDefaultName() { + return deviceDefaultName == null ? "" : deviceDefaultName; + } + + public void setDeviceDefaultName(String deviceDefaultName) { + this.deviceDefaultName = deviceDefaultName; + } + + public DeviceAddType getCurDeviceAddType() { + return curDeviceAddType; + } + + public void setCurDeviceAddType(DeviceAddType curDeviceAddType) { + this.curDeviceAddType = curDeviceAddType; + } + + public boolean hasAbility(@DeviceAbility String ability) { + return !TextUtils.isEmpty(this.ability) && this.ability.contains(ability); + } + + public void clearCache() { + wifiInfo.setPwd(null); + wifiInfo.setSsid(null); + curDeviceAddType = DeviceAddType.WLAN; + } + + public String getRecordSaveDays() { + return recordSaveDays; + } + + public void setRecordSaveDays(String recordSaveDays) { + this.recordSaveDays = recordSaveDays; + } + + public String getStreamType() { + return streamType; + } + + public void setStreamType(String streamType) { + this.streamType = streamType; + } + + public String getServiceTime() { + return serviceTime; + } + + public void setServiceTime(String serviceTime) { + this.serviceTime = serviceTime; + } + + public boolean isDeviceDetail() { + return isDeviceDetail; + } + + public void setDeviceDetail(boolean deviceDetail) { + isDeviceDetail = deviceDetail; + } + + public String getSc() { + return sc; + } + + public void setSc(String sc) { + this.sc = sc; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + + public boolean isManualInput() { + return isManualInput; + } + + public void setManualInput(boolean manualInput) { + isManualInput = manualInput; + } + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getPreviousSsid() { + return previousSsid; + } + + public void setPreviousSsid(String previousSsid) { + this.previousSsid = previousSsid; + } + + public String getWatchSetupVideoUrl() { + return watchSetupVideoUrl; + } + + public void setWatchSetupVideoUrl(String watchSetupVideoUrl) { + this.watchSetupVideoUrl = watchSetupVideoUrl; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public boolean isWifiConfigModeOptional() { + return wifiConfigModeOptional; + } + + public void setWifiConfigModeOptional(boolean wifiConfigModeOptional) { + this.wifiConfigModeOptional = wifiConfigModeOptional; + } + + public boolean isSupport() { + return support; + } + + public void setSupport(boolean support) { + this.support = support; + } + + @Override + public String toString() { + return "DeviceAddInfo{" + + "deviceSn='" + deviceSn + '\'' + + ", deviceCodeModel='" + deviceCodeModel + '\'' + + ", deviceExist='" + deviceExist + '\'' + + ", bindStatus='" + bindStatus + '\'' + + ", bindAcount='" + bindAcount + '\'' + + ", accessType='" + accessType + '\'' + + ", status='" + status + '\'' + + ", configMode='" + configMode + '\'' + + ", brand='" + brand + '\'' + + ", family='" + family + '\'' + + ", deviceModel='" + deviceModel + '\'' + + ", modelName='" + modelName + '\'' + + ", catalog='" + catalog + '\'' + + ", ability='" + ability + '\'' + + ", type='" + type + '\'' + + ", wifiTransferMode='" + wifiTransferMode + '\'' + + ", deviceDefaultName='" + deviceDefaultName + '\'' + + ", regCode='" + regCode + '\'' + + ", nc='" + nc + '\'' + + ", wifiInfo=" + wifiInfo + + ", curConfigMode='" + curConfigMode + '\'' + + ", devicePwd='" + devicePwd + '\'' + + ", isWifiOfflineMode=" + isWifiOfflineMode + + ", gpsInfo=" + gpsInfo + + ", gatewayInfo=" + gatewayInfo + + ", curDeviceAddType=" + curDeviceAddType + + ", mDevIntroductionInfo=" + mDevIntroductionInfo + + ",sc=" + sc + + ",requestId=" + requestId + + ",isManualInput=" + isManualInput + + ", ssid=" + ssid + + ", previousSsid=" + previousSsid + + '}'; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceBindResult.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceBindResult.java new file mode 100644 index 0000000..131def8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceBindResult.java @@ -0,0 +1,67 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd; + +import java.io.Serializable; + +/** + * 设备绑定结果信息类 + */ +public class DeviceBindResult implements Serializable { + String deviceName; //绑定成功返回设备默认名称 + String bindStatus; //绑定状态,bindByMe,bindByOther + String userAccount; //绑定帐号 + + //TODO SMB + //*********************接口不返回,要处理下默认逻辑*************************// + String recordSaveDays; // 录像保存天数(免费套餐信息,设备有可赠送免费套餐时返回) + String streamType; // 码流类型:main:主码流extra1:辅码流(免费套餐信息,设备有可赠送免费套餐时返回) + String serviceTime; //服务时长(秒)(免费套餐信息,设备有可赠送免费套餐时返回) 上层使用的时候,展示的是天 + //*********************接口不返回,要处理下默认逻辑*************************// + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getBindStatus() { + return bindStatus; + } + + public void setBindStatus(String bindStatus) { + this.bindStatus = bindStatus; + } + + public String getUserAccount() { + return userAccount; + } + + public void setUserAccount(String userAccount) { + this.userAccount = userAccount; + } + + public String getRecordSaveDays() { + return recordSaveDays; + } + + public void setRecordSaveDays(String recordSaveDays) { + this.recordSaveDays = recordSaveDays; + } + + public String getStreamType() { + return streamType; + } + + public void setStreamType(String streamType) { + this.streamType = streamType; + } + + public String getServiceTime() { + return serviceTime; + } + + public void setServiceTime(String serviceTime) { + this.serviceTime = serviceTime; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceIntroductionInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceIntroductionInfo.java new file mode 100644 index 0000000..404e3a7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceIntroductionInfo.java @@ -0,0 +1,55 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * 设备添加引导信息存储类 + **/ +public class DeviceIntroductionInfo implements Serializable { + String updateTime; //更新时间 + String language; //存储语言 + String deviceModel; //设备类型 + HashMap imageInfos; //图片信息 + HashMap strInfos; //文案信息 + + public HashMap getImageInfos() { + return imageInfos; + } + + public void setImageInfos(HashMap imageInfos) { + this.imageInfos = imageInfos; + } + + public HashMap getStrInfos() { + return strInfos; + } + + public void setStrInfos(HashMap strInfos) { + this.strInfos = strInfos; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getDeviceModel() { + return deviceModel; + } + + public void setDeviceModel(String deviceModel) { + this.deviceModel = deviceModel; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceTypeInfo.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceTypeInfo.java new file mode 100644 index 0000000..7f0fb18 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/entity/deviceadd/DeviceTypeInfo.java @@ -0,0 +1,69 @@ +package com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd; + +import com.mm.android.deviceaddmodule.mobilecommon.entity.DataInfo; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 设备类型信息类,大类包含多个小类 + **/ +public class DeviceTypeInfo extends DataInfo { + String updateTime; + String language; + LinkedHashMap> modelMap; + //设备详细类型数据结构 + public static class DeviceModelInfo extends DataInfo{ + String deviceType; //分类名称,摄像机Camera, 门锁DoorBell, 报警器AlarmDevice, 网关Gateway, 硬盘录像机DVR + String deviceModelName; //设备型号名称,APP展示使用 + String deviceImageURI; //设备正视图(图片尺寸参考UI)的URI + + public String getDeviceModelName() { + return deviceModelName; + } + + public void setDeviceModelName(String deviceModelName) { + this.deviceModelName = deviceModelName; + } + + public String getDeviceImageURI() { + return deviceImageURI; + } + + public void setDeviceImageURI(String deviceImageURI) { + this.deviceImageURI = deviceImageURI; + } + + public String getDeviceType() { + return deviceType; + } + + public void setDeviceType(String deviceType) { + this.deviceType = deviceType; + } + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public LinkedHashMap> getModelMap() { + return modelMap; + } + + public void setModelMap(LinkedHashMap> modelMap) { + this.modelMap = modelMap; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/BaseEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/BaseEvent.java new file mode 100644 index 0000000..87dc99d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/BaseEvent.java @@ -0,0 +1,21 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +/** + * EventBus消息基类 + */ + +public class BaseEvent { + private String code; + + public BaseEvent(String code){ + this.code=code; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseProgressWindow.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseProgressWindow.java new file mode 100644 index 0000000..53b8a89 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseProgressWindow.java @@ -0,0 +1,9 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +public class CloseProgressWindow extends BaseEvent { + + + public CloseProgressWindow(String code) { + super(code); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseTimeFilterEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseTimeFilterEvent.java new file mode 100644 index 0000000..95f309d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CloseTimeFilterEvent.java @@ -0,0 +1,7 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +public class CloseTimeFilterEvent { + public CloseTimeFilterEvent(){ + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CommonEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CommonEvent.java new file mode 100644 index 0000000..1c64767 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/CommonEvent.java @@ -0,0 +1,32 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +import android.os.Bundle; + +/** + * 跨模块通用事件 + **/ +public class CommonEvent extends BaseEvent{ + Bundle bundle; + public static String REFRESH_SINGLE_DEVICE_SYNC_ACTION="refresh_single_device_sync_action"; //刷新单个设备,从服务 + + public static String AP_PAIR_SUCCEED_2_MAIN_ACTION = "ap_pair_succeed_2_main_action"; //添加配件完成(回主页) + public static String AP_PAIR_SUCCEED_2_MID_ACTION = "ap_pair_succeed_2_mid_action"; //添加配件完成(回中间页) + public static String DEVICE_ADD_SUCCESS_ACTION = "device_add_success_action"; //设备添加成功 + + + public CommonEvent(String code) { + super(code); + } + + public CommonEvent(String code,Bundle bundle) { + super(code); + this.bundle = bundle; + } + public Bundle getBundle() { + return bundle; + } + + public void setBundle(Bundle bundle) { + this.bundle = bundle; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/DefaultCachePool.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/DefaultCachePool.java new file mode 100644 index 0000000..dc487cb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/DefaultCachePool.java @@ -0,0 +1,54 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +import java.util.ArrayList; +import java.util.List; + + +public class DefaultCachePool implements ICachePool{ + + private static final int DEFAULT_MAX_POOL_SIZE = 1000; + + private final List cachePool; + + private int maxPoolSize = DEFAULT_MAX_POOL_SIZE; + + private Class cls; + + public DefaultCachePool(Class cls, int maxPoolSize) + { + cachePool = new ArrayList<>(); + this.maxPoolSize = maxPoolSize; + this.cls = cls; + } + + @Override + public T obtain() + { + synchronized (cachePool) { + int size = cachePool.size(); + if (size > 0) { + return cachePool.remove(size - 1); + } + } + + T obj = null; + + try { + obj = cls.newInstance(); + } catch (Exception e) { + obj = null; + } + + return obj; + } + + @Override + public void recycle(T o) + { + synchronized (cachePool) { + if (cachePool.size() < maxPoolSize) { + cachePool.add(o); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/Event.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/Event.java new file mode 100644 index 0000000..787dad5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/Event.java @@ -0,0 +1,378 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; + + +public final class Event implements Parcelable{ + + private static final int MAX_POOL_SIZE = 1000; + + private final static ICachePool cachePool = new DefaultCachePool<>(Event.class, MAX_POOL_SIZE); + + private int eventId; + + private int arg1; + + private int arg2; + + private Object obj; + + private String posterId; + + private Bundle extras; + + private Bundle data = new Bundle(); + + public Event() + { + } + + public Event(int eventId) { + this.eventId = eventId; + } + + public Event(int eventId, int arg1) { + this.eventId = eventId; + this.arg1 = arg1; + } + + public Event(int eventId, int arg1, int arg2) + { + this.eventId = eventId; + this.arg1 = arg1; + this.arg2 = arg2; + } + + public Event(int eventId, int arg1, int arg2, Object obj) + { + this.eventId = eventId; + this.arg1 = arg1; + this.arg2 = arg2; + this.obj = obj; + } + + public Event(int eventId, Bundle extras) { + this.eventId = eventId; + this.extras = extras; + } + + public static Event obtain(int eventId) { + Event event = cachePool.obtain(); + + if (event == null) { + event = new Event(); + } + + event.setEventId(eventId); + + return event; + } + + + public void recycle() + { + clearForRecycle(); + cachePool.recycle(this); + } + + public void copyFrom(Event e) { + this.eventId = e.eventId; + this.arg1 = e.arg1; + this.arg2 = e.arg2; + this.obj = e.obj; + this.posterId = e.posterId; + this.data = (Bundle)data.clone(); + if (e.extras != null) { + this.extras = (Bundle) e.extras.clone(); + } else { + this.extras = null; + } + } + + void clearForRecycle() { + eventId = 0; + arg1 = 0; + arg2 = 0; + obj = null; + posterId = null; + if (this.extras != null) { + extras.clear(); + extras = null; + } + this.data.clear(); + } + + public void setPosterId(String id) { + posterId = id; + } + + public String getPosterId() { + return posterId; + } + + public void putString(String key, String value) + { + data.putString(key, value); + } + + public void putInt(String key, int value) + { + data.putInt(key, value); + } + + public void putShort(String key, short value) + { + data.putShort(key, value); + } + + public void putBoolean(String key, boolean value) + { + data.putBoolean(key, value); + } + + public void putDouble(String key, double value) + { + data.putDouble(key, value); + } + + public void putParcelable(String key, Parcelable value) + { + data.putParcelable(key, value); + } + + + public void putSerializable(String key, Serializable value) + { + data.putSerializable(key, value); + } + + public void putBundle(String key, Bundle value) + { + data.putBundle(key, value); + } + + public String getString(String key) + { + return data.getString(key); + } + + public int getInt(String key) + { + return data.getInt(key); + } + + public short getShort(String key) + { + return data.getShort(key); + } + + public boolean getBoolean(String key) + { + return data.getBoolean(key); + } + + public double getDouble(String key) + { + return data.getDouble(key); + } + + public Parcelable getParcelable(String key) + { + return data.getParcelable(key); + } + + public Serializable getSerializable(String key) + { + return data.getSerializable(key); + } + + public Bundle getBundle(String key) + { + return data.getBundle(key); + } + + public Object get(String key) + { + return data.get(key); + + } + + public boolean containsKey(String key) + { + return data.containsKey(key); + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + + b.append("{ eventId="); + b.append(eventId); + + if (arg1 != 0) { + b.append(" arg1="); + b.append(arg1); + } + + if (arg2 != 0) { + b.append(" arg2="); + b.append(arg2); + } + + if (obj != null) { + b.append(" obj="); + b.append(obj); + } + + if (posterId != null) { + b.append("posterId ="); + b.append(posterId); + } + + if (extras != null) { + b.append(" extras="); + b.append(extras.toString()); + } + + b.append(" data="); + b.append(data.toString()); + + b.append(" }"); + + return b.toString(); + } + + public Object getObject() + { + return obj; + } + + public void setObject(Object object) + { + this.obj = object; + } + + public Bundle getExtras() + { + return extras; + } + + public int getEventId() + { + return eventId; + } + + public int getArg1() + { + return arg1; + } + + public void setArg1(int arg1) + { + this.arg1 = arg1; + } + + public int getArg2() + { + return arg2; + } + + public void setArg2(int arg2) + { + this.arg2 = arg2; + } + + public void setEventId(int eventId) + { + this.eventId = eventId; + } + + public void setExtras(Bundle bundle) + { + this.extras = bundle; + } + + @Override + public int describeContents() + { + + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeInt(eventId); + dest.writeInt(arg1); + dest.writeInt(arg2); + Bundle bundle = new Bundle(); + + if (posterId != null) { + dest.writeString(posterId); + } + + if (obj != null) { + try { + if (obj instanceof Parcelable) { + Parcelable p = (Parcelable) obj; + bundle.putParcelable("obj", p); + } else if (obj instanceof Serializable) { + Serializable p = (Serializable) obj; + bundle.putSerializable("obj", p); + } + + } catch (ClassCastException e) { + throw new RuntimeException("Can't marshal non-Parcelable objects across setObject()."); + } + } + + if (extras != null) { + bundle.putBundle("extras", extras); + } + + bundle.putBundle("data", data); + + dest.writeBundle(bundle); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Event createFromParcel(Parcel source) { + Event event = new Event(); + event.readFromParcel(source); + return event; + } + + public Event[] newArray(int size) { + return new Event[size]; + } + }; + + private void readFromParcel(Parcel source) { + eventId = source.readInt(); + arg1 = source.readInt(); + arg2 = source.readInt(); + posterId = source.readString(); + /* if (source.readInt() != 0) { + obj = source.readParcelable(getClass().getClassLoader()); + }*/ + Bundle bundle = source.readBundle(); + + if (bundle.containsKey("obj")) { + obj = bundle.getParcelable("obj"); + if (obj == null) { + obj = bundle.getSerializable("obj"); + } + + } + + if (bundle.containsKey("extras")) { + extras = bundle.getBundle("extras"); + } + + data = bundle.getBundle("data"); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/ICachePool.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/ICachePool.java new file mode 100644 index 0000000..438c21b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/ICachePool.java @@ -0,0 +1,9 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +public interface ICachePool { + + public abstract T obtain(); + + public abstract void recycle(T o); + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetWorkChangeCheckEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetWorkChangeCheckEvent.java new file mode 100644 index 0000000..f98e909 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetWorkChangeCheckEvent.java @@ -0,0 +1,5 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +public class NetWorkChangeCheckEvent { + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetworkChangeEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetworkChangeEvent.java new file mode 100644 index 0000000..e669132 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NetworkChangeEvent.java @@ -0,0 +1,19 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + + +public class NetworkChangeEvent { + public static boolean mIsShowPlayNetworkTip = false; + + public static boolean mIsShowShareNetworkTip = true; + + public static boolean mIsShowDownloadNetworkTip = true; + + public final String networkType; + public final String lastNetworkType; + public final boolean isNetworkAvailable; + public NetworkChangeEvent(String networkType, String lastNetworkType, boolean isNetworkAvailable){ + this.networkType = networkType; + this.lastNetworkType = lastNetworkType; + this.isNetworkAvailable = isNetworkAvailable; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NoticeToBackEvent.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NoticeToBackEvent.java new file mode 100644 index 0000000..5fd8ac7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/eventbus/event/NoticeToBackEvent.java @@ -0,0 +1,6 @@ +package com.mm.android.deviceaddmodule.mobilecommon.eventbus.event; + +public class NoticeToBackEvent { + public NoticeToBackEvent(){ + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FetchAddressTask.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FetchAddressTask.java new file mode 100644 index 0000000..4862d7d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FetchAddressTask.java @@ -0,0 +1,101 @@ +package com.mm.android.deviceaddmodule.mobilecommon.location; + +import android.content.Context; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; +import android.os.AsyncTask; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * AsyncTask for reverse geocoding coordinates into a physical address. + * include country/city/street etc. + */ +public class FetchAddressTask extends AsyncTask { + + private Context mContext; + private OnGeoDecodeCompleted mListener; + private final String TAG = "FetchAddressTask"; + + public FetchAddressTask(Context applicationContext, OnGeoDecodeCompleted listener) { + mContext = applicationContext; + mListener = listener; + } + + @Override + protected String doInBackground(Location... params) { + // Set up the geocoder + Geocoder geocoder = new Geocoder(mContext, Locale.getDefault()); + + // Get the passed in location + Location location = params[0]; + List
addresses = null; + String resultMessage = ""; + + if (location == null) { + LogUtil.debugLog(TAG, "location has't got"); + return ""; + } + + + try { + // In this sample, get just a single address + addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1); + } catch (IOException ioException) { + // Catch network or other I/O problems + LogUtil.errorLog(TAG, "Catch network or other I/O problems -> service not available", ioException); + } catch (IllegalArgumentException illegalArgumentException) { + // Catch invalid latitude or longitude values + LogUtil.errorLog(TAG, "invalid latitude or longitude used" + ". " + + "Latitude = " + location.getLatitude() + + ", Longitude = " + + location.getLongitude(), illegalArgumentException); + } + + // If no addresses found, print an error message. + if (addresses == null || addresses.size() == 0) { + if (resultMessage.isEmpty()) { + LogUtil.debugLog(TAG, "no address found"); + } + return ""; + } + // If an address is found, read it into resultMessage + Address address = addresses.get(0); + ArrayList addressParts = new ArrayList<>(); + + // Fetch the address lines using getAddressLine, + // join them, and send them to the thread + for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) { + addressParts.add(address.getAddressLine(i)); + } + resultMessage = address.getCountryCode(); + LogUtil.debugLog(TAG, "address info -> " + resultMessage + " || " + TextUtils.join("\n", addressParts)); + + return resultMessage; + } + + /** + * Called once the background thread is finished and updates the + * UI with the result. + * + * @param address The resulting reverse geocoded address, or error + * message if the task failed. + */ + @Override + protected void onPostExecute(String address) { + mListener.onGeoDecodeCompleted(address); + super.onPostExecute(address); + } + + //反编码回调接口 + public interface OnGeoDecodeCompleted { + void onGeoDecodeCompleted(String result); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FuseLocationUtil.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FuseLocationUtil.java new file mode 100644 index 0000000..49ffd83 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/location/FuseLocationUtil.java @@ -0,0 +1,133 @@ +package com.mm.android.deviceaddmodule.mobilecommon.location; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.provider.Settings; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.text.DecimalFormat; + +/** + * 获取经纬度和反编码的工具类 + * 1.首先使用原生的provider获取 + * 2.未获取到时,采用基于FusedLocation方式 + * 3.支持对经纬度进行反编码 + * note:need to assign necessary listener to your goal + */ +public class FuseLocationUtil { + + private Activity mActivity; + private FetchAddressTask.OnGeoDecodeCompleted mGeoDecodeCompletedListener; + private OnLocationGetCompleted mLocationGetCompletedListener; + private Location mLocation; + + //仅获取经纬度回调接口 + public interface OnLocationGetCompleted { + void onLocationGetCompleted(Location result); + } + + //判断定位是否可用 + public static boolean isLocationEnabled(Context context) { + LocationManager lm = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); + return lm != null && (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) || lm.isProviderEnabled(LocationManager.GPS_PROVIDER)); + } + + //判断Gps是否可用 + public static boolean isGpsEnabled(Context context) { + LocationManager lm = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); + return lm != null && lm.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + /** + * 打开Gps设置界面 + */ + public static void openGpsSettings(Context context) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + /** + * GPS坐标 转换成 角度 + */ + public static String gpsToDegree(double location) { + double degree = Math.floor(location); + double minute_temp = (location - degree) * 60; + double minute = Math.floor(minute_temp); + String second = new DecimalFormat("#.##").format((minute_temp - minute) * 60); + return (int) degree + "°" + (int) minute + "′" + second + "″"; + } + + //不在中国范围内 + public static boolean outOfChina(double longitude, double latitude) { + return longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271; + } + + //比较两次坐标,是否偏移 + public static boolean isMove(Location location, Location preLocation) { + boolean isMove; + if (preLocation != null) { + double speed = location.getSpeed() * 3.6; + double distance = location.distanceTo(preLocation); + double compass = Math.abs(preLocation.getBearing() - location.getBearing()); + double angle; + if (compass > 180) { + angle = 360 - compass; + } else { + angle = compass; + } + if (speed != 0) { + if (speed < 35 && (distance > 3 && distance < 10)) { + isMove = angle > 10; + } else { + isMove = (speed < 40 && distance > 10 && distance < 100) || + (speed < 50 && distance > 10 && distance < 100) || + (speed < 60 && distance > 10 && distance < 100) || + (speed < 9999 && distance > 100); + } + } else { + isMove = false; + } + } else { + isMove = true; + } + return isMove; + } + + + public Location getGpsInfoByProvider(Context context) { + Location location = null; + try { + Criteria criteria = new Criteria(); + criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度,如果设置为高精度,依然获取不了location。 + criteria.setAltitudeRequired(false);//不要求海拔 + criteria.setBearingRequired(false);//不要求方位 + criteria.setCostAllowed(true);//允许有花费 + criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗 + + LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + //从可用的位置提供器中,匹配以上标准的最佳提供器 + if (locationManager != null) { + String locationProvider = locationManager.getBestProvider(criteria, true); + location = TextUtils.isEmpty(locationProvider) ? null : locationManager.getLastKnownLocation(locationProvider); + } + if (mLocationGetCompletedListener != null) { + mLocationGetCompletedListener.onLocationGetCompleted(location); + } + LogUtil.debugLog("FuseLocationUtil", location == null ? "getGpsInfo by provider not worked" : + "getBestProvider worked! -> Longitude: " + location.getLongitude() + " & Latitude: " + location.getLatitude()); + } catch (SecurityException e) { + e.printStackTrace(); + } + + return location; + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/p2pDevice/P2PErrorHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/p2pDevice/P2PErrorHelper.java new file mode 100644 index 0000000..122eb36 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/p2pDevice/P2PErrorHelper.java @@ -0,0 +1,8 @@ +package com.mm.android.deviceaddmodule.mobilecommon.p2pDevice; + +public class P2PErrorHelper { + public final static int LOGIN_ERROR_KEY_MISMATCH = 201;//密码不正确 + public final static int LOGIN_ERROR_USER_LOCKED = 205;//帐户被锁定 + public final static int LOGIN_ERROR_KEY_OR_USER_MISMATCH = 217;//设备用户名或密码错误 +} + diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/AppUtils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/AppUtils.java new file mode 100644 index 0000000..6d8fcd7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/AppUtils.java @@ -0,0 +1,22 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + + +public class AppUtils { + + public static synchronized int getTargetSdkVersion(Context context) { + int version = 0; + try { + final PackageInfo info = context.getPackageManager().getPackageInfo( + context.getPackageName(), 0); + version = info.applicationInfo.targetSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return version; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/Base64Help.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/Base64Help.java new file mode 100644 index 0000000..dbc529f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/Base64Help.java @@ -0,0 +1,18 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.util.Base64; + +/** + * 功能说明: + * 版权申明: + */ + +public class Base64Help { + public static String encode(byte[] bytes){ + return Base64.encodeToString(bytes, Base64.DEFAULT); + } + + public static byte[] decode(String str) { + return Base64.decode(str, Base64.DEFAULT); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/BusinessAuthUtil.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/BusinessAuthUtil.java new file mode 100644 index 0000000..44911cb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/BusinessAuthUtil.java @@ -0,0 +1,18 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.SMBErrorCode; + +public class BusinessAuthUtil { + + //被踢出的相关错误码 + private static int [] errorCodesInt = new int[]{SMBErrorCode.REQUEST_AUTHORITY_ERROR, SMBErrorCode.REQUEST_INVALID_TOKEN, SMBErrorCode.REQUEST_LOGIN_EXPIRED, SMBErrorCode.REQUEST_SIGNATURE_FORMAT_ERROR};//客户端转换,两组 对应 + + public static boolean isAuthFailed(int codeFromHandle) { + for (int errorCode : errorCodesInt){ + if( codeFromHandle == errorCode){ + return true; + } + } + return false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/CommonHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/CommonHelper.java new file mode 100644 index 0000000..53cc35e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/CommonHelper.java @@ -0,0 +1,292 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.ComponentName; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; +import android.provider.Settings; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.widget.TextView; +import android.widget.Toast; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddContact; + +import java.io.File; +import java.io.FileOutputStream; +import java.text.NumberFormat; +import java.util.List; + +public class CommonHelper { + private static final String HWMobile = "HUAWEI"; + /** + * 使用该接口需要先申请位置权限,否则返回gps的数据是空的 + * + * @param context + * @return + */ + public static double[] getGpsInfo(Context context) { + Criteria criteria = new Criteria(); + criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度,如果设置为高精度,依然获取不了location。 + criteria.setAltitudeRequired(false);//不要求海拔 + criteria.setBearingRequired(false);//不要求方位 + criteria.setCostAllowed(true);//允许有花费 + criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗 + double[] gpsInfo = new double[2]; + try { + LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + //从可用的位置提供器中,匹配以上标准的最佳提供器 + if (locationManager != null) { + String locationProvider = locationManager.getBestProvider(criteria, true); + Location location = locationManager.getLastKnownLocation(locationProvider); + if (location != null) { + gpsInfo[0] = keepTwoDigitsOfDouble(location.getLongitude()); + gpsInfo[1] = keepTwoDigitsOfDouble(location.getLatitude()); + } + } + LogUtil.debugLog("CommonHelper", "Longitude: " + gpsInfo[0] + " & Latitude: " + gpsInfo[1]); + } catch (SecurityException e) { + e.printStackTrace(); + }catch (Exception e1){ + e1.printStackTrace(); + } + return gpsInfo; + } + + /** + * Double 数据保留2位小数点 + * @param number + * @return + */ + public static double keepTwoDigitsOfDouble(double number){ + NumberFormat numberFormat = NumberFormat.getNumberInstance(); + numberFormat.setMaximumFractionDigits(2); + return Double.valueOf(numberFormat.format(number)); + } + + //用户头像保存到本地 + public static void savePhotoToLocal(String path, Bitmap bitmap) { + File file = new File(path); + if (file.exists()) { + if (!file.delete()) + return; + } else { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + try { + FileOutputStream out = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); + out.flush(); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // 判断是否安装应用 + + public static boolean isApkInstalled(Context context, String packageName) { + if (TextUtils.isEmpty(packageName)) { + return false; + } + PackageManager manager = context.getPackageManager(); + List pkgList = manager.getInstalledPackages(0); + + if (pkgList != null) { + for (int i = 0; i < pkgList.size(); i++) { + PackageInfo pi = pkgList.get(i); + if (pi.packageName.equalsIgnoreCase(packageName)) { + return true; + } + } + } + return false; + } + + // 启动应用 + public static void startAppByPackageName(Context context, String packageName) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); + context.startActivity(intent); + } + + public static void gotoWifiSetting(Context context) { + Intent intent = new Intent(); + intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.wifi.WifiSettings")); + + List result = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_ALL); + if(result.isEmpty()){ + intent = new Intent(Settings.ACTION_WIFI_SETTINGS); + } + + context.startActivity(intent); + } + + public static void addContact(Context context , AddContact contact){ + // 创建一个空的ContetnValues + ContentValues values = new ContentValues(); + + // 向RawContacts.CONTENT_URI 空值插入 + // 先获取android系统返回的rawContactId + // 后面要基础此id插入值 + Uri rawContactUri = context.getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values); + long rawContactId = ContentUris.parseId(rawContactUri); + values.clear(); + + values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId); + //内容类型 + values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); + //联系人名字 + values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contact.getName()); + //向联系人URI添加联系人名字 + context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values); + values.clear(); + + + for(AddContact.NumbersBean phone : contact.getNumbers()){ + values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId); + values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); + //联系人的电话号码 + values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone.getPhone()); + //电话类型 + values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE); + //向联系人电话号码URI添加电话号码 + context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values); + values.clear(); + } + } + + public static String getChannel(Context context) { + try { + PackageManager pm = context.getPackageManager(); + ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); + String channel = appInfo.metaData.getString("APP_CHANNEL_VALUE"); // key为标签中的name + if (!TextUtils.isEmpty(channel)) { + return channel; + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 是否是华为渠道包 + * @return + */ + public static boolean isHuaweiFlavor(Context context){ + return "huawei".equals(getChannel(context)); + } + + /** + * 根据渠道包跳转到应用市场 + * @param context + */ + public static void gotoPlayStore(Context context) { + if (context == null) { + return; + } + if(isHuaweiFlavor(context)){ + gotoHuaweiPlayStore(context); + }else{ + gotoGooglePlayStore(context); + } + } + + /** + * 跳转谷歌应用商店 + * @param context + */ + public static void gotoGooglePlayStore(Context context) { + if (context == null) { + return; + } + + final String GOOGLE_PLAY = "com.android.vending";//谷歌商店,跳转别的商店改成对应的即可 + String appPkg = context.getPackageName(); + try { + if (TextUtils.isEmpty(appPkg)) + return; + Uri uri = Uri.parse("market://details?id=" + appPkg); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.setPackage(GOOGLE_PLAY); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } catch (Exception e) { + //跳转失败的处理 + Toast.makeText(context, R.string.mobile_common_no_google_play_detection, Toast.LENGTH_SHORT).show(); + } + } + + /** + * 跳转华为应用商店 + * @param context + */ + public static void gotoHuaweiPlayStore(Context context) { + if (context == null) { + return; + } + + final String HUAWEI_PLAY = "com.huawei.appmarket";//华为商店,跳转别的商店改成对应的即可 + String appPkg = context.getPackageName(); + try { + if (TextUtils.isEmpty(appPkg)) + return; + Uri uri = Uri.parse("market://details?id=" + appPkg); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.setPackage(HUAWEI_PLAY); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } catch (Exception e) { + //跳转失败的处理 + Toast.makeText(context, R.string.mobile_common_no_huawei_play_detection, Toast.LENGTH_SHORT).show(); + } + } + + /** + * 是否是P以上系统 + * @return + */ + public static boolean isAndroidPOrLater(){ + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + } + + /** + * 是否是Q以上系统 + * @return + */ + /* public static boolean isAndroidQOrLater(){ + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + }*/ + + /** + * 设置底部下划线并可点击跳转 + */ + public static void setProtocolClick(String str1, ClickableSpan span1, TextView textView) { + SpannableString info = new SpannableString(str1); + if (!TextUtils.isEmpty(str1)) { + info.setSpan(span1, 0, str1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + textView.setText(info); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setHighlightColor(Color.TRANSPARENT); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/LogUtil.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/LogUtil.java new file mode 100644 index 0000000..284728b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/LogUtil.java @@ -0,0 +1,356 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class LogUtil { + + + /** + * + * @param tag + * @param sep + * @param args + */ + public static void printDebug(String tag,String sep,Object...args){ + if(args == null || args.length == 0)return; + if(sep == null){ + sep = ""; + } + if(tag == null){ + tag = ""; + } + StringBuffer buffer = new StringBuffer(); + int leng = args.length; + for (int i = 0;i max_str_length){ + Log.w(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.w(tag, message); + } + + private static void w(String tag, String message, Throwable throwable){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.w(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.w(tag, message, throwable); + } + + private static void e(String tag, String message){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.e(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.e(tag, message); + } + + private static void e(String tag, String message, Throwable throwable){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.e(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.e(tag, message, throwable); + } + + private static void v(String tag, String message){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.v(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.v(tag, message); + } + + private static void v(String tag, String message, Throwable throwable){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.v(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.v(tag, message, throwable); + } + + private static void i(String tag, String message){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.i(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.i(tag, message); + } + + private static void i(String tag, String message, Throwable throwable){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.i(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.i(tag, message, throwable); + } + + private static void d(String tag, String message){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.d(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.d(tag, message); + } + + private static void d(String tag, String message, Throwable throwable){ + int max_str_length = 2001 - tag.length(); + while (message.length() > max_str_length){ + Log.d(tag, message.substring(0, max_str_length)); + message = message.substring(max_str_length); + } + + Log.d(tag, message, throwable); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/MD5Helper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/MD5Helper.java new file mode 100644 index 0000000..5b891ef --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/MD5Helper.java @@ -0,0 +1,82 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.text.TextUtils; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Helper +{ + private static byte[] hex = new byte[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + /** + * 对字符串进行MD5加密 + * @param rawString 要加密的字符串 + * @return MD5摘要码 + */ + public static byte[] encode2byte(String rawString) { + if (TextUtils.isEmpty(rawString)) { + return null; + }try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(rawString.getBytes()); + return md5.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * 对字符串进行MD5加密 + * @param rawString 要加密的字符串 + * @return MD5摘要码 + */ + public static String encode(String rawString) + { + String md5String = null; + if (TextUtils.isEmpty(rawString)) { + return md5String; + } + try + { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(rawString.getBytes()); + md5String = convertToHexString(md5.digest()); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + } + + if (null != md5String) + { + return md5String.toUpperCase(); + } + + return md5String; + } + + + public static String encodeToLowerCase(String rawString){ + String mD5String = encode(rawString); + if (TextUtils.isEmpty(mD5String)) { + return mD5String; + } + return mD5String.toLowerCase(); + } + + private static String convertToHexString(byte[] digests) + { + byte[] md5String = new byte[digests.length * 2]; + + int index = 0; + for (byte digest : digests) + { + md5String[index] = hex[(digest >> 4) & 0x0F]; + md5String[index + 1] = hex[digest &0x0F]; + index += 2; + } + + return new String(md5String); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NameLengthFilter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NameLengthFilter.java new file mode 100644 index 0000000..c086830 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NameLengthFilter.java @@ -0,0 +1,50 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.text.InputFilter; +import android.text.Spanned; + + +public class NameLengthFilter implements InputFilter { + + private final int mMax; + + public NameLengthFilter(int max) { + mMax = max; + } + + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + int destCount = getWordCountRegex(dest.toString()); + int sourceCount = getWordCountRegex(source.toString()); + if(destCount + sourceCount > mMax){ + int surplusCount = mMax - destCount; + String result = ""; + int resultCount = 0; + int index = 0; + while (surplusCount > resultCount){ + result += source.charAt(index); + resultCount = getWordCountRegex(result); + index++; + } + + if(surplusCount == resultCount){ + return source.subSequence(start, index); + }else{ + return source.subSequence(start, index - 1); + } + + }else{ + return source; + } + + } + + private int getWordCountRegex(String str){ + if(str == null){ + return 0; + } + + str = str.replaceAll("[^\\x00-\\xff]" , "**"); + return str.length(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NetWorkHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NetWorkHelper.java new file mode 100644 index 0000000..c95fd9d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/NetWorkHelper.java @@ -0,0 +1,121 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +public class NetWorkHelper { + +/** + * 获取当前网络类型 + * @param context + * @return + */ + public static int checkNetwork(Context context) { + int flag = -1; + ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (conMan == null) { + flag = -1; + } else { + NetworkInfo[] info = conMan.getAllNetworkInfo(); + if (info != null) { + for (NetworkInfo anInfo : info) { + if (anInfo.getState() == NetworkInfo.State.CONNECTED) { + flag = anInfo.getType(); + break; + } + } + } + } + return flag; + } + + /** + * 获取当前网络是否连接 + * @param context + * @return + */ + public static boolean isConnected(Context context) { + if(context == null){ + return false; + } + ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if(conn == null){ + return false; + } + NetworkInfo info = conn.getActiveNetworkInfo(); + return (info != null && info.isAvailable()); + } + + + public static boolean isWifiNetworkAvailable(Context context) { + if(context == null)return false; + ConnectivityManager connectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); + if (activeNetInfo != null + && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // 判断wifi + return true; + } + return false; + } + + + + + + + public static int getIpV4Value(String ipOrMask) { + byte[] addr = getIpV4Bytes(ipOrMask); + int address = addr[3] & 0xFF; + address |= ((addr[2] << 8) & 0xFF00); + address |= ((addr[1] << 16) & 0xFF0000); + address |= ((addr[0] << 24) & 0xFF000000); + return address; + } + + public static byte[] getIpV4Bytes(String ipOrMask) { + try{ + String[] addrs = ipOrMask.split("\\."); + int length = addrs.length; + byte[] addr = new byte[length]; + for(int i = 0; i < length; i++) { + addr[i] = (byte)(Integer.parseInt(addrs[i]) & 0xff); + } + return addr; + }catch (Exception e) { + + } + return new byte[4]; + } + + + + /** + * 网络是否可用 + * + * @param context + * @return + */ + public static boolean isNetworkAvailable(Context context) { + android.net.ConnectivityManager connectivity = (android.net.ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); // 获取系统网络连接管理�? + if (connectivity == null) { // 如果网络管理器为null + return false; // 返回false表明网络无法连接 + } else { + android.net.NetworkInfo[] info = connectivity.getAllNetworkInfo(); // 获取�?��的网络连接对�? + if (info != null) { // 网络信息不为null + for (NetworkInfo anInfo : info) { // 遍历网路连接对象 + if (anInfo.isConnected()) { // 当有�?��网络连接对象连接上网络时 + return true; // 返回true表明网络连接正常 + } + } + } + } + return false; + } + + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PasswordCheckRules.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PasswordCheckRules.java new file mode 100644 index 0000000..f41bfb2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PasswordCheckRules.java @@ -0,0 +1,210 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.text.TextUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PasswordCheckRules { + + private final static int AWARD_2 = 2; + private final static int AWARD_3 = 3; + private final static int AWARD_5 = 5; + + public static final int PASSWORD_INVALID = 59999; //密码为空 不合法 + public static final int PASSWORD_VALID_OK = 60000; //密码符合规则 + public static final int PASSWORD_NOT_MATCH = 60001; //新密码和确认密码不一致 + public static final int PASSWORD_INVALID_COMBINATION = 60002; //新密码组合不合法(2种以上类型) + public static final int PASSWORD_INVALID_LENGTH = 60003; //新密码的长度不合法(8~32位) + public static final int PASSWORD_INVALID_NO_SN = 60004; //新密码不合法:不允许为序列号 + public static final int PASSWORD_NOT_SAFY = 60005; //密码不符合安全基线要求 + + /** + * 自定义加密密码校验 + * @param pwd + * @return + */ + public static int checkSinglePasswordValidationLC( String pwd) { + if (TextUtils.isEmpty(pwd)) return PASSWORD_INVALID; + + if (pwd.length() < 6 || pwd.length() > 32) return PASSWORD_INVALID_LENGTH; + + return PASSWORD_VALID_OK; + } + + public static int checkSinglePasswordValidation(Context context, String pwd) { + if (TextUtils.isEmpty(pwd)) return PASSWORD_INVALID; + + if (pwd.length() < 8 || pwd.length() > 32) return PASSWORD_INVALID_LENGTH; + + if (!isMultiCharacterPassword(pwd)) return PASSWORD_INVALID_COMBINATION; + + if(StringUtils.checkSafetyBaseline(null , pwd, context)) return PASSWORD_NOT_SAFY; + + return PASSWORD_VALID_OK; + } + + //密码为8~32位字母且字符组合 + public static int checkPasswordValidation(String pwd, String conformPwd, Context context){ + + if(TextUtils.isEmpty(pwd) || TextUtils.isEmpty(conformPwd)) return PASSWORD_INVALID; + + if (pwd.length() < 8 || pwd.length() > 32) return PASSWORD_INVALID_LENGTH; + + if(!isMultiCharacterPassword(pwd)) return PASSWORD_INVALID_COMBINATION; + + if (!pwd.equals(conformPwd)) return PASSWORD_NOT_MATCH; + + if(StringUtils.checkSafetyBaseline(null , pwd, context)) return PASSWORD_NOT_SAFY; + + return PASSWORD_VALID_OK; + + } + + //蓝牙锁管理员密码重置 密码为6~12位字母且字符组合 + public static int checkLockPasswordValidation(String pwd, String conformPwd, Context context){ + + if(TextUtils.isEmpty(pwd) || TextUtils.isEmpty(conformPwd)) return PASSWORD_INVALID; + + if (pwd.length() < 6 || pwd.length() > 12) return PASSWORD_INVALID_LENGTH; + + if (!pwd.equals(conformPwd)) return PASSWORD_NOT_MATCH; + + return PASSWORD_VALID_OK; + + } + + + + //是否包含其他特殊字符 + public static boolean isSpeCharacterPassword(String str) { + + //27个特殊符号ASC码:33、35、36、37、40、41、42、43、44、45、46、47、60、61、62、63、64、91、92、93、94、95、96、123、124、125、126 + String charEx = "[\\!\\#\\$\\%\\(\\)\\*\\+\\,\\-\\.\\/\\<\\=" + + "\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~]*"; + Pattern pChar = Pattern.compile(charEx); + Matcher mChar = pChar.matcher(str); + if (mChar.matches()) { + return false; + } + + return true; + } + + + //判断密码是否包含两种以上字符 + public static boolean isMultiCharacterPassword(String str) { + String numEx = "[0-9]*"; // 不能纯数字 + Pattern pNum = Pattern.compile(numEx); + Matcher mNum = pNum.matcher(str); + if (mNum.matches()) { + return false; + } + + String lowEx = "[a-z]*"; //不能纯小写英语 + Pattern pLow = Pattern.compile(lowEx); + Matcher mLow = pLow.matcher(str); + if (mLow.matches()) { + return false; + } + + String highEx = "[A-Z]*"; //不能纯大写英语 + Pattern pHigh = Pattern.compile(highEx); + Matcher mHigh = pHigh.matcher(str); + if (mHigh.matches()) { + return false; + } + + //27个特殊符号ASC码:33、35、36、37、40、41、42、43、44、45、46、47、60、61、62、63、64、91、92、93、94、95、96、123、124、125、126 + String charEx = "[\\!\\#\\$\\%\\(\\)\\*\\+\\,\\-\\.\\/\\<\\=" + + "\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~]*"; + Pattern pChar = Pattern.compile(charEx); + Matcher mChar = pChar.matcher(str); + if (mChar.matches()) { + return false; + } + + return true; + } + + /** + * 获取密码强度分数 + * @param password + * @return + */ + public static int getPwdStrength(String password){ + //遍历计算字符串中的数字个数、大写字母的个数、小写字母个数、符号个数 + int strength = 0; + int lowerCaseNum = 0; + int upperCaseNum = 0; + int digitNum = 0; + for (int i = 0;i= 8) + strength = 25; + + //字母 + if (!(lowerCaseNum == 0 && upperCaseNum == 0)){ + strength = strength + 10; + if(lowerCaseNum > 0 && upperCaseNum > 0) + strength = strength + 10; + } + + //数字 + if (digitNum == 1) + strength = strength + 10; + else if (digitNum > 1) + strength = strength + 20; + + //符号 + if (characterNum == 1) + strength = strength + 10; + else if (characterNum > 1) + strength = strength + 25; + + int awardScore = getAwardScore(upperCaseNum, lowerCaseNum, digitNum, characterNum); + strength += awardScore; + return strength; + } + + /** + * 五:奖励规则则 检验字母和符号组合 + * 2 分: 两种字符类型组合 + * 3 分: 三种字符类型组合 + * 5 分: 四种字符类型组合 + */ + private static int getAwardScore(int upperCaseLetterCount, int lowerCaseLetterCount, int numberCount, int symbolCount) { + + upperCaseLetterCount = upperCaseLetterCount > 0 ? 1 : 0; + lowerCaseLetterCount = lowerCaseLetterCount > 0 ? 1 : 0; + numberCount = numberCount > 0 ? 1 : 0; + symbolCount = symbolCount > 0 ? 1 : 0; + switch (upperCaseLetterCount + lowerCaseLetterCount + numberCount + symbolCount) { + case 2: + return AWARD_2; + case 3: + return AWARD_3; + case 4: + return AWARD_5; + default: + return 0; + } + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PreferencesHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PreferencesHelper.java new file mode 100644 index 0000000..03e597f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/PreferencesHelper.java @@ -0,0 +1,383 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.Base64; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.StreamCorruptedException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class PreferencesHelper { + private final static String PRENAME = "dh_data"; + + private static Context mContext = null; + private SharedPreferences mConfig = null; + + private PreferencesHelper() + { + } + + private static class Instance{ + private static PreferencesHelper ph=new PreferencesHelper(); + } + + public static PreferencesHelper getInstance(Context context){ + mContext = context.getApplicationContext(); + return Instance.ph; + } + + /** + * 若不存在Key,则返回 空字符串 + * @param Key + * @return + */ + public String getString(String Key){ + SharedPreferences config = getConfig(); + String result = config.getString(Key, ""); + return result; + } + + /** + * 若不存在Key,则返回 默认值 + * + * @param Key + * @return + */ + public String getString(String Key, String defValue) { + SharedPreferences config = getConfig(); + String result = config.getString(Key, defValue); + return result; + } + + /** + * 若不存在Key,则返回0 + * @param Key + * @return + */ + public int getInt(String Key){ + SharedPreferences config = getConfig(); + int result = config.getInt(Key, 0); + return result; + } + + /** + * 若不存在Key,则返回 默认值 + * + * @param Key + * @return + */ + public int getInt(String Key, int defValue) { + SharedPreferences config = getConfig(); + int result = config.getInt(Key, defValue); + return result; + } + + /** + * 若不存在Key,则返回 false + * @param Key + * @return + */ + public boolean getBoolean(String Key){ + SharedPreferences config = getConfig(); + boolean result = config.getBoolean(Key, false); + return result; + } + + /** + * 若不存在Key,则返回 默认值 + * + * @param Key + * @return + */ + public boolean getBoolean(String Key, boolean defValue) { + SharedPreferences config = getConfig(); + boolean result = config.getBoolean(Key, defValue); + return result; + } + + /** + * 若不存在Key,则返回 false + * @param Key + * @return + */ + public float getFloat(String Key){ + SharedPreferences config = getConfig(); + float result = config.getFloat(Key, 0); + return result; + } + + /** + * 若不存在Key,则返回 默认值 + * + * @param Key + * @return + */ + public float getFloat(String Key, float defValue) { + SharedPreferences config = getConfig(); + float result = config.getFloat(Key, defValue); + return result; + } + + /** + * 新消息推送模块,专业默认返回true的 + *

+ *

+ * @param Key + * @return + */ + public boolean getMessagePushBoolean(String Key) { + SharedPreferences config = getConfig(); + boolean result = config.getBoolean(Key, true); + return result; + } + + /** + * 若不存在Key,则返回 0 + * @param Key + * @return + */ + public long getLong(String Key){ + SharedPreferences config = getConfig(); + long result = config.getLong(Key, 0); + return result; + } + + public long getLong(String Key, long defValue){ + SharedPreferences config = getConfig(); + long result = config.getLong(Key, defValue); + return result; + } + + public void set(String key, String value){ + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putString(key, value); + editor.commit(); + } + + public void set(String key, int value){ + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putInt(key, value); + editor.commit(); + } + + public void set(String key, boolean value){ + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putBoolean(key, value); + editor.commit(); + editor.apply(); + } + + public void set(String key, long value){ + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putLong(key, value); + editor.commit(); + } + + public void set(String key, float value){ + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putFloat(key, value); + editor.commit(); + } + + public void set(String key, List values) { + if (values == null) { + return; + } + + Set set = new HashSet<>(values); + SharedPreferences config = getConfig(); + SharedPreferences.Editor editor = config.edit(); + editor.putStringSet(key, set); + editor.commit(); + } + + public List getStrings(String key) { + List list = new ArrayList<>(); + + if (!contains(key)) { + return list; + } + + SharedPreferences config = getConfig(); + Set set = config.getStringSet(key, new HashSet()); + list.addAll(set); + return list; + } + + /** + * 是否存在key值 + * @param key + * @return + */ + public boolean contains(String key){ + SharedPreferences config = getConfig(); + return config.contains(key); + } + + private SharedPreferences getConfig() + { + if(mConfig == null) + { + mConfig = mContext.getSharedPreferences(PRENAME, Context.MODE_PRIVATE); + } + return mConfig; + } + + + public void setData(String tempName, List tempList) { + SharedPreferences config = getConfig(); + // 创建字节输出流 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + // 创建对象输出流,并封装字节流 + ObjectOutputStream oos = new ObjectOutputStream(baos); + // 将对象写入字节流 + oos.writeObject(tempList); + // 将字节流编码成base64的字符串 + String tempBase64 = new String(Base64.encode(baos.toByteArray(),Base64.DEFAULT)); + SharedPreferences.Editor editor = config.edit(); + editor.putString(tempName, tempBase64); + editor.commit(); + } catch (IOException e) { + e.printStackTrace(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + } + + + public List getData(String tempName, List tempList) { + SharedPreferences config = getConfig(); + String tempBase64 = config.getString(tempName, "");// 初值空 + if (TextUtils.isEmpty(tempBase64)) { + return tempList; + } + // 读取字节 + byte[] base64 = Base64.decode(tempBase64,Base64.DEFAULT); + // 封装到字节流 + ByteArrayInputStream bais = new ByteArrayInputStream(base64); + try { + // 再次封装 + ObjectInputStream ois = new ObjectInputStream(bais); + // 读取对象 + tempList = (List) ois.readObject(); + } catch (StreamCorruptedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return tempList; + + } + + /** + * 对象存储 + */ + public void setObject(String key, Object temp) { + SharedPreferences config = getConfig(); + // 创建字节输出流 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + // 创建对象输出流,并封装字节流 + ObjectOutputStream oos = new ObjectOutputStream(baos); + // 将对象写入字节流 + oos.writeObject(temp); + // 将字节流编码成base64的字符串 + String tempBase64 = new String(Base64Help.encode(baos.toByteArray())); + SharedPreferences.Editor editor = config.edit(); + editor.putString(key, tempBase64); + editor.commit(); + } catch (IOException e) { + e.printStackTrace(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + } + + public Object getObject(String key, Object defaultValue) { + SharedPreferences config = getConfig(); + String tempBase64 = config.getString(key, "");// 初值空 + if (TextUtils.isEmpty(tempBase64)) { + return defaultValue; + } + // 读取字节 + byte[] base64 = Base64Help.decode(tempBase64); + // 封装到字节流 + ByteArrayInputStream bais = new ByteArrayInputStream(base64); + try { + // 再次封装 + ObjectInputStream ois = new ObjectInputStream(bais); + // 读取对象 + defaultValue = ois.readObject(); + } catch (StreamCorruptedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return defaultValue; + + } + + // key value + + public static void clearKeyValueCache(Context context,String totalKey) { + PreferencesHelper preferencesHelper = PreferencesHelper.getInstance(context); + ArrayList urlKeyList = (ArrayList) + preferencesHelper.getData(totalKey, new ArrayList()); + for (String urlKey : urlKeyList) { + preferencesHelper.set(urlKey, ""); + } + preferencesHelper.setData(totalKey, new ArrayList()); + } + + public static void clearKeyValueCacheBySnCode(Context context,String totalKey,String key) { + PreferencesHelper preferencesHelper = PreferencesHelper.getInstance(context); + ArrayList urlKeyList = (ArrayList) + preferencesHelper.getData(totalKey, new ArrayList()); + ArrayList newList = new ArrayList<>(); + for (String urlKey : urlKeyList) { + if(urlKey!=null && urlKey.contains(key)){ + preferencesHelper.set(urlKey, ""); + }else{ + newList.add(urlKey); + } + } + preferencesHelper.setData(totalKey, newList); + } + public static void saveKeyValueToCache(Context context,String totalKey, String singleKey,String value) { + PreferencesHelper preferencesHelper = PreferencesHelper.getInstance(context); + preferencesHelper.set(singleKey ,value); + + ArrayList urlKeyList = (ArrayList) preferencesHelper.getData(totalKey, new ArrayList<>()); + if(!urlKeyList.contains(singleKey)){ + urlKeyList.add(singleKey); + } + preferencesHelper.setData(totalKey ,urlKeyList); + } + + public static void removeKey(Context context,String key) { + PreferencesHelper preferencesHelper = PreferencesHelper.getInstance(context); + SharedPreferences.Editor editor = preferencesHelper.getConfig().edit(); + editor.remove(key); + editor.commit(); + } + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/StringUtils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/StringUtils.java new file mode 100644 index 0000000..4a881d2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/StringUtils.java @@ -0,0 +1,260 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class StringUtils { + + /** + * 平台存数据库需要取出换行符 + * + * @param password + * @param deviceSnCode + * @return + */ + public static String getRTSPAuthPassword(String password, String deviceSnCode) { + + byte[] key = MD5Helper.encode(new String(deviceSnCode).toUpperCase() + "DAHUAKEY").toLowerCase().getBytes(); + byte[] iv = new String("0a52uuEvqlOLc5TO").getBytes(); + byte[] psw = null; + try { + SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv)); + psw = cipher.doFinal(password.getBytes()); + } catch (Exception e) { + + } + String baseString = psw == null ? "" : Base64Help.encode(psw); + + if (baseString.endsWith("\n")) { + baseString = baseString.replace("\n", ""); + } + + return baseString; + } + + + /** + * 不规则字符过滤 + * + * @param str + * @return + */ + public static String strFilter(String str) { + + if (TextUtils.isEmpty(str)) { + return str; + } + + String strEx = "^[a-zA-Z0-9\\-\u4E00-\u9FA5\\_\\@\\,\\.]+"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (!temp.matches(strEx)) { + str = str.replace(temp, ""); + return strFilter(str); + } + } + + return str; + } + + //过滤密码 + public static String strPsswordFilter(String str) { + +// String strEx = "^[a-zA-Z0-9\\~\\`\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)" + +// "\\-\\_\\+\\=\\{\\[\\}\\]\\|\\\\\\;\\:\\'\\\"\\<\\>\\,\\.\\/\\?]+"; + + //27个特殊符号ASC码:33、35、36、37、40、41、42、43、44、45、46、47、60、61、62、63、64、91、92、93、94、95、96、123、124、125、126 + String strEx = "^[a-zA-Z0-9\\!\\#\\$\\%\\(\\)\\*\\+\\,\\-\\.\\/\\<\\=" + + "\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~]*"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (!temp.matches(strEx)) { + str = str.replace(temp, ""); + return strPsswordFilter(str); + } + } + + return str; + } + + + /** + * @param username + * @param password + * @return true 表示校验失败 + */ + public static boolean checkSafetyBaseline(String username, String password, Context context) { + return checkPasswordWithUername(username, password) || checkRepeat(password) || checkCryptographicLibrary(password, context); + } + + + /** + * 客户端新增不合规密码的校验,当密码是用户名本身或者用户名的逆序,在点击【获取验证码】时,toast提示【密码过于简单】,无需清除密码框的密码; + * + * @param username + * @param password + * @return + */ + public static boolean checkPasswordWithUername(String username, String password) { + if (TextUtils.isEmpty(username)) { + return false; + } + String userNameLowerCase = username.toLowerCase(); + String passwordLowerCase = password.toLowerCase(); + String reverse = new StringBuilder(userNameLowerCase).reverse().toString(); + return TextUtils.equals(passwordLowerCase, reverse) || TextUtils.equals(passwordLowerCase, userNameLowerCase); + } + + /** + * 客户端新增弱密码库校验,当用户设置的密码属于“弱密码”,在点击【获取验证码】时,toast提示【密码过于简单】,无需清除密码框的密码; + * + * @param password + * @return + */ + public static boolean checkCryptographicLibrary(String password, Context context) { + List library = getCryptographicLirary(context); + return library.contains(password); + } + + + /** + * 获取密码库 + * + * @param context + * @return + */ + private static List getCryptographicLirary(Context context) { + List array = new ArrayList<>(); + + try { + XmlPullParser pullParser = Xml.newPullParser(); + InputStream is = context.getAssets().open("password.xml"); + pullParser.setInput(is, "utf-8"); + + int eventType = pullParser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_DOCUMENT: + array = new ArrayList<>(); + break; + case XmlPullParser.START_TAG: + if ("string".equals(pullParser.getName())) { + String str = pullParser.getAttributeValue(0); + array.add(str); + } + break; + } + + eventType = pullParser.next(); + + } + + + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return array; + } + + /** + * 客户端新增密码重复字符校验,当密码中重复的字符连续超过6次(含6次),在点击【获取验证码】时,toast提示【密码过于简单】,无需清除密码框的密码; + * + * @param password + * @return + */ + public static boolean checkRepeat(String password) { + String rex = "(.)\\1+"; + + List arr = new ArrayList<>(); + + Pattern pattern = Pattern.compile(rex); + Matcher matcher = pattern.matcher(password); + + while (matcher.find()) { + String str = matcher.group(); + arr.add(str); + } + + if (arr.isEmpty()) { + return false; + } + + for (String str : arr) { + if (str.length() >= 6) { + return true; + } + } + + return false; + } + + /** + * 过滤密码中的非数字字母字符 + * + * @param str + * @return + */ + public static String snFilter(String str) { + if (TextUtils.isEmpty(str)) { + return str; + } + String E1 = "[A-Z]";// 大写英文字母 + String E2 = "[a-z]";// 小写英文字母 + String E3 = "[0-9]";// 数字 + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (!temp.matches(E1) && !temp.matches(E2) + && !temp.matches(E3)) { + str = str.replace(temp, ""); + return snFilter(str); + } + } + return str; + } + + /** + * 字符过滤,用于密码 + * + * @param str + * @return + */ + public static String strPwdFilter(String str) { + + if (TextUtils.isEmpty(str)) { + return str; + } + + String strEx = "^[a-zA-Z0-9\\-\\_\\@]+"; + + for (int i = 0; i < str.length(); i++) { + String temp = str.substring(i, i + 1); + if (!temp.matches(strEx)) { + str = str.replace(temp, ""); + return strPwdFilter(str); + } + } + + return str; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/TimeUtils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/TimeUtils.java new file mode 100644 index 0000000..94e82ed --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/TimeUtils.java @@ -0,0 +1,1118 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.text.TextUtils; + +import com.company.NetSDK.NET_TIME; +import com.mm.android.deviceaddmodule.R; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public class TimeUtils { + /** + * 一天的总时间 + */ + public static final int TOTAL_SECONDS = 24 * 3600; + + public static final String LONG_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + + public static final String BLE_MESSAGE_FORMAT = "yyyy年MM月dd天HH:mm:ss"; + + public static final String SMB_REQUEST_FORMAT = "yyyyMMdd'T'HHmmss"; + public static final String REQUEST_FORMAT = "yyyyMMddHHmmss"; + public static final String REQUEST_DATE_FORMAT = "yyyyMMdd"; + + public static final String COMMON_TIME_FORMAT = "%04d%02d%02d%02d%02d%02d"; + public static final String DH_TIME_FORMAT = "%04d%02d%02dT%02d%02d%02d"; + + public static final String SHORT_FORMAT = "HH:mm:ss"; + public static final String SHORT_FORMAT2 = "HHmmss"; + + public static final String SIMPLE_FORMAT = "HH:mm"; + + public static String displayTime(Context context,long inputTime, String todayFormatStr, String yesterdayFormatStr, + String otherFormatStr) { + // 日期格式化 + SimpleDateFormat todayFormat = todayFormatStr != null ? TimeUtils.getDateFormatWithUS(todayFormatStr) : null; + SimpleDateFormat yesterdayFormat = yesterdayFormatStr != null ? TimeUtils.getDateFormatWithUS(yesterdayFormatStr) : null; + SimpleDateFormat otherFormat = otherFormatStr != null ? TimeUtils.getDateFormatWithUS(otherFormatStr) : null; + String timeStr = null; + + // 获取当前凌晨时间 + Calendar c = Calendar.getInstance(); + String getYear = String.valueOf(c.get(Calendar.YEAR)); + String getMonth = String.valueOf(c.get(Calendar.MONTH) + 1); + String getDayOfMonth = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); + if (getMonth.length() == 1) { + getMonth = "0" + getMonth; + } + if (getDayOfMonth.length() == 1) { + getDayOfMonth = "0" + getDayOfMonth; + } + String currentStartTimeStr = getYear + "-" + getMonth + "-" + getDayOfMonth + " 00:00:00"; + + // 当前凌晨时间格式转换 + java.sql.Timestamp currentStartTime = java.sql.Timestamp.valueOf(currentStartTimeStr); + long currentStart = currentStartTime.getTime(); + + // 与当前凌晨时间相差秒数 + long timeGap = (currentStart - inputTime) / 1000; + + // 输入时间:年 + if (timeGap <= 0) { + timeStr = todayFormat != null ? todayFormat.format(inputTime) :context.getResources().getString(R.string.common_today); // 今天格式:10:00 + } else if (timeGap > 0 && timeGap <= 24 * 60 * 60) { + timeStr = yesterdayFormat != null ? yesterdayFormat.format(inputTime) :context.getResources().getString(R.string.common_yesterday); // 昨天格式:昨天 + } else { + timeStr = otherFormat != null ? otherFormat.format(inputTime) : String.valueOf(inputTime); // 其他格式:15/09/03 + } + + return timeStr; + } + + + public static NET_TIME Date2NetTime(Date date) + { + NET_TIME time = new NET_TIME(); + time.dwYear = date.getYear() + 1900; + time.dwMonth = date.getMonth() + 1; + time.dwDay = date.getDate(); + time.dwHour = date.getHours(); + time.dwMinute = date.getMinutes(); + time.dwSecond = date.getSeconds(); + return time; + } + + public static Date NetTimeToData(NET_TIME netTime) + { + Date date = new Date((int)netTime.dwYear - 1900, + (int)netTime.dwMonth - 1, + (int)netTime.dwDay, + (int)netTime.dwHour, + (int)netTime.dwMinute, + (int)netTime.dwSecond); + return date; + } + + /** + * 比较两个NET_TIME的大小 + * @param time1 + * @param time2 + * @return an int < 0 if time1 is less than time2, 0 if they are equal, and an int > 0 if time1 is greater. + */ + public static int compareNetTime(NET_TIME time1, NET_TIME time2) + { + Date date1 = new Date((int)time1.dwYear - 1900, + (int)time1.dwMonth - 1, + (int)time1.dwDay, + (int)time1.dwHour, + (int)time1.dwMinute, + (int)time1.dwSecond); + + Date date2 = new Date((int)time2.dwYear - 1900, + (int)time2.dwMonth - 1, + (int)time2.dwDay, + (int)time2.dwHour, + (int)time2.dwMinute, + (int)time2.dwSecond); + return date1.compareTo(date2); + + } + public static boolean isToday(Calendar calendar) { + if(calendar == null){ + return false; + } + Calendar now = Calendar.getInstance(); + boolean isToday = now.get(Calendar.YEAR) == calendar + .get(Calendar.YEAR) + && (now.get(Calendar.MONTH) + 1) == (calendar + .get(Calendar.MONTH) + 1) + && now.get(Calendar.DATE) == calendar.get(Calendar.DATE) + ; + return isToday; + } + + public static boolean isTodayOrBefore(Calendar calendar) { + if(calendar == null){ + return false; + } + Calendar now = Calendar.getInstance(); + + boolean isTodayOrBefore = now.get(Calendar.YEAR) == calendar + .get(Calendar.YEAR) + && (now.get(Calendar.MONTH) + 1) == (calendar + .get(Calendar.MONTH) + 1) + && now.get(Calendar.DATE) == calendar.get(Calendar.DATE) + || calendar.before(now); + return isTodayOrBefore; + } + + public static boolean isBeforeToday(Calendar calendar) { + if(calendar == null){ + return false; + } + Calendar now = Calendar.getInstance(); + + boolean isTodayOrAfter = now.get(Calendar.YEAR) == calendar.get(Calendar.YEAR) + && (now.get(Calendar.MONTH) + 1) == (calendar.get(Calendar.MONTH) + 1) + && now.get(Calendar.DATE) == calendar.get(Calendar.DATE) + || !calendar.before(now); + return !isTodayOrAfter; + } + public static boolean isCurrentMonthOrBefore(Calendar calendar) { + if(calendar == null){ + return false; + } + Calendar now = Calendar.getInstance(); + + boolean isCurrentMonthOrBefore = now.get(Calendar.YEAR) == calendar + .get(Calendar.YEAR) + && (now.get(Calendar.MONTH) + 1) == (calendar + .get(Calendar.MONTH) + 1) + || !calendar.before(now); + return !isCurrentMonthOrBefore; + } + + /** + * String2Date + *

+ *

+ * + * @param dateStr + * @param format + * @return + */ + public static Date stringToDate(String dateStr, String format) { + SimpleDateFormat formatter = TimeUtils.getDateFormatWithUS(format); + Date strtodate = null; + try { + strtodate = formatter.parse(dateStr); + } catch (ParseException e) { + e.printStackTrace(); + return new Date(); + } + return strtodate; + } + + /** + * 服务器0时区字符串转换才本地时间 + * @param dateStr + * @param format + * @return + */ + public static long getLocalTimeByString(String dateStr, String format){ + if(TextUtils.isEmpty(dateStr)){ + return 0; + } + + long time = TimeUtils.stringToDate(dateStr, format).getTime(); + return time = time + getTimeZone() * 1000; //加偏移量 + } + + + /** + * long转String + *

+ *

+ * @param milliseconds + * the number of milliseconds since Jan. 1, 1970 GMT. + * @param formatStr + * 要转化成的时间格式 + * @return + */ + public static String long2String(long milliseconds, String formatStr) { + Date date = new Date(milliseconds); + SimpleDateFormat format = TimeUtils.getDateFormatWithUS(formatStr); + return format.format(date); + } + + /** + * string2String + *

+ *

+ * @param dateStr + * 被转换的时间字符串 + * @param formatFrom + * 转化前的时间格式 + * @param formatTo + * 转化后的时间格式 + * @return + */ + public static String string2String(String dateStr, String formatFrom, String formatTo) { + SimpleDateFormat formatF = TimeUtils.getDateFormatWithUS(formatFrom); + try { + Date date = formatF.parse(dateStr); + SimpleDateFormat formatT = TimeUtils.getDateFormatWithUS(formatTo); + return formatT.format(date); + } catch (ParseException e1) { + e1.printStackTrace(); + return dateStr; + } + } + + public static String string2StringForReport(String dateStr, String formatFrom, String formatTo) { + SimpleDateFormat formatF = TimeUtils.getDateFormatWithUS(formatFrom); + try { + Date date = formatF.parse(dateStr); + SimpleDateFormat formatT = TimeUtils.getDateFormatWithUS(formatTo); + return formatT.format(date); + } catch (ParseException e1) { + e1.printStackTrace(); + return "--"; + } + } + + /** + * date2Str + *

+ *

+ * @param d + * 被转化的Date + * @param format + * 转化格式 + * @return + */ + public static String date2String(Date d, String format) { + if(d == null) { + return ""; + } + SimpleDateFormat formatter = TimeUtils.getDateFormatWithUS(format); + return formatter.format(d); + } + + public static Date string2hhmm(String strDate) { + Date mDate = stringToDate2(strDate, LONG_FORMAT); + if (mDate == null) { + mDate = stringToDate2(strDate, SHORT_FORMAT); + } + if (mDate == null) { + mDate = stringToDate2(strDate, SIMPLE_FORMAT); + } + return mDate; + } + + private static Date stringToDate2(String dateStr, String format) { + SimpleDateFormat formatter = TimeUtils.getDateFormatWithUS(format); + Date strtodate = null; + try { + strtodate = formatter.parse(dateStr); + } catch (ParseException e) { + e.printStackTrace(); + } + return strtodate; + } + + + + public static String getNewRequestTime(long time){ + Date d = new Date(time); + return date2String(d,REQUEST_DATE_FORMAT)+"T"+date2String(d,SHORT_FORMAT2); + } + + public static long getResponseTime(String dateString){ + if(dateString==null) + return 0; + if(dateString.contains("T")){ + dateString = dateString.replace("T" ,""); + } + Date date = stringToDate(dateString,REQUEST_FORMAT); + if (date == null) + return 0; + return date.getTime(); + } + + /** + * 获取时间戳 + * @param dateString 0时区的时间 + * @return + */ + public static long getResponseStamp(String dateString){ + if(dateString==null) + return 0; + if(dateString.contains("T")){ + dateString = dateString.replace("T" ,""); + } + + SimpleDateFormat formatter = TimeUtils.getDateFormatWithUS(REQUEST_FORMAT); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Date strtodate = null; + try { + strtodate = formatter.parse(dateString); + } catch (ParseException e) { + e.printStackTrace(); + } + + if (strtodate == null) + return 0; + return strtodate.getTime(); + } + public static String setOnceTime(String time) { + Date d = string2hhmm(time); + Date now = new Date(); + if (d!=null && d.before(now)) { + // 加一天 + long tomorro = d.getTime() + 24 * 60 * 60 * 1000; + Date tomorr = new Date(tomorro); + return date2String(tomorr, LONG_FORMAT); + } + return date2String(d, LONG_FORMAT); + } + + /** + * 格式化显示时间 + * + * @param inputTime + * 毫秒 + * @param inputTime 输入时间(UNIX时间戳毫秒) + * @return + */ + public static String displayTime(long inputTime, String todayFormatStr, String yesterdayFormatStr, + String otherFormatStr) { + // 日期格式化 + SimpleDateFormat todayFormat = todayFormatStr != null ? TimeUtils.getDateFormatWithUS(todayFormatStr) : null; + SimpleDateFormat yesterdayFormat = yesterdayFormatStr != null ? TimeUtils.getDateFormatWithUS(yesterdayFormatStr) : null; + SimpleDateFormat otherFormat = otherFormatStr != null ? TimeUtils.getDateFormatWithUS(otherFormatStr) : null; + String timeStr = null; + + // 获取当前凌晨时间 + Calendar c = Calendar.getInstance(); + String getYear = String.valueOf(c.get(Calendar.YEAR)); + String getMonth = String.valueOf(c.get(Calendar.MONTH) + 1); + String getDayOfMonth = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); + if (getMonth.length() == 1) { + getMonth = "0" + getMonth; + } + if (getDayOfMonth.length() == 1) { + getDayOfMonth = "0" + getDayOfMonth; + } + String currentStartTimeStr = getYear + "-" + getMonth + "-" + getDayOfMonth + " 00:00:00"; + + // 当前凌晨时间格式转换 + java.sql.Timestamp currentStartTime = java.sql.Timestamp.valueOf(currentStartTimeStr); + long currentStart = currentStartTime.getTime(); + + // 与当前凌晨时间相差秒数 + long timeGap = (currentStart - inputTime) / 1000; + + // 输入时间:年 + if (timeGap <= 0) { + timeStr = todayFormat != null ? todayFormat.format(inputTime) : "今天 "; // 今天格式:10:00 + } else if (timeGap > 0 && timeGap <= 24 * 60 * 60) { + timeStr = yesterdayFormat != null ? yesterdayFormat.format(inputTime) : "昨天 "; // 昨天格式:昨天 + } else { + timeStr = otherFormat != null ? otherFormat.format(inputTime) : String.valueOf(inputTime); // 其他格式:15/09/03 + } + + return timeStr; + } + + /** + * 我的文件、报警消息列表悬停头的文案 今天 、昨天、 05/07、15/12/19 + * + * @param strTimestamp + * 输入时间(格式:"yyyy-MM-dd HH:mm:ss") + * @return + */ + public static String getStickxinzaieader(String strTimestamp) { + // 日期格式化 + SimpleDateFormat xinzai = TimeUtils.getDateFormatWithUS("yy/MM/dd"); + SimpleDateFormat mh = TimeUtils.getDateFormatWithUS("MM/dd"); + SimpleDateFormat y = TimeUtils.getDateFormatWithUS("yyyy"); + String timeStr = null; + + // 获取当前凌晨时间 + Calendar c = Calendar.getInstance(); + String getYear = String.valueOf(c.get(Calendar.YEAR)); + String getMonth = String.valueOf(c.get(Calendar.MONTH) + 1); + String getDayOfMonth = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); + if (getMonth.length() == 1) { + getMonth = "0" + getMonth; + } + if (getDayOfMonth.length() == 1) { + getDayOfMonth = "0" + getDayOfMonth; + } + String currentStartTimeStr = getYear + "-" + getMonth + "-" + getDayOfMonth + " 00:00:00"; + + // 当前凌晨时间格式转换 + java.sql.Timestamp currentStartTime = java.sql.Timestamp.valueOf(currentStartTimeStr); + long currentStart = currentStartTime.getTime(); + + // 输入时间格式转换 + java.sql.Timestamp time = java.sql.Timestamp.valueOf(strTimestamp); + long timestamp = time.getTime(); + + // 与当前凌晨时间相差秒数 + long timeGap = (currentStart - timestamp) / 1000; + + // 输入时间:年 + String year = y.format(timestamp); + + if (timeGap <= 0) { + timeStr = "今天 "; // 格式:今天 + } else if (timeGap > 0 && timeGap <= 24 * 60 * 60) { + timeStr = "昨天 "; // 格式:昨天 + } else if (year.equals(String.valueOf(getYear))) { + timeStr = mh.format(timestamp); // (年内)MM月dd日 + } else { + timeStr = xinzai.format(timestamp); // (年前)格式:yyyy年MM月dd日 + } + + return timeStr; + } + + /** + * 我的文件、报警消息列表悬停头的文案 今天 、昨天、 05/07、15/12/19 + * + * @param timestamp 输入时间UNIX时间戳毫秒 + * @return + */ + public static String getStickxinzaieader(long timestamp) { + // 日期格式化 + SimpleDateFormat xinzai = TimeUtils.getDateFormatWithUS("yy/MM/dd"); + SimpleDateFormat mh = TimeUtils.getDateFormatWithUS("MM/dd"); + SimpleDateFormat y = TimeUtils.getDateFormatWithUS("yyyy"); + String timeStr = null; + + // 获取当前凌晨时间 + Calendar c = Calendar.getInstance(); + String getYear = String.valueOf(c.get(Calendar.YEAR)); + String getMonth = String.valueOf(c.get(Calendar.MONTH) + 1); + String getDayOfMonth = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); + if (getMonth.length() == 1) { + getMonth = "0" + getMonth; + } + if (getDayOfMonth.length() == 1) { + getDayOfMonth = "0" + getDayOfMonth; + } + String currentStartTimeStr = getYear + "-" + getMonth + "-" + getDayOfMonth + " 00:00:00"; + + // 当前凌晨时间格式转换 + java.sql.Timestamp currentStartTime = java.sql.Timestamp.valueOf(currentStartTimeStr); + long currentStart = currentStartTime.getTime(); + + // 与当前凌晨时间相差秒数 + long timeGap = (currentStart - timestamp) / 1000; + + // 输入时间:年 + String year = y.format(timestamp); + + if (timeGap <= 0) { + timeStr = "今天 "; // 格式:今天 + } else if (timeGap > 0 && timeGap <= 24 * 60 * 60) { + timeStr = "昨天 "; // 格式:昨天 + } else if (year.equals(String.valueOf(getYear))) { + timeStr = mh.format(timestamp); // (年内)MM月dd日 + } else { + timeStr = xinzai.format(timestamp); // (年前)格式:yyyy年MM月dd日 + } + + return timeStr; + } + + /** + * 获取当前年的第一天 + *

+ *

+ * + * @return + */ + public static Date getCurrentYearFirst() { + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + return getYearFirst(year); + } + /** + * 获取某一年的第一天 + *

+ *

+ * @param year + * @return + */ + public static Date getYearFirst(int year) { + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.set(Calendar.YEAR, year); + Date firstDay = calendar.getTime(); + return firstDay; + } + + /** + * 获取当前年的最后一天 + *

+ *

+ * @return + */ + public static Date getCurrentYearLast() { + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + return getYearLast(year); + } + /** + * 获取某一年的最后一天 + *

+ *

+ * @param year + * @return + */ + public static Date getYearLast(int year) { + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.set(Calendar.YEAR, year); + calendar.roll(Calendar.DAY_OF_YEAR, -1); + Date lastDay = calendar.getTime(); + return lastDay; + } + + /** + * 在输入Date的基础上加/减某段时间,返回一个新的Date + *

+ *

+ * @param date + * @param field + * @param value + * @return + */ + public static Date add(Date date, int field, int value) { + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.setTime(date); + calendar.add(field, value); + return calendar.getTime(); + } + + + /** + * 直播分享时间格式 + */ + public static String getTime(long time) { + time = time +System.currentTimeMillis(); + Date date = new Date(time); + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("MM月dd日 HH:mm"); + return format.format(date); + + } + + public static String getTimeSec() { + Date date = new Date(System.currentTimeMillis()); + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm:ss"); + return format.format(date); + + } + + /*用户融合添加*/ + + /*获取手机时区----UTC格式*/ + public static int getTimeZone(){ + Calendar cal = Calendar.getInstance(Locale.getDefault()); + int zoneOffset = cal.get(Calendar.ZONE_OFFSET); + int zone = zoneOffset/1000; + + return zone; + } + + /*获取时间字符串:从yyyyMMddTHHmmssZ时间格式到yyyy-MM-dd HH:mm*/ + public static String getTimeFromUTC(String timeStr) { + if(TextUtils.isEmpty(timeStr)) { + return ""; + } + Date timeDate = TimeUtils.stringToDate(timeStr, "yyyyMMdd'T'HHmmss'Z'"); + if(timeDate == null) { + return ""; + } + long time = timeDate.getTime(); +// time = time + getTimeZone() * 1000; //加偏移量 + Date date = new Date(time); + SimpleDateFormat sdf = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm"); + return sdf.format(date); + } + + /** + * 我的文件、报警消息列表悬停头的文案 今天 、昨天、 05/07、15/12/19 + * + * @param context 上下文 + * @param timestamp 输入时间UNIX时间戳毫秒 + * @return + */ + public static String getStickxinzaieader(Context context,long timestamp) { + // 日期格式化 + SimpleDateFormat xinzai = TimeUtils.getDateFormatWithUS("yy/MM/dd"); + SimpleDateFormat mh = TimeUtils.getDateFormatWithUS("MM/dd"); + SimpleDateFormat y = TimeUtils.getDateFormatWithUS("yyyy"); + String timeStr = null; + + // 获取当前凌晨时间 + Calendar c = Calendar.getInstance(); + String getYear = String.valueOf(c.get(Calendar.YEAR)); + String getMonth = String.valueOf(c.get(Calendar.MONTH) + 1); + String getDayOfMonth = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); + if (getMonth.length() == 1) { + getMonth = "0" + getMonth; + } + if (getDayOfMonth.length() == 1) { + getDayOfMonth = "0" + getDayOfMonth; + } + String currentStartTimeStr = getYear + "-" + getMonth + "-" + getDayOfMonth + " 00:00:00"; + + // 当前凌晨时间格式转换 + java.sql.Timestamp currentStartTime = java.sql.Timestamp.valueOf(currentStartTimeStr); + long currentStart = currentStartTime.getTime(); + + // 与当前凌晨时间相差秒数 + long timeGap = (currentStart - timestamp) / 1000; + + // 输入时间:年 + String year = y.format(timestamp); + + if (timeGap <= 0) { + timeStr = context.getResources().getString(R.string.common_today); // 格式:今天 + } else if (timeGap > 0 && timeGap <= 24 * 60 * 60) { + timeStr = context.getResources().getString(R.string.common_yesterday); // 格式:昨天 + } else if (year.equals(String.valueOf(getYear))) { + timeStr = mh.format(timestamp); // (年内)MM月dd日 + } else { + timeStr = xinzai.format(timestamp); // (年前)格式:yyyy年MM月dd日 + } + + return timeStr; + } + + //获取当前时区与0时区差值 + public static int getTimeOffset(){ + Calendar calendar=Calendar.getInstance(TimeZone.getDefault()); + int offset=calendar.get(Calendar.ZONE_OFFSET); + return offset/1000; + } + + /** + * + * @param time 带时区的时间戳(时间单位为mS) + * @return + */ + public static long change2UTC(long time) { + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm:ss"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + String timeStr=format.format(new Date(time)); + Date date = string2hhmm(timeStr); + return date != null ? date.getTime() : 0; + } + + /** + * + * @param time UTC时间戳(时间单位为mS) + * @return + */ + public static long change2Local(long time){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm:ss"); + format.setTimeZone(TimeZone.getDefault()); + String timeStr=format.format(new Date(time + getTimeOffset() * 1000)); + Date date = string2hhmm(timeStr); + return date != null ? date.getTime() : 0; + } + + /** + *将服务返回的时间字串格式转换为yyyy-MM-dd HH:mm:ss格式 + * @param time 服务返回设备时间 + * @return + */ + public static String changeTimeFormat2Standard(String time){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyyMMdd'T'HHmmss"); + Date date=null; + try { + date=format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + SimpleDateFormat standardFormat = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm:ss"); + String standardTimeStr=date==null?"":standardFormat.format(date); + return standardTimeStr; + } + + /** + *将服务返回的时间字串格式转换为MM-dd HH:mm格式 + * @param time 服务返回设备时间 + * @return + */ + public static String changeTimeFormat2StandardNoYear(String time){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyyMMdd'T'HHmmss"); + Date date=null; + try { + date=format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + SimpleDateFormat standardFormat = TimeUtils.getDateFormatWithUS("MM-dd HH:mm:ss"); + String standardTimeStr=date==null?"":standardFormat.format(date); + return standardTimeStr; + } + + /** + *将服务返回的时间字串格式转换为yyyy-MM-dd HH:mm格式 + * @param time 服务返回设备时间 + * @return + */ + public static String changeTimeFormat2StandardMin(String time){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyyMMdd'T'HHmmss"); + Date date=null; + try { + date=format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + SimpleDateFormat standardFormat = TimeUtils.getDateFormatWithUS("yyyy-MM-dd HH:mm"); + String standardTimeStr=date==null?"":standardFormat.format(date); + return standardTimeStr; + } + + /** + *将服务返回的时间字串格式转换为长整型 + * @param time 服务返回设备时间 + * @return + */ + public static long changeTimeStrToStamp(String time){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyyMMdd'T'HHmmss"); + Date date=null; + try { + date=format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + long timeStamp=date==null?0:date.getTime(); + return timeStamp; + } + + /** + *将服务返回的时间字串格式转换为outTimeformat格式 + * @param time 服务返回设备时间 + * @param outTimeformat 自定义时间格式 , 0时区时间转换 + * @return + */ + public static String changeTimeFormat2StandardMinByDateFormat(String time,String outTimeformat){ + SimpleDateFormat format = TimeUtils.getDateFormatWithUS("yyyyMMdd'T'HHmmss'Z'"); + Date date=null; + try { + date=format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + }catch (NullPointerException e){ + e.printStackTrace(); + } + SimpleDateFormat standardFormat = TimeUtils.getDateFormatWithUS(outTimeformat); + if(date == null)return ""; + date.setTime(date.getTime()+ TimeUtils.getTimeZone() * 1000);//加偏移量 + String standardTimeStr= standardFormat.format(date); + return standardTimeStr; + } + + //返回 0时区 毫秒值 + public static long changeTime2UTCStamp(String time, String dateFormat) { + SimpleDateFormat format = TimeUtils.getDateFormatWithUS(dateFormat); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = null; + try { + date = format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return date == null ? 0 : date.getTime(); + } + + /** + * 不带年份的时间转时间戳 + * @param time + * @return + */ + public static long changeDateToUnix(String time) { + SimpleDateFormat sdf = TimeUtils.getDateFormatWithUS("MM-dd HH:mm"); + Date date = new Date(); + try { + date = sdf.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return date.getTime(); + } + + + /** + * 转成大华标准时间 yyyyMMddTHHmmss + * @return + */ + public static String changeTimeFormat(String timeFormat) { + try { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + return String.format(timeFormat, + calendar.get(Calendar.YEAR), + (calendar.get(Calendar.MONTH) + 1), + calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND)); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 按周设置夏令时,保存时将 + * Mar 2nd Sun 00:00 + * 格式转换成 + * 3-2-0 00:00:00 格式 + * 3--1-1 代表三月最后一个周一 + * 月份 "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" + 第几个 "1st","2nd","3rd","4th","5th" + 周几 "Mon","Tue","Wed","Thu","Fri","Sat","Sun" + + 月,是从1开始,1~12 + 周是从1开始,1~4,以及-1,-1表示最后一周,或第四周是最后一周,也可以用4表示 + 从0~6,0表示周日 + + * @param time + * @return + */ + private static final String[] months = new String[]{"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; + private static final String[] numweeks = new String[]{"1st","2nd","3rd","4th","last"}; + private static final String[] weekDays = new String[]{"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}; + + public static String changeEngStrToNumStr(String time) + { + StringBuffer buffer = new StringBuffer(); + if(!TextUtils.isEmpty(time)) + { + String[] array = time.split(" "); + if(array!=null && array.length==4) + { + String month = array[0]; + String numWeek = array[1]; + String weekDay = array[2]; + String date = array[3]; + + for(int i=0; i11) + { + return ""; + }else + { + buffer.append(months[index]).append(" "); + } + }else + { + int index = Integer.parseInt(month)-1; + if(index<0 || index>11) + { + return ""; + }else + { + buffer.append(months[index]).append(" "); + } + } + } + + if(hasLastFlag) + { + buffer.append("last").append(" "); + + }else if(numWeek!=null && !numWeek.equalsIgnoreCase("last")) + { + int index = Integer.parseInt(numWeek.substring(1))-1; + if(index<0 || index >4) + { + return ""; + }else + { + buffer.append(numweeks[index]).append(" "); + } + } + + if(weekDay!=null && weekDay.equals("00")) //00 是周日,不能按常规判断 + { + buffer.append(weekDays[6]).append(" "); + } + else if(weekDay!=null && weekDay.length()==2 && !weekDay.equals("00")) + { + int index = Integer.parseInt(weekDay.substring(1))-1; + if(index<0 || index >6) + { + return ""; + }else + { + buffer.append(weekDays[index]).append(" "); + } + } + buffer.append(hour).append(":").append(minute); + } + return buffer.toString(); + } + + /** + * 使用默认英语格式化时间,避免多语言环境下(如阿拉伯语)格式化的时间服务器无法识别 + * @param formate + * @return + */ + public static SimpleDateFormat getDateFormatWithUS(String formate){ + return new SimpleDateFormat(formate, Locale.US); + } + + /** + * 计算两时间戳相差天数 + * @param startTime + * @param endTime + * @return + */ + public static long dateDiff(long startTime, long endTime) { + long nd = 24 * 60 * 60;// 一天的秒数 + long nh = 60 * 60;// 一小时的秒数 + long nm = 60;// 一分钟的秒数 + long ns = 1;// 一秒钟的秒数 + long diff; + long day = 0; + // 获得两个时间的毫秒时间差异 + diff = endTime - startTime; + day = diff / nd;// 计算差多少天 + long hour = diff % nd / nh;// 计算差多少小时 + long min = diff % nd % nh / nm;// 计算差多少分钟 + long sec = diff % nd % nh % nm / ns;// 计算差多少秒 + if (day >= 1) { + return day; + } else { + if (day == 0) { + return 0; + } else { + return 0; + } + + } + } + + public static long getDateAddDays(int days){ + Calendar c = Calendar.getInstance(); + c.add(Calendar.DAY_OF_MONTH, days); + return c.getTimeInMillis(); + + } + + /** + * 时间戳转换成日期格式字符串 + * @param seconds 精确到秒的字符串 + * @param format + * @return + */ + public static String timeStamp2Date(String seconds,String format) { + if(seconds == null || seconds.isEmpty() || seconds.equals("null")){ + return ""; + } + if(format == null || format.isEmpty()){ + format = "yyyy-MM-dd HH:mm:ss"; + } + SimpleDateFormat sdf = new SimpleDateFormat(format); + return sdf.format(new Date(Long.valueOf(seconds+"000"))); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIHelper.java new file mode 100644 index 0000000..440e2af --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIHelper.java @@ -0,0 +1,110 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; + +public class UIHelper { + /** + * 设置按钮选中与否 + *

+ * @param selected + * @param views + */ + public static void setSelected(boolean selected, View... views) { + for (View view : views) { + view.setSelected(selected); + } + } + + /** + * 设置空间是否可用(不置灰) + *

+ *

+ * @param enabled + * @param views + */ + public static void setEnabled(boolean enabled, View... views) { + for (View view : views) { + view.setEnabled(enabled); + } + } + + /** + * 启用/禁用控件,包括所有子控件 + *

+ *

+ * @param enabled + */ + public static void setEnabledSub(boolean enabled, ViewGroup... viewGroups) { + for (ViewGroup viewGroup : viewGroups) { + viewGroup.setEnabled(enabled); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setEnabledSub(enabled, (ViewGroup) v); + } else { + setEnabled(enabled, v); + } + } + } + } + + /** + * 设置控件可用与否 (置灰) + * + * @param enabled + * 是否可用 + */ + public static void setEnabledEX(boolean enabled, View... views) { + for (View view : views) { + if (enabled) { + view.setEnabled(enabled); + view.clearAnimation(); + } else { + Animation aniAlp = new AlphaAnimation(1f, 0.5f); + aniAlp.setDuration(0); + aniAlp.setInterpolator(new AccelerateDecelerateInterpolator()); + aniAlp.setFillEnabled(true); + aniAlp.setFillAfter(true); + view.startAnimation(aniAlp); + view.setEnabled(enabled); + } + } + } + + /** + * 遍历布局,禁用/启用所有子控件 + *

+ *

+ * @param enabled + */ + public static void setEnabledSubEX(boolean enabled, ViewGroup... viewGroups) { + for (ViewGroup viewGroup : viewGroups) { + setEnabledEX(enabled, viewGroup); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setEnabledSubEX(enabled, (ViewGroup) v); + } else { + setEnabledEX(enabled, v); + } + } + } + } + + /** + * 隐藏/显示 + *

+ *

+ * @param visibility + * @param views + */ + public static void setVisibility(int visibility, View... views) { + for (View view : views) { + view.setVisibility(visibility); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIUtils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIUtils.java new file mode 100644 index 0000000..6991ec8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/UIUtils.java @@ -0,0 +1,989 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.text.TextPaint; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.TouchDelegate; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.EditText; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; + +import java.lang.reflect.Field; +import java.util.List; + +public class UIUtils { + private static final String TAG = "UIUtils"; + private static long mLastClickTime; + + private static float sDensity = -1; + + /** + * 获取屏幕像素密度 + */ + public static float getScreenDensity(Context context) { + if(context == null)return sDensity; + DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); + sDensity = dm.density; + + return dm.density; + } + + + // 将px值转换为dip或dp值,保证尺寸大小不变 + public static int px2dip(DisplayMetrics dM, float pxValue) { + final float scale = dM.density; + return (int) (pxValue / scale + 0.5f); + } + + // 将dip或dp值转换为px值,保证尺寸大小不变 + public static int dip2px(DisplayMetrics dM, float dipValue) { + final float scale = dM.density; + return (int) (dipValue * scale + 0.5f); + } + + /** + * 获取当前屏幕宽度 + */ + public static int getDefaultDialogWidth(Context context) { + return getScreenWidth(context) * 4 / 5; + } + /** + * 获取当前屏幕宽度 + */ + public static int getScreenWidth(Context context) { + if(context == null)return -1; + DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); + return dm.widthPixels; + } + + public static int getDefaultDialogWidthWithLandscape(Context context){ + return getScreenHeight(context) * 4 / 5; + } + + /** + * 获取当前屏幕高度 + */ + public static int getScreenHeight(Context context) { + if(context == null)return -1; + DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); + return dm.heightPixels; + } + + // 将px值转换为dip或dp值,保证尺寸大小不变 + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + // 将dip或dp值转换为px值,保证尺寸大小不变 + public static int dip2px(Context context, float dipValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dipValue * scale + 0.5f); + } + + + // 将px值转换为sp值,保证文字大小不变 + public static int px2sp(Context context, float pxValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (pxValue / fontScale + 0.5f); + } + + // 将sp值转换为px值,保证文字大小不变 + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + // 屏幕宽度(像素) + public static int getWindowWidth(Activity context) { + DisplayMetrics metric = new DisplayMetrics(); + context.getWindowManager().getDefaultDisplay().getMetrics(metric); + return metric.widthPixels; + } + + // 屏幕高度(像素) + public static int getWindowHeight(Activity context) { + DisplayMetrics metric = new DisplayMetrics(); + context.getWindowManager().getDefaultDisplay().getMetrics(metric); + return metric.heightPixels; + } + + + /** + * 检测是否重复点击事件,默认时间为800毫秒 + * + * @return + */ + public static boolean isFastDoubleClick() { + long time = System.currentTimeMillis(); + long timeD = time - mLastClickTime; + if (0 < timeD && timeD < 800) { + return true; + } + mLastClickTime = time; + return false; + } + + /** + * 将当前activity拉到前台 + * + * @param paramActivity + */ + public static void goForeground(Activity paramActivity) { + if (paramActivity == null) return; + Window localWindow = paramActivity.getWindow(); + if (localWindow != null) { + localWindow.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + localWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + localWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + } + } + + + /** + * 检测在规定的时间里面是否重复点击事件 + * + * @return + */ + public static boolean isFastDoubleClick(long elapse) { + long time = System.currentTimeMillis(); + long timeD = time - mLastClickTime; + if (0 < timeD && timeD < elapse) { + return true; + } + mLastClickTime = time; + return false; + } + /** + * 检测在100ms规定的时间里面是否快速触发相同方法两次,针对误触发情况的兼容 + * + * @return + */ + public static boolean isFastCallFuncTwice() { + long time = System.currentTimeMillis(); + long timeD = time - mLastClickTime; + if (0 < timeD && timeD < 100) { + return true; + } + mLastClickTime = time; + return false; + } + /** + * 进入全屏 + * + * @param activity + */ + public static void setFullScreen(Activity activity) { + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + /** + * 退出全屏 + * + * @param activity + */ + public static void quitFullScreen(Activity activity) { + if (activity == null) { + return; + } + final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); + attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); + activity.getWindow().setAttributes(attrs); + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } + + /** + * 输入框禁止复制,粘贴 + * + * @param editText + */ + public static void UnCopyAble(EditText editText) { + if (editText == null) { + return; + } + editText.setLongClickable(false); + } + + /** + * 获取状态栏高度 + *

+ *

+ */ + public static int getStatusBarHeight(Context context) { + Class c = null; + Object object = null; + Field field = null; + int x = 0; + int statusBar = 0; + try { + c = Class.forName("com.android.internal.R$dimen"); + object = c.newInstance(); + field = c.getField("status_bar_height"); + x = Integer.parseInt(field.get(object).toString()); + statusBar = context.getResources().getDimensionPixelSize(x); + } catch (Exception e) { + e.printStackTrace(); + } + return statusBar == 0 ? dp2px(context, 20) : statusBar; + } + + /** + * 设置按钮选中与否 + *

+ *

+ * + * @param selected + * @param views + */ + public static void setSelected(boolean selected, View... views) { + for (View view : views) { + view.setSelected(selected); + } + } + + public static void setSelected(boolean selected, ViewGroup... viewGroups) { + for (ViewGroup viewGroup : viewGroups) { + viewGroup.setSelected(selected); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setSelected(selected, (ViewGroup) v); + } else { + setSelected(selected, v); + } + } + } + } + + /** + * 设置空间是否可用(不置灰) + *

+ *

+ * + * @param enabled + * @param views + */ + public static void setEnabled(boolean enabled, View... views) { + for (View view : views) { + view.setEnabled(enabled); + } + } + + /** + * 启用/禁用控件,包括所有子控件 + */ + public static void setEnabledSub(boolean enabled, ViewGroup... viewGroups) { + for (ViewGroup viewGroup : viewGroups) { + viewGroup.setEnabled(enabled); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setEnabledSub(enabled, (ViewGroup) v); + } else { + setEnabled(enabled, v); + } + } + } + } + + /** + * 启用/禁用 item + *

+ * @param enabled + * @param viewGroup + * @param tv + */ + public static void setDevDetailItemEnable(boolean enabled, ViewGroup viewGroup, TextView tv) { + setEnabledSub(enabled, viewGroup); + + if (tv == null) { + return; + } + if (enabled) { + tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.mobile_common_icon_nextarrow, 0); + } else { + tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + } + + /** + * 设置控件可用与否 (置灰) + * + * @param views 被设置的控件 + * @param enabled 是否可用 + */ + public static void setEnabledEX(boolean enabled, View... views) { + for (View view : views) { + if (enabled) { + view.setEnabled(enabled); + view.clearAnimation(); + } else { + Animation aniAlp = new AlphaAnimation(1f, 0.5f); + aniAlp.setDuration(0); + aniAlp.setInterpolator(new AccelerateDecelerateInterpolator()); + aniAlp.setFillEnabled(true); + aniAlp.setFillAfter(true); + view.startAnimation(aniAlp); + view.setEnabled(enabled); + } + } + } + + /** + * 遍历布局,禁用/启用所有子控件 + *

+ *

+ * + * @param viewGroup + * @param enabled + */ + public static void setEnabledSubControls(ViewGroup viewGroup, boolean enabled) { + setEnabledEX(enabled, viewGroup); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setEnabledSubControls((ViewGroup) v, enabled); + } else { + setEnabledEX(enabled, v); + } + } + } + + /** + * 隐藏/显示 + *

+ *

+ * + * @param visibility + * @param views + */ + public static void setVisibility(int visibility, View... views) { + for (View view : views) { + view.setVisibility(visibility); + } + } + + public static void expandViewTouchDelegate(final View view, final int top, final int bottom, final int left, + final int right) { + + ((View) view.getParent()).post(new Runnable() { + + @Override + public void run() { + Rect bounds = new Rect(); + view.setEnabled(true); + view.getHitRect(bounds); + + bounds.top -= top; + bounds.bottom += bottom; + bounds.left -= left; + bounds.right += right; + + TouchDelegate touchDelegate = new TouchDelegate(bounds, view); + + if (View.class.isInstance(view.getParent())) { + ((View) view.getParent()).setTouchDelegate(touchDelegate); + } + + } + }); + } + + + /** + * 设置一组控件显隐 + * + * @param views + * @param flags + */ + public static void setViewsVisibility(View[] views, int[] flags) { + if (views == null) { + return; + } + for (int i = 0; i < views.length; i++) { + if (views[i] != null) views[i].setVisibility(i < flags.length ? flags[i] : View.GONE); + } + } + + /** + * 设置控件显隐 + * + * @param view + * @param flag + */ + public static void setViewVisibility(View view, int flag) { + if (view == null) { + return; + } + view.setVisibility(flag); + } + + public static void setEnableWithAlphaChanged(View view, boolean enable) { + if (view == null) { + return; + } + view.setEnabled(enable); + view.setAlpha(enable ? 1f : 0.5f); + } + + public static void setEnabledAllInGroup(ViewGroup viewGroup, boolean enabled) { + if (viewGroup == null) { + return; + } + viewGroup.setEnabled(enabled); + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View v = viewGroup.getChildAt(i); + if (v instanceof ViewGroup) { + setEnabledAllInGroup((ViewGroup) v, enabled); + } else { + v.setEnabled(enabled); + } + } + } + + public static int getEncryV2(int byAuthMode, int byEncrAlgr) { + int nEncryption = 0; + + if(byAuthMode == 6 && byEncrAlgr == 0) + { + nEncryption = 0; + } + else if(byAuthMode == 0 && byEncrAlgr == 0) + { + nEncryption = 1; + } + else if(byAuthMode == 0 && byEncrAlgr == 4) + { + nEncryption = 2; + } + else if(byAuthMode == 1 && byEncrAlgr == 4) + { + nEncryption = 3; + } + else if(byAuthMode == 2 && byEncrAlgr == 5) + { + nEncryption = 4; + } + else if(byAuthMode == 3 && byEncrAlgr == 5) + { + nEncryption = 5; + } + else if(byAuthMode == 4 && byEncrAlgr == 5) + { + nEncryption = 6; + } + else if(byAuthMode == 5 && byEncrAlgr == 5) + { + nEncryption = 7; + } + else if(byAuthMode == 2 && byEncrAlgr == 6) + { + nEncryption = 8; + } + else if(byAuthMode == 3 && byEncrAlgr == 6) + { + nEncryption = 9; + } + else if(byAuthMode == 4 && byEncrAlgr == 6) + { + nEncryption = 10; + } + else if(byAuthMode == 5 && byEncrAlgr == 6) + { + nEncryption = 11; + } + else if(byAuthMode == 2 && byEncrAlgr == 7) + { + nEncryption = 8; // 4或者8 + } + else if(byAuthMode == 3 && byEncrAlgr == 7) + { + nEncryption = 9; // 5或9 + } + else if(byAuthMode == 4 && byEncrAlgr == 7) + { + nEncryption = 10; // 6或10 + } + else if(byAuthMode == 5 && byEncrAlgr == 7) + { + nEncryption = 11; // 7或11 + } + else if(byAuthMode == 7) // 混合模式WPA-PSK|WPA2-PSK 3或5 + { + if(byEncrAlgr == 5) { + nEncryption = 7; // 5或7 + } + else if(byEncrAlgr == 6) + { + nEncryption = 11; // 9或11 + } + else if(byEncrAlgr == 7) + { + nEncryption = 11; // 5或7或9或11 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 8) // 混合模式WPA|WPA2 2或4 + { + if(byEncrAlgr == 5) { + nEncryption = 6; // 4或6 + } + else if(byEncrAlgr == 6) + { + nEncryption = 10; // 8或10 + } + else if(byEncrAlgr == 7) + { + nEncryption = 10; // 4或6或8或10 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 9) // 混合模式WPA|WPA-PSK 2或3 + { + if(byEncrAlgr == 5) { + nEncryption = 5; // 4或5 + } + else if(byEncrAlgr == 6) + { + nEncryption = 9; // 8或9 + } + else if(byEncrAlgr == 7) + { + nEncryption = 9; // 4或5或8或9 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 10) // 混合模式WPA2|WPA2-PSK 4或5 + { + if(byEncrAlgr == 5) { + nEncryption = 7; // 6或7 + } + else if(byEncrAlgr == 6) + { + nEncryption = 11; // 10或11 + } + else if(byEncrAlgr == 7) + { + nEncryption = 11; // 6或7或10或11 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 11) // 混合模式WPA|WPA-PSK|WPA2|WPA2-PSK 2或3或4或5 + { + if(byEncrAlgr == 5) { + nEncryption = 7; // 4或5或6或7 + } + else if(byEncrAlgr == 6) + { + nEncryption = 11; // 8或9或10或11 + } + else if(byEncrAlgr == 7) + { + nEncryption = 11; // 4或5或6或7或8或9或10或11 + } + else + { + nEncryption = 12; + } + } else { + nEncryption = 12; + } + return nEncryption; + } + + public static int getEncry(int byAuthMode, int byEncrAlgr) { + int nEncryption = 0; + + if(byAuthMode == 6 && byEncrAlgr == 0) + { + nEncryption = 0; + } + else if(byAuthMode == 0 && byEncrAlgr == 0) + { + nEncryption = 1; + } + else if(byAuthMode == 0 && byEncrAlgr == 1) + { + nEncryption = 2; + } + else if(byAuthMode == 1 && byEncrAlgr == 1) + { + nEncryption = 3; + } + else if(byAuthMode == 2 && byEncrAlgr == 2) + { + nEncryption = 4; + } + else if(byAuthMode == 3 && byEncrAlgr == 2) + { + nEncryption = 5; + } + else if(byAuthMode == 4 && byEncrAlgr == 2) + { + nEncryption = 6; + } + else if(byAuthMode == 5 && byEncrAlgr == 2) + { + nEncryption = 7; + } + else if(byAuthMode == 2 && byEncrAlgr == 3) + { + nEncryption = 8; + } + else if(byAuthMode == 3 && byEncrAlgr == 3) + { + nEncryption = 9; + } + else if(byAuthMode == 4 && byEncrAlgr == 3) + { + nEncryption = 10; + } + else if(byAuthMode == 5 && byEncrAlgr == 3) + { + nEncryption = 11; + } + else if(byAuthMode == 2 && byEncrAlgr == 4) + { + nEncryption = 8; // 4或者8 + } + else if(byAuthMode == 3 && byEncrAlgr == 4) + { + nEncryption = 9; // 5或9 + } + else if(byAuthMode == 4 && byEncrAlgr == 4) + { + nEncryption = 10; // 6或10 + } + else if(byAuthMode == 5 && byEncrAlgr == 4) + { + nEncryption = 11; // 7或11 + } + else if(byAuthMode == 7) // 混合模式WPA-PSK|WPA2-PSK 3或5 + { + if(byEncrAlgr == 2) { + nEncryption = 7; // 5或7 + } + else if(byEncrAlgr == 3) + { + nEncryption = 11; // 9或11 + } + else if(byEncrAlgr == 4) + { + nEncryption = 11; // 5或7或9或11 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 8) // 混合模式WPA|WPA2 2或4 + { + if(byEncrAlgr == 2) { + nEncryption = 6; // 4或6 + } + else if(byEncrAlgr == 3) + { + nEncryption = 10; // 8或10 + } + else if(byEncrAlgr == 4) + { + nEncryption = 10; // 4或6或8或10 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 9) // 混合模式WPA|WPA-PSK 2或3 + { + if(byEncrAlgr == 2) { + nEncryption = 5; // 4或5 + } + else if(byEncrAlgr == 3) + { + nEncryption = 9; // 8或9 + } + else if(byEncrAlgr == 4) + { + nEncryption = 9; // 4或5或8或9 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 10) // 混合模式WPA2|WPA2-PSK 4或5 + { + if(byEncrAlgr == 2) { + nEncryption = 7; // 6或7 + } + else if(byEncrAlgr == 3) + { + nEncryption = 11; // 10或11 + } + else if(byEncrAlgr == 4) + { + nEncryption = 11; // 6或7或10或11 + } + else + { + nEncryption = 12; + } + } + else if(byAuthMode == 11) // 混合模式WPA|WPA-PSK|WPA2|WPA2-PSK 2或3或4或5 + { + if(byEncrAlgr == 2) { + nEncryption = 7; // 4或5或6或7 + } + else if(byEncrAlgr == 3) + { + nEncryption = 11; // 8或9或10或11 + } + else if(byEncrAlgr == 4) + { + nEncryption = 11; // 4或5或6或7或8或9或10或11 + } + else + { + nEncryption = 12; + } + } else { + nEncryption = 12; + } + return nEncryption; + } + + public static int getEncry4Sc(int byAuthMode, int byEncrAlgr) { + + int nEncryption = 0; + + if (byAuthMode == 6 && byEncrAlgr == 0) { + nEncryption = 0; + } else if (byAuthMode == 0 && byEncrAlgr == 0) { + nEncryption = 1; + } else if (byAuthMode == 0 && byEncrAlgr == 4) { + nEncryption = 13; + } else if (byAuthMode == 1 && byEncrAlgr == 4) { + nEncryption = 14; + } else if (byAuthMode == 2 && byEncrAlgr == 5) { + nEncryption = 8; + } else if (byAuthMode == 3 && byEncrAlgr == 5) { + nEncryption = 4; + } else if (byAuthMode == 4 && byEncrAlgr == 5) { + nEncryption = 10; + } else if (byAuthMode == 5 && byEncrAlgr == 5) { + nEncryption = 6; + } else if (byAuthMode == 2 && byEncrAlgr == 6) { + nEncryption = 9; + } else if (byAuthMode == 3 && byEncrAlgr == 6) { + nEncryption = 5; + } else if (byAuthMode == 4 && byEncrAlgr == 6) { + nEncryption = 11; + } else if (byAuthMode == 5 && byEncrAlgr == 6) { + nEncryption = 7; + } else if (byAuthMode == 2 && byEncrAlgr == 7) { + nEncryption = 9; // 8或者9 + } else if (byAuthMode == 3 && byEncrAlgr == 7) { + nEncryption = 5; // 4或5 + } else if (byAuthMode == 4 && byEncrAlgr == 7) { + nEncryption = 11; // 10或11 + } else if (byAuthMode == 5 && byEncrAlgr == 7) { + nEncryption = 7; // 6或7 + } else if (byAuthMode == 7) // 混合模式WPA-PSK|WPA2-PSK 3或5 + { + if (byEncrAlgr == 5) { + nEncryption = 6; // 4或6 + } else if (byEncrAlgr == 6) { + nEncryption = 7; // 5或7 + } else if (byEncrAlgr == 7) { + nEncryption = 7; // 4或5或6或7 + } else { + nEncryption = 12; + } + } else if (byAuthMode == 8) // 混合模式WPA|WPA2 2或4 + { + if (byEncrAlgr == 5) { + nEncryption = 10; // 8或10 + } else if (byEncrAlgr == 6) { + nEncryption = 11; // 9或11 + } else if (byEncrAlgr == 7) { + nEncryption = 10; // 8或9或10或11 + } else { + nEncryption = 12; + } + } else if (byAuthMode == 9) // 混合模式WPA|WPA-PSK 2或3 + { + if (byEncrAlgr == 5) { + nEncryption = 8; // 4或8 + } else if (byEncrAlgr == 6) { + nEncryption = 9; // 5或9 + } else if (byEncrAlgr == 7) { + nEncryption = 9; // 4或5或8或9 + } else { + nEncryption = 12; + } + } else if (byAuthMode == 10) // 混合模式WPA2|WPA2-PSK 4或5 + { + if (byEncrAlgr == 5) { + nEncryption = 10; // 6或10 + } else if (byEncrAlgr == 6) { + nEncryption = 11; // 7或11 + } else if (byEncrAlgr == 7) { + nEncryption = 11; // 6或7或10或11 + } else { + nEncryption = 12; + } + } else if (byAuthMode == 11) // 混合模式WPA|WPA-PSK|WPA2|WPA2-PSK 2或3或4或5 + { + if (byEncrAlgr == 5) { + nEncryption = 10; // 4或6或8或10 + } else if (byEncrAlgr == 6) { + nEncryption = 11; // 5或7或9或11 + } else if (byEncrAlgr == 7) { + nEncryption = 11; // 4或5或6或7或8或9或10或11 + } else { + nEncryption = 12; + } + } else { + nEncryption = 12; + } + return nEncryption; + } + + public static Fragment getVisibleFragment(FragmentActivity activity) { + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + @SuppressLint("RestrictedApi") List fragments = fragmentManager.getFragments(); + for (Fragment fragment : fragments) { + if (fragment != null && fragment.isVisible()) { + return fragment; + } + } + + return null; + } + + public static boolean isAppOnForeground(Context context) { + if (context == null) { + return false; + } + ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + if (mActivityManager == null) { + return false; + } + List tasksInfo = mActivityManager.getRunningTasks(1); + if (tasksInfo != null && tasksInfo.size() > 0) { + // 应用程序位于堆栈的顶层 + ComponentName componentName = tasksInfo.get(0).topActivity; + if (componentName != null && context.getPackageName().equals(componentName.getPackageName())) { + return true; + } + } + return false; + } + + public static boolean isAssignClass(Context context, String className){ + if (context == null) { + return false; + } + ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + if (mActivityManager == null) { + return false; + } + List tasksInfo = mActivityManager.getRunningTasks(1); + if (tasksInfo != null && tasksInfo.size() > 0) { + ComponentName componentName = tasksInfo.get(0).topActivity; + if (componentName != null) { + LogUtil.debugLog("32752", "className->"+componentName.getClassName() + " & packageName->" + componentName.getPackageName()); + if (componentName.getClassName().contains(className)) { + return true; + } + } + } + return false; + } + + public static boolean listIsEmpty(List list){ + return list == null || list.isEmpty(); + } + + /** + * 测量字符高度 + * + * @param text + * @return + */ + public static int getTextHeight(TextPaint textPaint, String text) { + Rect bounds = new Rect(); + textPaint.getTextBounds(text, 0, text.length(), bounds); + return bounds.height(); + } + + public static boolean isFragmentExist(Fragment fragment){ + return fragment != null && fragment.isAdded() && fragment.isVisible(); + } + + public static GradientDrawable createShape(int color, int radius, Context context){ + GradientDrawable drawable = new GradientDrawable(); + drawable.setCornerRadius(UIUtils.dip2px(context, radius)); + drawable.setColor(color); + return drawable; + } + + public static int makeDropDownMeasureSpec(int measureSpec){ + int mode; + if(measureSpec == ViewGroup.LayoutParams.WRAP_CONTENT){ + mode = View.MeasureSpec.UNSPECIFIED; + }else{ + mode = View.MeasureSpec.EXACTLY; + } + return View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.getSize(measureSpec), mode); + } + + public static int dp2px(Context context, float dpValue){ + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,context.getResources().getDisplayMetrics()); + } + + public static float px2dp(Context context, float dpValue){ + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,dpValue,context.getResources().getDisplayMetrics()); + } + + // 设置view 的margin值 + public static void setMargins(View v, int l, int t, int r, int b) { + if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + p.setMargins(l, t, r, b); + v.requestLayout(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WifiUtil.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WifiUtil.java new file mode 100644 index 0000000..d31c0f0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WifiUtil.java @@ -0,0 +1,612 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.content.Context; +import android.net.DhcpInfo; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.os.Build; +import android.os.Build.VERSION; +import android.text.TextUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +public class WifiUtil { + private final String LC_PACKAGE_NAME = "com.lechange.demo.a"; + + private WifiManager mWifiManager; + private WifiInfo mWifiInfo; + private List mWifiList; + private List mWifiConfiguration; + private WifiLock mWifiLock; + + public WifiUtil(Context context) { + this.mWifiManager = (WifiManager)context.getSystemService("wifi"); + this.mWifiInfo = this.mWifiManager.getConnectionInfo(); + } + + public void openWifi() { + if (!this.mWifiManager.isWifiEnabled()) { + this.mWifiManager.setWifiEnabled(true); + } + + } + + public void closeWifi() { + if (this.mWifiManager.isWifiEnabled()) { + this.mWifiManager.setWifiEnabled(false); + } + + } + + public boolean isWifi5G(Context context) { + int freq = 0; + if (VERSION.SDK_INT > 21) { + freq = this.mWifiInfo.getFrequency(); + } else { + String ssid = this.mWifiInfo.getSSID(); + if (ssid != null && ssid.length() > 2) { + String ssidTemp = ssid.substring(1, ssid.length() - 1); + List scanResults = this.mWifiManager.getScanResults(); + Iterator var6 = scanResults.iterator(); + + while(var6.hasNext()) { + ScanResult scanResult = (ScanResult)var6.next(); + if (scanResult.SSID.equals(ssidTemp)) { + freq = scanResult.frequency; + break; + } + } + } + } + + return freq > 4900 && freq < 5900; + } + + public int checkState() { + return this.mWifiManager.getWifiState(); + } + + public void acquireWifiLock() { + this.mWifiLock.acquire(); + } + + public void releaseWifiLock() { + if (this.mWifiLock.isHeld()) { + this.mWifiLock.acquire(); + } + + } + + public void creatWifiLock() { + this.mWifiLock = this.mWifiManager.createWifiLock("Test"); + } + + public List getConfiguration() { + return this.mWifiConfiguration; + } + + public void connectConfiguration(int index) { + if (index <= this.mWifiConfiguration.size()) { + this.mWifiManager.enableNetwork(((WifiConfiguration)this.mWifiConfiguration.get(index)).networkId, true); + } + } + + public void startScan() { + this.mWifiManager.startScan(); + this.mWifiList = this.mWifiManager.getScanResults(); + this.mWifiConfiguration = this.mWifiManager.getConfiguredNetworks(); + } + + public List getWifiList() { + return this.mWifiList; + } + + public StringBuilder lookUpScan() { + StringBuilder stringBuilder = new StringBuilder(); + + for(int i = 0; i < this.mWifiList.size(); ++i) { + stringBuilder.append("Index_" + (new Integer(i + 1)).toString() + ":"); + stringBuilder.append(((ScanResult)this.mWifiList.get(i)).toString()); + stringBuilder.append("/n"); + } + + return stringBuilder; + } + + public String getMacAddress() { + return this.mWifiInfo == null ? "NULL" : this.mWifiInfo.getMacAddress(); + } + + public String getBSSID() { + return this.mWifiInfo == null ? "NULL" : this.mWifiInfo.getBSSID(); + } + + public int getIPAddress() { + return this.mWifiInfo == null ? 0 : this.mWifiInfo.getIpAddress(); + } + + public int getNetworkId() { + return this.mWifiInfo == null ? 0 : this.mWifiInfo.getNetworkId(); + } + + public String getWifiInfo() { + return this.mWifiInfo == null ? "NULL" : this.mWifiInfo.toString(); + } + + public boolean addNetwork(WifiConfiguration wcg) { + int wcgID = this.mWifiManager.addNetwork(wcg); + return this.mWifiManager.enableNetwork(wcgID, true); + } + + public boolean addNetworkEx(WifiConfiguration wcg) { + //int wcgID = this.mWifiManager.addNetwork(wcg); + //Method connectMethod = this.connectWifiByReflectMethod(wcgID); + Method connectMethod = connectWifiByReflectMethod(wcg); + if (connectMethod == null) { + int wcgID = this.mWifiManager.addNetwork(wcg); + boolean isOK = this.mWifiManager.enableNetwork(wcgID, true); + return isOK; + } else { + return true; + } + } + + private Method connectWifiByReflectMethod(WifiConfiguration wcg) { + Method connectMethod = null; + if (this.isAndroidBetween8To9()) { + Method[] var3 = this.mWifiManager.getClass().getDeclaredMethods(); + int var4 = var3.length; + + for(int var5 = 0; var5 < var4; ++var5) { + Method methodSub = var3[var5]; + if ("connect".equalsIgnoreCase(methodSub.getName())) { + Class[] types = methodSub.getParameterTypes(); + if (types != null && types.length > 0 && "android.net.wifi.WifiConfiguration".equalsIgnoreCase(types[0].getName())) { + connectMethod = methodSub; + break; + } + } + } + + if (connectMethod != null) { + try { + connectMethod.setAccessible(true); + connectMethod.invoke(this.mWifiManager, wcg, null); + } catch (Exception var8) { + var8.printStackTrace(); + return null; + } + } + } + + return connectMethod; + } + + private Method connectWifiByReflectMethod(int netId) { + Method connectMethod = null; + if (this.isAndroidBetween8To9()) { + Method[] var3 = this.mWifiManager.getClass().getDeclaredMethods(); + int var4 = var3.length; + + for(int var5 = 0; var5 < var4; ++var5) { + Method methodSub = var3[var5]; + if ("connect".equalsIgnoreCase(methodSub.getName())) { + Class[] types = methodSub.getParameterTypes(); + if (types != null && types.length > 0 && "int".equalsIgnoreCase(types[0].getName())) { + connectMethod = methodSub; + break; + } + } + } + + if (connectMethod != null) { + try { + connectMethod.setAccessible(true); + connectMethod.invoke(this.mWifiManager, netId, null); + } catch (Exception var8) { + var8.printStackTrace(); + return null; + } + } + } + + return connectMethod; + } + + private boolean isAndroidBetween8To9() { + return VERSION.SDK_INT >= 26 && VERSION.SDK_INT <= 28; + } + + public void disconnectWifi(int netId) { + this.mWifiManager.disableNetwork(netId); + this.mWifiManager.disconnect(); + } + + public WifiConfiguration createWifiInfo(String SSID, String Password, WifiCipherType Type) { + WifiConfiguration config = new WifiConfiguration(); + //config.allowedAuthAlgorithms.clear(); + //config.allowedGroupCiphers.clear(); + //config.allowedKeyManagement.clear(); + //config.allowedPairwiseCiphers.clear(); + //config.allowedProtocols.clear(); + config.SSID = "\"" + SSID + "\""; + Class clz = WifiConfiguration.class; + WifiConfiguration tempConfig = this.IsExsits(SSID); + if (tempConfig != null) { + this.mWifiManager.removeNetwork(tempConfig.networkId); + } + + if (Type == WifiCipherType.WIFICIPHER_NOPASS) { + config.allowedKeyManagement.set(0); + } else if (Type == WifiCipherType.WIFICIPHER_WEP) { + if (!TextUtils.isEmpty(Password)) { + if (isHexWepKey(Password)) { + config.wepKeys[0] = Password; + } else { + config.wepKeys[0] = "\"" + Password + "\""; + } + } + + config.allowedAuthAlgorithms.set(0); + config.allowedAuthAlgorithms.set(1); + config.allowedKeyManagement.set(0); + config.wepTxKeyIndex = 0; + } else if (Type == WifiCipherType.WIFICIPHER_WPA) { + config.preSharedKey = "\"" + Password + "\""; + config.allowedAuthAlgorithms.set(0); + config.allowedGroupCiphers.set(2); + config.allowedGroupCiphers.set(3); + config.allowedKeyManagement.set(1); + config.allowedPairwiseCiphers.set(1); + config.allowedPairwiseCiphers.set(2); + config.allowedProtocols.set(1); + config.allowedProtocols.set(0); + config.status = 2; + } + + try { + Field filed = clz.getField("validatedInternetAccess"); + filed.set(config, true); + } catch (Exception var8) { + var8.printStackTrace(); + } + + return config; + } + + private static boolean isHexWepKey(String wepKey) { + int len = wepKey.length(); + return len != 10 && len != 26 && len != 58 ? false : isHex(wepKey); + } + + private static boolean isHex(String key) { + for(int i = key.length() - 1; i >= 0; --i) { + char c = key.charAt(i); + if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) { + return false; + } + } + + return true; + } + + public WifiConfiguration IsExsits(String SSID) { + if (TextUtils.isEmpty(SSID)) { + return null; + } else { + String targetSSID = SSID.startsWith("\"") ? SSID : "\"" + SSID + "\""; + List existingConfigs = this.mWifiManager.getConfiguredNetworks(); + if (existingConfigs == null) { + return null; + } else { + Iterator var4 = existingConfigs.iterator(); + + WifiConfiguration existingConfig; + do { + + if (!var4.hasNext()) { + return null; + } + + existingConfig = (WifiConfiguration)var4.next(); + } while(!existingConfig.SSID.equals(targetSSID)); + + return existingConfig; + } + } + } + + public boolean connectWifi(String SSID, String passWord) { + if (VERSION.SDK_INT >= 23) { + WifiConfiguration tempConfig = this.IsExsits(SSID); + if (tempConfig != null) { + boolean ret = this.mWifiManager.removeNetwork(tempConfig.networkId); + if (!ret) { + return this.mWifiManager.enableNetwork(tempConfig.networkId, true); + } + } + } + + return this.addNetwork(this.createWifiInfo(SSID, passWord, WifiCipherType.WIFICIPHER_NOPASS)); + } + + public boolean connectWifi(String SSID, String passWord, WifiCipherType type) { + if (VERSION.SDK_INT >= 23) { + WifiConfiguration tempConfig = this.IsExsits(SSID); + if (tempConfig != null) { + boolean ret = this.mWifiManager.removeNetwork(tempConfig.networkId); + if (!ret) { + return this.mWifiManager.enableNetwork(tempConfig.networkId, true); + } + } + } + + return this.addNetwork(this.createWifiInfo(SSID, passWord, type)); + } + + public boolean connectWifiEx(String SSID, String passWord, WifiCipherType type) { + if (VERSION.SDK_INT >= 23) { + WifiConfiguration tempConfig = this.IsExsits(SSID); + if (tempConfig != null) { + boolean ret = this.mWifiManager.removeNetwork(tempConfig.networkId); + boolean isLechangeCreat = TextUtils.equals(LC_PACKAGE_NAME, getCreatorName(tempConfig)) || TextUtils.equals(LC_PACKAGE_NAME, getLastUpdateName(tempConfig)); + //判断是该应用创建的直接走addNetworkEx + if (!ret && !isLechangeCreat) { + return this.mWifiManager.enableNetwork(tempConfig.networkId, true); + } + } + } + + return this.addNetworkEx(this.createWifiInfo(SSID, passWord, type)); + } + + public String getCreatorName(WifiConfiguration config) { + String creatorName = null; + + if(config == null){ + return creatorName; + } + + try{ + Field[] fields = config.getClass().getDeclaredFields(); + for (Field field : fields) { + if (field.getName().equals("creatorName")) { + field.setAccessible(true); + try { + if (field.get(config) != null) { + creatorName = field.get(config).toString(); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + } catch (Exception e){ + + } + + return creatorName; + } + + public String getLastUpdateName(WifiConfiguration config) { + String creatorName = null; + + if(config == null){ + return creatorName; + } + + try{ + Field[] fields = config.getClass().getDeclaredFields(); + for (Field field : fields) { + if (field.getName().equals("lastUpdateName")) { + field.setAccessible(true); + try { + if (field.get(config) != null) { + creatorName = field.get(config).toString(); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + } catch (Exception e){ + + } + + return creatorName; + } + + + + public WifiCipherType getCipherType(String ssid) { + if (this.mWifiManager == null) { + return WifiCipherType.WIFICIPHER_WEP; + } else { + List list = this.mWifiManager.getScanResults(); + Iterator var3 = list.iterator(); + + while(var3.hasNext()) { + ScanResult scResult = (ScanResult)var3.next(); + if (!TextUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) { + String capabilities = scResult.capabilities; + if (!TextUtils.isEmpty(capabilities)) { + if (!capabilities.contains("WPA") && !capabilities.contains("wpa") && !capabilities.contains("RSN")) { + if (!capabilities.contains("WEP") && !capabilities.contains("wep")) { + return WifiCipherType.WIFICIPHER_NOPASS; + } + + return WifiCipherType.WIFICIPHER_WEP; + } + + return WifiCipherType.WIFICIPHER_WPA; + } + } + } + + return WifiCipherType.WIFICIPHER_WEP; + } + } + + public String getGatewayIp() { + DhcpInfo dhcpInfo = this.mWifiManager.getDhcpInfo(); + if (dhcpInfo != null) { + long gatewayIps = (long)dhcpInfo.gateway; + return this.long2ip(gatewayIps); + } else { + return ""; + } + } + + public String long2ip(long ip) { + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(String.valueOf((int)(ip & 255L))); + stringBuffer.append('.'); + stringBuffer.append(String.valueOf((int)(ip >> 8 & 255L))); + stringBuffer.append('.'); + stringBuffer.append(String.valueOf((int)(ip >> 16 & 255L))); + stringBuffer.append('.'); + stringBuffer.append(String.valueOf((int)(ip >> 24 & 255L))); + return stringBuffer.toString(); + } + + public WifiInfo getCurrentWifiInfo() { + this.mWifiInfo = this.mWifiManager.getConnectionInfo(); + return this.mWifiInfo; + } + + public int getWifiEncryption(String capabilities) { + int encryption = 255; + String cap = capabilities.toUpperCase(Locale.US); + if (cap.indexOf("WPA2") != -1) { + if (cap.indexOf("WPA2-PSK-TKIP") != -1) { + encryption = 6; + } else if (cap.indexOf("WPA2-PSK-AES") != -1) { + encryption = 7; + } else if (cap.indexOf("WPA2-TKIP") != -1) { + encryption = 10; + } else if (cap.indexOf("WPA2-AES") != -1) { + encryption = 11; + } else if (cap.indexOf("WPA2-PSK-CCMP") != -1) { + encryption = 12; + } + } else if (cap.indexOf("WPA") != -1) { + if (cap.indexOf("WPA-PSK-TKIP") != -1) { + encryption = 4; + } else if (cap.indexOf("WPA-PSK-CCMP") != -1) { + encryption = 5; + } else if (cap.indexOf("WPA-TKIP") != -1) { + encryption = 8; + } else if (cap.indexOf("WPA-CCMP") != -1) { + encryption = 9; + } + } else if (cap.indexOf("WEP") != -1) { + if (cap.indexOf("WEP_Open") != -1) { + encryption = 2; + } else if (cap.indexOf("WEP_Shared") != -1) { + encryption = 3; + } + } else { + encryption = 255; + } + + return encryption; + } + + public ScanResult getScanResult() { + ScanResult scanResult = null; + if (this.mWifiManager == null) { + return null; + } else { + this.getCurrentWifiInfo(); + if (this.mWifiInfo.getSSID() != null) { + try { + if (this.mWifiList == null) { + this.startScan(); + } + + if (this.mWifiList == null) { + return null; + } + + Iterator var2 = this.mWifiList.iterator(); + + while(var2.hasNext()) { + ScanResult s = (ScanResult)var2.next(); + if (s.SSID.replaceAll("\"", "").equals(this.mWifiInfo.getSSID().replaceAll("\"", ""))) { + scanResult = s; + break; + } + } + } catch (Exception var4) { + return null; + } + } + + return scanResult; + } + } + + public boolean isNoPasswordWifi() { + ScanResult scanResult = this.getScanResult(); + if (scanResult == null) { + return false; + } else { + int encypt = this.getWifiEncryption(scanResult.capabilities); + return encypt == 2 || encypt == 255; + } + } + + public String getDoorbellSSID(String deviceSn) { + return "Doorbell-" + deviceSn; + } + + public boolean isConnectedDoorbellHot(String deviceSn) { + WifiInfo wifiInfo = this.getCurrentWifiInfo(); + if (wifiInfo == null) { + return false; + } else { + String ssid = this.getDoorbellSSID(deviceSn); + ssid = "\"" + ssid + "\""; + return wifiInfo.getSSID().equals(ssid); + } + } + + public void disconnectCurrentWifi(String SSID) { + WifiInfo wifiInfo = this.getCurrentWifiInfo(); + + if (wifiInfo != null) { + WifiConfiguration currentConfig = this.IsExsits(wifiInfo.getSSID()); + if (!wifiInfo.getSSID().equals(SSID) && currentConfig != null) { + this.mWifiManager.disableNetwork(currentConfig.networkId); + this.mWifiManager.disconnect(); + } + } + + } + + public static enum WifiCipherType { + WIFICIPHER_WEP, + WIFICIPHER_WPA, + WIFICIPHER_NOPASS, + WIFICIPHER_INVALID; + + private WifiCipherType() { + } + } + + + private static final String HWMobile = "HUAWEI"; + + public static boolean isHuaweiMobile(){ + return HWMobile.equalsIgnoreCase(Build.MANUFACTURER == null ? "UNKNOWN" : Build.MANUFACTURER.trim()); //false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WordInputFilter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WordInputFilter.java new file mode 100644 index 0000000..3bbda4e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/utils/WordInputFilter.java @@ -0,0 +1,47 @@ +package com.mm.android.deviceaddmodule.mobilecommon.utils; + +import android.text.InputFilter; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; + +public class WordInputFilter implements InputFilter { + + private String rex = "[^a-zA-Z0-9\\-_@.]"; + + public static final String REX_EMAIL = "[^a-zA-Z0-9\\-\\_\\@\\.]"; + + public static final String REX_PHONE = "[^0-9]"; + + public static final String REX_CHINESS = "[\\u4e00-\\u9fa5]"; + + public static final String REX_DEVICE_SN = "[^0-9A-Za-z]"; + + public static final String REX_PASSWORD = "[^a-zA-Z0-9\\!\\#\\$\\%\\(\\)\\*\\+\\,\\-\\.\\/\\<\\=" + + "\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~]*"; + + public static final String REX_NAME = "[^a-zA-Z0-9\\-\\u4e00-\\u9fa5\\_\\@\\s]"; + + public static final String ACCOUNT_REX_NAME = "[^a-zA-Z0-9\\-\\u4e00-\\u9fa5\\_\\@ ]"; + + + public static final String REX_EMOJI = "[\\x{1F300}-\\x{1F5FF}\\x{1F600}-\\x{1F64F}\\x{1F900}-\\x{1F9FF}\\x{1F680}-\\x{1F6FF}\\x{2600}-\\x{26FF}\\x{2700}-\\x{27BF}]"; + + public static final String REX_NAME_NO_SPACE = "[^a-zA-Z0-9\\-\\u4e00-\\u9fa5\\_\\@]"; + + public WordInputFilter(String rex) { + this.rex = rex; + } + + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + String result = source.toString().replaceAll(rex, ""); + if(source instanceof Spanned){ + SpannableString str = new SpannableString(result); + TextUtils.copySpansFrom((Spanned) source ,0 ,result.length(), null, str, 0 ); + return str; + } + + return result; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/AverageLinearLayout.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/AverageLinearLayout.java new file mode 100644 index 0000000..81a3d31 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/AverageLinearLayout.java @@ -0,0 +1,75 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class AverageLinearLayout extends ViewGroup{ + + public AverageLinearLayout(Context context) { + super(context); + } + + public AverageLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AverageLinearLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + measureChildren(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int width = getMeasuredWidth(); + int hight = getMeasuredHeight(); + int childCount = getChildCount(); + int spaceCount = childCount - 1; + int childTotalWidth = 0; + for(int i = 0; i < childCount; i++){ + final View child = getChildAt(i); + if(child.getVisibility() == View.VISIBLE){ + final int childWidth = child.getMeasuredWidth(); + childTotalWidth += childWidth; + }else{ + spaceCount--; + } + + } + + int space = (width - getPaddingLeft() - getPaddingRight() - childTotalWidth) / spaceCount; + int childLeft = getPaddingLeft(); + + for(int i = 0; i < childCount; i++){ + final View child = getChildAt(i); + if(child.getVisibility() == View.VISIBLE){ + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + + int childTop =(hight - getPaddingTop() - getPaddingBottom() - childHeight) / 2; + + if(i != childCount -1){ + child.layout(childLeft ,childTop , childLeft + childWidth, childTop + childHeight); + + childLeft += space; + + }else{ + child.layout(r - getPaddingRight() - childWidth ,childTop , r - getPaddingRight(), childTop + childHeight); + } + + childLeft += childWidth; + } + } + + + } + + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/BadgeView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/BadgeView.java new file mode 100644 index 0000000..bad6c2a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/BadgeView.java @@ -0,0 +1,466 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.TabWidget; + +/** + * A simple text label view that can be applied as a "badge" to any given {@link View}. + * This class is intended to be instantiated at runtime rather than included in XML layouts. + * + */ +public class BadgeView extends android.support.v7.widget.AppCompatTextView { + + private final static int POSITION_TOP_LEFT = 1; + private final static int POSITION_TOP_RIGHT = 2; + private final static int POSITION_BOTTOM_LEFT = 3; + private final static int POSITION_BOTTOM_RIGHT = 4; + private final static int POSITION_CENTER = 5; + + private final static int DEFAULT_MARGIN_DIP = 5; + private final static int DEFAULT_LR_PADDING_DIP = 5; + private final static int DEFAULT_CORNER_RADIUS_DIP = 9; + private final static int DEFAULT_POSITION = POSITION_TOP_RIGHT; + private final static int DEFAULT_BADGE_COLOR = Color.parseColor("#CCFF0000"); // Color.RED; + private final static int DEFAULT_TEXT_COLOR = Color.WHITE; + + private static Animation fadeIn; + private static Animation fadeOut; + + private Context context; + private View target; + + private int badgePosition; + private int badgeMarginH; + private int badgeMarginV; + private int badgeColor; + + private boolean isShown; + + private ShapeDrawable badgeBg; + + private int targetTabIndex; + + public BadgeView(Context context) { + this(context, (AttributeSet) null, android.R.attr.textViewStyle); + } + + public BadgeView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.textViewStyle); + } + + /** + * Constructor - + * + * create a new BadgeView instance attached to a target {@link View}. + * + * @param context context for this view. + * @param target the View to attach the badge to. + */ + public BadgeView(Context context, View target) { + this(context, null, android.R.attr.textViewStyle, target, 0); + } + + /** + * Constructor - + * + * create a new BadgeView instance attached to a target {@link TabWidget} + * tab at a given index. + * + * @param context context for this view. + * @param target the TabWidget to attach the badge to. + * @param index the position of the tab within the target. + */ + public BadgeView(Context context, TabWidget target, int index) { + this(context, null, android.R.attr.textViewStyle, target, index); + } + + public BadgeView(Context context, AttributeSet attrs, int defStyle) { + this(context, attrs, defStyle, null, 0); + } + + public BadgeView(Context context, AttributeSet attrs, int defStyle, View target, int tabIndex) { + super(context, attrs, defStyle); + init(context, target, tabIndex); + } + + private void init(Context context, View target, int tabIndex) { + + this.context = context; + this.target = target; + this.targetTabIndex = tabIndex; + + // apply defaults + badgePosition = DEFAULT_POSITION; + badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP); + badgeMarginV = badgeMarginH; + badgeColor = DEFAULT_BADGE_COLOR; + + setTypeface(Typeface.DEFAULT_BOLD); + int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP); + setPadding(paddingPixels, 0, paddingPixels, 0); + setTextColor(DEFAULT_TEXT_COLOR); + + fadeIn = new AlphaAnimation(0, 1); + fadeIn.setInterpolator(new DecelerateInterpolator()); + fadeIn.setDuration(200); + + fadeOut = new AlphaAnimation(1, 0); + fadeOut.setInterpolator(new AccelerateInterpolator()); + fadeOut.setDuration(200); + + isShown = false; + + if (this.target != null) { + applyTo(this.target); + } else { + show(); + } + + } + + private void applyTo(View target) { + + LayoutParams lp = target.getLayoutParams(); + ViewParent parent = target.getParent(); + FrameLayout container = new FrameLayout(context); + + if (target instanceof TabWidget) { + + // set target to the relevant tab child container + target = ((TabWidget) target).getChildTabViewAt(targetTabIndex); + this.target = target; + + if(target != null){ + ((ViewGroup) target).addView(container, new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT)); + + this.setVisibility(View.GONE); + container.addView(this); + + } + } else { + + // TODO verify that parent is indeed a ViewGroup + ViewGroup group = (ViewGroup) parent; + int index = group.indexOfChild(target); + + group.removeView(target); + group.addView(container, index, lp); + + container.addView(target); + + this.setVisibility(View.GONE); + container.addView(this); + + group.invalidate(); + + } + + } + + /** + * Make the badge visible in the UI. + * + */ + public void show() { + show(false, null); + } + + /** + * Make the badge visible in the UI. + * + * @param animate flag to apply the default fade-in animation. + */ + public void show(boolean animate) { + show(animate, fadeIn); + } + + /** + * Make the badge visible in the UI. + * + * @param anim Animation to apply to the view when made visible. + */ + public void show(Animation anim) { + show(true, anim); + } + + /** + * Make the badge non-visible in the UI. + * + */ + public void hide() { + hide(false, null); + } + + /** + * Make the badge non-visible in the UI. + * + * @param animate flag to apply the default fade-out animation. + */ + public void hide(boolean animate) { + hide(animate, fadeOut); + } + + /** + * Make the badge non-visible in the UI. + * + * @param anim Animation to apply to the view when made non-visible. + */ + public void hide(Animation anim) { + hide(true, anim); + } + + /** + * Toggle the badge visibility in the UI. + * + */ + public void toggle() { + toggle(false, null, null); + } + + /** + * Toggle the badge visibility in the UI. + * + * @param animate flag to apply the default fade-in/out animation. + */ + public void toggle(boolean animate) { + toggle(animate, fadeIn, fadeOut); + } + + /** + * Toggle the badge visibility in the UI. + * + * @param animIn Animation to apply to the view when made visible. + * @param animOut Animation to apply to the view when made non-visible. + */ + public void toggle(Animation animIn, Animation animOut) { + toggle(true, animIn, animOut); + } + + private void show(boolean animate, Animation anim) { + if (getBackground() == null) { + if (badgeBg == null) { + badgeBg = getDefaultBackground(); + } + setBackgroundDrawable(badgeBg); + } + applyLayoutParams(); + + if (animate) { + this.startAnimation(anim); + } + this.setVisibility(View.VISIBLE); + isShown = true; + } + + private void hide(boolean animate, Animation anim) { + this.setVisibility(View.GONE); + if (animate) { + this.startAnimation(anim); + } + isShown = false; + } + + private void toggle(boolean animate, Animation animIn, Animation animOut) { + if (isShown) { + hide(animate && (animOut != null), animOut); + } else { + show(animate && (animIn != null), animIn); + } + } + + /** + * Increment the numeric badge label. If the current badge label cannot be converted to + * an integer value, its label will be set to "0". + * + * @param offset the increment offset. + */ + public int increment(int offset) { + CharSequence txt = getText(); + int i; + if (txt != null) { + try { + i = Integer.parseInt(txt.toString()); + } catch (NumberFormatException e) { + i = 0; + } + } else { + i = 0; + } + i = i + offset; + setText(String.valueOf(i)); + return i; + } + + /** + * Decrement the numeric badge label. If the current badge label cannot be converted to + * an integer value, its label will be set to "0". + * + * @param offset the decrement offset. + */ + public int decrement(int offset) { + return increment(-offset); + } + + private ShapeDrawable getDefaultBackground() { + + int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP); + float[] outerR = new float[] {r, r, r, r, r, r, r, r}; + + RoundRectShape rr = new RoundRectShape(outerR, null, null); + ShapeDrawable drawable = new ShapeDrawable(rr); + drawable.getPaint().setColor(badgeColor); + + return drawable; + + } + + private void applyLayoutParams() { + + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + switch (badgePosition) { + case POSITION_TOP_LEFT: + lp.gravity = Gravity.LEFT | Gravity.TOP; + lp.setMargins(badgeMarginH, badgeMarginV, 0, 0); + break; + case POSITION_TOP_RIGHT: + lp.gravity = Gravity.RIGHT | Gravity.TOP; + lp.setMargins(0, badgeMarginV, badgeMarginH, 0); + break; + case POSITION_BOTTOM_LEFT: + lp.gravity = Gravity.LEFT | Gravity.BOTTOM; + lp.setMargins(badgeMarginH, 0, 0, badgeMarginV); + break; + case POSITION_BOTTOM_RIGHT: + lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; + lp.setMargins(0, 0, badgeMarginH, badgeMarginV); + break; + case POSITION_CENTER: + lp.gravity = Gravity.CENTER; + lp.setMargins(0, 0, 0, 0); + break; + default: + break; + } + + setLayoutParams(lp); + + } + + /** + * Returns the target View this badge has been attached to. + * + */ + public View getTarget() { + return target; + } + + /** + * Is this badge currently visible in the UI? + * + */ + @Override + public boolean isShown() { + return isShown; + } + + /** + * Returns the positioning of this badge. + * + * one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER. + * + */ + public int getBadgePosition() { + return badgePosition; + } + + /** + * Set the positioning of this badge. + * + * @param layoutPosition one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER. + * + */ + public void setBadgePosition(int layoutPosition) { + this.badgePosition = layoutPosition; + } + + /** + * Returns the horizontal margin from the target View that is applied to this badge. + * + */ + public int getHorizontalBadgeMargin() { + return badgeMarginH; + } + + /** + * Returns the vertical margin from the target View that is applied to this badge. + * + */ + public int getVerticalBadgeMargin() { + return badgeMarginV; + } + + /** + * Set the horizontal/vertical margin from the target View that is applied to this badge. + * + * @param badgeMargin the margin in pixels. + */ + public void setBadgeMargin(int badgeMargin) { + this.badgeMarginH = badgeMargin; + this.badgeMarginV = badgeMargin; + } + + /** + * Set the horizontal/vertical margin from the target View that is applied to this badge. + * + * @param horizontal margin in pixels. + * @param vertical margin in pixels. + */ + public void setBadgeMargin(int horizontal, int vertical) { + this.badgeMarginH = horizontal; + this.badgeMarginV = vertical; + } + + /** + * Returns the color value of the badge background. + * + */ + public int getBadgeBackgroundColor() { + return badgeColor; + } + + /** + * Set the color value of the badge background. + * + * @param badgeColor the badge background color. + */ + public void setBadgeBackgroundColor(int badgeColor) { + this.badgeColor = badgeColor; + badgeBg = getDefaultBackground(); + } + + private int dipToPixels(int dip) { + Resources r = getResources(); + float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics()); + return (int) px; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleCountDownView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleCountDownView.java new file mode 100644 index 0000000..4cce1a7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleCountDownView.java @@ -0,0 +1,196 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Handler; +import android.os.Message; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +/** + * 圆形倒计时控件 + **/ +public class CircleCountDownView extends View { + private int mRingColor; //圆轮颜色 + private int mCirbgColor; //圆形背景色 + private float mRingWidth; //圆轮宽度 + private int mRingProgessTextSize; //圆轮进度值文本大小 + private int mWidth; //宽度 + private int mHeight; //高度 + private Paint mPaint; + private RectF mRectF; //圆环的矩形区域 + private int mProgessTextColor; + private int mCountdownTime; + private int mTotalCountdownTime; + private float mCurrentProgress; + private OnCountDownFinishListener mListener; + ValueAnimator mValueAnimator; + private int mMiddleTime; //设置中间提醒时间,即0-CountdownTime之间的时间 + private boolean mHasMiddleTimeUp=false; + + public CircleCountDownView(Context context) { + super(context); + init(); + } + + public CircleCountDownView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initAttrs(context, attrs); + init(); + } + + public CircleCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + init(); + } + Paint textPaint; + private void init() { + textPaint = new Paint(); + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setAntiAlias(true); + mPaint.setColor(mRingColor); //颜色 + mPaint.setStyle(Paint.Style.STROKE); //空心 + mPaint.setStrokeWidth(mRingWidth); //宽度 + mCirbgColor = Color.parseColor("#e0e0e0"); + this.setWillNotDraw(false); + } + + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleCountDownView); + mRingColor = a.getColor(R.styleable.CircleCountDownView_ringColor, mCirbgColor); + mCirbgColor=a.getColor(R.styleable.CircleCountDownView_ringbgColor,mCirbgColor); + mRingWidth = a.getDimensionPixelSize(R.styleable.CircleCountDownView_ringWidth, UIUtils.dp2px(context, 10)); + mRingProgessTextSize = a.getDimensionPixelSize(R.styleable.CircleCountDownView_progressTextSize, UIUtils.sp2px(context, 25)); + mProgessTextColor = a.getColor(R.styleable.CircleCountDownView_progressTextColor, mCirbgColor); + mCountdownTime = a.getInteger(R.styleable.CircleCountDownView_countdownTime, 60); + mTotalCountdownTime=mCountdownTime; + a.recycle(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mWidth = getMeasuredWidth(); + mHeight = getMeasuredHeight(); + if(mRectF == null){ + mRectF = new RectF(0 + mRingWidth / 2, 0 + mRingWidth / 2, + mWidth - mRingWidth / 2, mHeight - mRingWidth / 2); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + mPaint.setColor(mCirbgColor); //颜色 + canvas.drawArc(mRectF, -90, -360, false, mPaint); + mPaint.setColor(mRingColor); //颜色 + canvas.drawArc(mRectF, -90, mCurrentProgress - 360, false, mPaint); + //绘制文本 + String text = mCountdownTime - (int) (mCurrentProgress / 360f * mCountdownTime)+""; + + textPaint.setAntiAlias(true); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setTextSize(mRingProgessTextSize); + textPaint.setFakeBoldText(true); + textPaint.setColor(mProgessTextColor); + + //文字居中显示 + Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt(); + int baseline = (int) ((mRectF.bottom + mRectF.top ) / 2); + canvas.drawText(text, mRectF.centerX(), baseline, textPaint); + textPaint.setFakeBoldText(false); + canvas.drawText("s",mRectF.centerX(), baseline-fontMetrics.bottom-fontMetrics.top+10, textPaint); + } + + private ValueAnimator getValA(long countdownTime) { + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); + valueAnimator.setDuration(countdownTime); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setRepeatCount(0); + return valueAnimator; + } + + public void setCountdownTime(int mCountdownTime) { + this.mCountdownTime = mCountdownTime; + this.mTotalCountdownTime=this.mCountdownTime; + } + + public void setMiddleTime(int middleTime){ + this.mMiddleTime=middleTime; + } + + Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { // handle message + switch (msg.what) { + case 1: + mTotalCountdownTime--; + if (mTotalCountdownTime > 0) { + mCurrentProgress = (int) (360 * ((mCountdownTime-mTotalCountdownTime) * 1.0f / mCountdownTime)); + int curTime = (int) (mCurrentProgress / 360f * mCountdownTime); + if (mMiddleTime > 0 && curTime >= mMiddleTime && !mHasMiddleTimeUp && mListener != null) { + mListener.middleTimeUp(); + mHasMiddleTimeUp = true; + } + invalidate(); + Message message = handler.obtainMessage(1); + handler.sendMessageDelayed(message, 1000); + } else { + //倒计时结束回调 + if (mListener != null) { + mListener.countDownFinished(); + } + setClickable(true); + } + } + super.handleMessage(msg); + } + }; + + /** + * 开始倒计时 + */ + public void startCountDown() { + mHasMiddleTimeUp=false; + setClickable(false); + mValueAnimator = getValA((long)mCountdownTime * 1000); + Message message = handler.obtainMessage(1); + handler.sendMessageDelayed(message, 1000); + mValueAnimator.start(); + } + + public int getCurCountdownTime() { + return mCountdownTime - (int) (mCurrentProgress / 360f * mCountdownTime); + } + + public void stopCountDown(){ + mListener=null; + if(mValueAnimator!=null) { + mValueAnimator.cancel(); + } + if (handler!=null){ + handler.removeCallbacksAndMessages(null); + handler=null; + } + } + + public void setCountDownListener(OnCountDownFinishListener mListener) { + this.mListener = mListener; + } + + public interface OnCountDownFinishListener { + void countDownFinished(); + void middleTimeUp(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleImageView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleImageView.java new file mode 100644 index 0000000..507a966 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CircleImageView.java @@ -0,0 +1,463 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.support.annotation.ColorInt; +import android.support.annotation.ColorRes; +import android.support.annotation.DrawableRes; +import android.support.annotation.RequiresApi; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewOutlineProvider; + +import com.mm.android.deviceaddmodule.R; + +public class CircleImageView extends android.support.v7.widget.AppCompatImageView { + + private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; + + private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; + private static final int COLORDRAWABLE_DIMENSION = 2; + + private static final int DEFAULT_BORDER_WIDTH = 0; + private static final int DEFAULT_BORDER_COLOR = Color.BLACK; + private static final int DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT; + private static final boolean DEFAULT_BORDER_OVERLAY = false; + + private final RectF mDrawableRect = new RectF(); + private final RectF mBorderRect = new RectF(); + + private final Matrix mShaderMatrix = new Matrix(); + private final Paint mBitmapPaint = new Paint(); + private final Paint mBorderPaint = new Paint(); + private final Paint mCircleBackgroundPaint = new Paint(); + + private int mBorderColor = DEFAULT_BORDER_COLOR; + private int mBorderWidth = DEFAULT_BORDER_WIDTH; + private int mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR; + + private Bitmap mBitmap; + private BitmapShader mBitmapShader; + private int mBitmapWidth; + private int mBitmapHeight; + + private float mDrawableRadius; + private float mBorderRadius; + + private ColorFilter mColorFilter; + + private boolean mReady; + private boolean mSetupPending; + private boolean mBorderOverlay; + private boolean mDisableCircularTransformation; + + public CircleImageView(Context context) { + super(context); + + init(); + } + + public CircleImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); + + mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); + mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); + mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); + + // Look for deprecated civ_fill_color if civ_circle_background_color is not set + if (a.hasValue(R.styleable.CircleImageView_civ_circle_background_color)) { + mCircleBackgroundColor = a.getColor(R.styleable.CircleImageView_civ_circle_background_color, + DEFAULT_CIRCLE_BACKGROUND_COLOR); + } else if (a.hasValue(R.styleable.CircleImageView_civ_fill_color)) { + mCircleBackgroundColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, + DEFAULT_CIRCLE_BACKGROUND_COLOR); + } + + a.recycle(); + + init(); + } + + private void init() { + super.setScaleType(SCALE_TYPE); + mReady = true; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setOutlineProvider(new OutlineProvider()); + } + + if (mSetupPending) { + setup(); + mSetupPending = false; + } + } + + @Override + public ScaleType getScaleType() { + return SCALE_TYPE; + } + + @Override + public void setScaleType(ScaleType scaleType) { + if (scaleType != SCALE_TYPE) { + throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); + } + } + + @Override + public void setAdjustViewBounds(boolean adjustViewBounds) { + if (adjustViewBounds) { + throw new IllegalArgumentException("adjustViewBounds not supported."); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (mDisableCircularTransformation) { + super.onDraw(canvas); + return; + } + + if (mBitmap == null) { + return; + } + + if (mCircleBackgroundColor != Color.TRANSPARENT) { + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mCircleBackgroundPaint); + } + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); + if (mBorderWidth > 0) { + canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + setup(); + } + + @Override + public void setPadding(int left, int top, int right, int bottom) { + super.setPadding(left, top, right, bottom); + setup(); + } + + @Override + public void setPaddingRelative(int start, int top, int end, int bottom) { + super.setPaddingRelative(start, top, end, bottom); + setup(); + } + + public int getBorderColor() { + return mBorderColor; + } + + public void setBorderColor(@ColorInt int borderColor) { + if (borderColor == mBorderColor) { + return; + } + + mBorderColor = borderColor; + mBorderPaint.setColor(mBorderColor); + invalidate(); + } + + @Deprecated + public void setBorderColorResource(@ColorRes int borderColorRes) { + setBorderColor(getContext().getResources().getColor(borderColorRes)); + } + + public int getCircleBackgroundColor() { + return mCircleBackgroundColor; + } + + public void setCircleBackgroundColor(@ColorInt int circleBackgroundColor) { + if (circleBackgroundColor == mCircleBackgroundColor) { + return; + } + + mCircleBackgroundColor = circleBackgroundColor; + mCircleBackgroundPaint.setColor(circleBackgroundColor); + invalidate(); + } + + public void setCircleBackgroundColorResource(@ColorRes int circleBackgroundRes) { + setCircleBackgroundColor(getContext().getResources().getColor(circleBackgroundRes)); + } + + /** + * Return the color drawn behind the circle-shaped drawable. + * + * @return The color drawn behind the drawable + * + * @deprecated Use {@link #getCircleBackgroundColor()} instead. + */ + @Deprecated + public int getFillColor() { + return getCircleBackgroundColor(); + } + + /** + * Set a color to be drawn behind the circle-shaped drawable. Note that + * this has no effect if the drawable is opaque or no drawable is set. + * + * @param fillColor The color to be drawn behind the drawable + * + * @deprecated Use {@link #setCircleBackgroundColor(int)} instead. + */ + @Deprecated + public void setFillColor(@ColorInt int fillColor) { + setCircleBackgroundColor(fillColor); + } + + /** + * Set a color to be drawn behind the circle-shaped drawable. Note that + * this has no effect if the drawable is opaque or no drawable is set. + * + * @param fillColorRes The color resource to be resolved to a color and + * drawn behind the drawable + * + * @deprecated Use {@link #setCircleBackgroundColorResource(int)} instead. + */ + @Deprecated + public void setFillColorResource(@ColorRes int fillColorRes) { + setCircleBackgroundColorResource(fillColorRes); + } + + public int getBorderWidth() { + return mBorderWidth; + } + + public void setBorderWidth(int borderWidth) { + if (borderWidth == mBorderWidth) { + return; + } + + mBorderWidth = borderWidth; + setup(); + } + + public boolean isBorderOverlay() { + return mBorderOverlay; + } + + public void setBorderOverlay(boolean borderOverlay) { + if (borderOverlay == mBorderOverlay) { + return; + } + + mBorderOverlay = borderOverlay; + setup(); + } + + public boolean isDisableCircularTransformation() { + return mDisableCircularTransformation; + } + + public void setDisableCircularTransformation(boolean disableCircularTransformation) { + if (mDisableCircularTransformation == disableCircularTransformation) { + return; + } + + mDisableCircularTransformation = disableCircularTransformation; + initializeBitmap(); + } + + @Override + public void setImageBitmap(Bitmap bm) { + super.setImageBitmap(bm); + initializeBitmap(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + super.setImageDrawable(drawable); + initializeBitmap(); + } + + @Override + public void setImageResource(@DrawableRes int resId) { + super.setImageResource(resId); + initializeBitmap(); + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + initializeBitmap(); + } + + @Override + public void setColorFilter(ColorFilter cf) { + if (cf == mColorFilter) { + return; + } + + mColorFilter = cf; + applyColorFilter(); + invalidate(); + } + + @Override + public ColorFilter getColorFilter() { + return mColorFilter; + } + + private void applyColorFilter() { + if (mBitmapPaint != null) { + mBitmapPaint.setColorFilter(mColorFilter); + } + } + + private Bitmap getBitmapFromDrawable(Drawable drawable) { + if (drawable == null) { + return null; + } + + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + + try { + Bitmap bitmap; + + if (drawable instanceof ColorDrawable) { + bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private void initializeBitmap() { + if (mDisableCircularTransformation) { + mBitmap = null; + } else { + mBitmap = getBitmapFromDrawable(getDrawable()); + } + setup(); + } + + private void setup() { + if (!mReady) { + mSetupPending = true; + return; + } + + if (getWidth() == 0 && getHeight() == 0) { + return; + } + + if (mBitmap == null) { + invalidate(); + return; + } + + mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + + mBitmapPaint.setAntiAlias(true); + mBitmapPaint.setShader(mBitmapShader); + + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(mBorderColor); + mBorderPaint.setStrokeWidth(mBorderWidth); + + mCircleBackgroundPaint.setStyle(Paint.Style.FILL); + mCircleBackgroundPaint.setAntiAlias(true); + mCircleBackgroundPaint.setColor(mCircleBackgroundColor); + + mBitmapHeight = mBitmap.getHeight(); + mBitmapWidth = mBitmap.getWidth(); + + mBorderRect.set(calculateBounds()); + mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); + + mDrawableRect.set(mBorderRect); + if (!mBorderOverlay && mBorderWidth > 0) { + mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); + } + mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); + + applyColorFilter(); + updateShaderMatrix(); + invalidate(); + } + + private RectF calculateBounds() { + int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); + + int sideLength = Math.min(availableWidth, availableHeight); + + float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; + float top = getPaddingTop() + (availableHeight - sideLength) / 2f; + + return new RectF(left, top, left + sideLength, top + sideLength); + } + + private void updateShaderMatrix() { + float scale; + float dx = 0; + float dy = 0; + + mShaderMatrix.set(null); + + if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { + scale = mDrawableRect.height() / (float) mBitmapHeight; + dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; + } else { + scale = mDrawableRect.width() / (float) mBitmapWidth; + dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; + } + + mShaderMatrix.setScale(scale, scale); + mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); + + mBitmapShader.setLocalMatrix(mShaderMatrix); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private class OutlineProvider extends ViewOutlineProvider { + + @Override + public void getOutline(View view, Outline outline) { + Rect bounds = new Rect(); + mBorderRect.roundOut(bounds); + outline.setRoundRect(bounds, bounds.width() / 2.0f); + } + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearAutoCompleteText.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearAutoCompleteText.java new file mode 100644 index 0000000..9c009b5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearAutoCompleteText.java @@ -0,0 +1,302 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; + +public class ClearAutoCompleteText extends android.support.v7.widget.AppCompatAutoCompleteTextView {// delete the onFocusChangeListener, + // incorrect use, at 20150512 + private Drawable imgLeftFoucus = null; + + private Drawable imgLeftUnFoucus = null; + + private Drawable imgRightFoucus = null; + + private Drawable imgRightUnFoucus = null; + + private Context context; + + private int mLimitedLen = -1; + + private boolean mbUnregFilter = false; + + private boolean mbPWDFilter = false; + + private boolean mbFocus = false; + + private int errorTip; + + private TextWatcher mTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + ClearAutoCompleteText.this.removeTextChangedListener(mTextWatcher); + filter(s); + setDrawable(); + ClearAutoCompleteText.this.addTextChangedListener(mTextWatcher); + } + }; + + public ClearAutoCompleteText(Context context) { + super(context); + this.context = context; + init(); + } + + public ClearAutoCompleteText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + this.context = context; + init(); + } + + public ClearAutoCompleteText(Context context, AttributeSet attrs) { + super(context, attrs); + this.context = context; + init(); + } + + private void init() { + addTextChangedListener(mTextWatcher); + // setOnFocusChangeListener(this); //not need, deleted at 20150512 + setDrawable(); + } + + /** + * 输入框是否可以复制|粘贴 + * + * @param copyAble + */ + public void setCopyAble(boolean copyAble) { + this.setLongClickable(copyAble); + } + + /** + * 设置编辑框前后图像 + * + * @param leftFocusResId + * (获取焦点时显示)当为0时表示不显示,其它则取资源文件 + * @param leftUnFocusResId + * (失去焦点时显示)当为0时表示不显示,其它则取资源文件 + * @param rightFocusResId + * 当为0时表示不显示,其它则取资源文件 + * @param rightUnFocusResId + * 当为0时表示不显示,其它则取资源文件 + */ + public void setDrawables(int leftFocusResId, int leftUnFocusResId, int rightFocusResId, int rightUnFocusResId) { + + if (leftFocusResId > 0) { + imgLeftFoucus = context.getResources().getDrawable(leftFocusResId); + } + + if (leftUnFocusResId > 0) { + imgLeftUnFoucus = context.getResources().getDrawable(leftUnFocusResId); + } + + if (rightFocusResId > 0) { + imgRightFoucus = context.getResources().getDrawable(rightFocusResId); + } + + if (rightUnFocusResId > 0) { + imgRightUnFoucus = context.getResources().getDrawable(rightUnFocusResId); + } else { + imgRightUnFoucus = null; + } + + setDrawable(); + } + + public void setFocus(boolean mFocus) { + mbFocus = mFocus; + } + + /** + * 设置删除图片 + */ + private void setDrawable() { + if (mbFocus) { + if (length() == 0) { + setCompoundDrawablesWithIntrinsicBounds(imgLeftFoucus, null, null, null); + } else { + setCompoundDrawablesWithIntrinsicBounds(imgLeftFoucus, null, imgRightFoucus, null); + } + } else { + if (length() == 0) { + setCompoundDrawablesWithIntrinsicBounds(imgLeftUnFoucus, null, null, null); + } else { + setCompoundDrawablesWithIntrinsicBounds(imgLeftUnFoucus, null, imgRightUnFoucus, null); + } + } + } + + /** + * event.getX() 获取相对应自身左上角的X坐标 event.getY() 获取相对应自身左上角的Y坐标 getWidth() 获取控件的宽度 + * getTotalPaddingRight() 获取删除图标左边缘到控件右边缘的距离 getPaddingRight() 获取删除图标右边缘到控件右边缘的距离 getWidth() - + * getTotalPaddingRight() 计算删除图标左边缘到控件左边缘的距离 getWidth() - getPaddingRight() 计算删除图标右边缘到控件左边缘的距离 + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + if (imgRightFoucus != null && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + // 判断触摸点是否在水平范围内 + boolean isInnerWidth = (x > (getWidth() - getTotalPaddingRight())) + && (x < (getWidth() - getPaddingRight())); + // 获取删除图标的边界,返回一个Rect对象 + Rect rect = imgRightFoucus.getBounds(); + // 获取删除图标的高度 + int height = rect.height(); + int y = (int) event.getY(); + // 计算图标底部到控件底部的距离 + int distance = (getHeight() - height) / 2; + // 判断触摸点是否在竖直范围内(可能会有点误差) + // 触摸点的纵坐标在distance到(distance+图标自身的高度)之内,则视为点中删除图标 + boolean isInnerHeight = (y > distance) && (y < (distance + height)); + if (isInnerWidth && isInnerHeight && mbFocus) { + setText(""); + } + + } + + return super.onTouchEvent(event); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + } + + public void onFocusChangeSelf(View v, boolean hasFocus) { + mbFocus = hasFocus; + setDrawable(); + } + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + + super.onFocusChanged(focused, direction, previouslyFocusedRect); + + onFocusChangeSelf(this, focused); + } + + /** + * 设置最大输入长度,1个中文计两个英文,且自动屏蔽不规则字符 + * + * @param maxlen + */ + public void setMaxLenth(int maxlen) { + if (maxlen > 0) { + mLimitedLen = maxlen; + } else { + mLimitedLen = 20; + } + } + + /** + * 是否限制特殊字符输入 + * + * @param enbale + */ + public void setUnregFilterEnbale(boolean enbale) { + mbUnregFilter = enbale; + } + + /** + * 是否限中文及制特殊字符输入,常用于密码输入 + * + * @param enbale + */ + public void setCHFilterEnbale(boolean enbale) { + mbPWDFilter = enbale; + } + + private int calcultateLength(CharSequence c) { + int len = 0; + for (int i = 0; i < c.length(); i++) { + int tmp = (int) c.charAt(i); + if (tmp > 0 && tmp < 127) { + len++; + } else { + len += 2; + } + } + return len; + } + + private void filter(Editable s) { + String str = s.toString(); + int indexStart = ClearAutoCompleteText.this.getSelectionStart(); + + if (mbPWDFilter) { + str = StringUtils.strPwdFilter(str); + int iDelLen = s.length() - str.length(); + if (iDelLen > 0) { + ClearAutoCompleteText.this.setText(str); + if (indexStart - iDelLen >= 0 && indexStart - iDelLen <= str.length()) { + ClearAutoCompleteText.this.setSelection(indexStart - iDelLen); + indexStart -= iDelLen; + } + } + } else if (mbUnregFilter) { + str = StringUtils.strFilter(s.toString()); + int iDelLen = s.length() - str.length(); + if (iDelLen > 0) { + ClearAutoCompleteText.this.setText(str); + if (indexStart - iDelLen >= 0 && indexStart - iDelLen <= str.length()) { + ClearAutoCompleteText.this.setSelection(indexStart - iDelLen); + indexStart -= iDelLen; + } + } + } + + limitLenght(str, indexStart); + } + + private void limitLenght(String str, int indexStart) { + if (mLimitedLen > 0) { + + boolean bFlag = false; + if (calcultateLength(str) > mLimitedLen) { + bFlag = true; + } + while (calcultateLength(str) > mLimitedLen) { + if (indexStart > 0 && indexStart <= str.length()) { + str = str.substring(0, indexStart - 1) + str.substring(indexStart, str.length()); + } else { + str = str.substring(0, str.length() - 1); + } + indexStart = indexStart - 1; + } + + if (bFlag) { + ClearAutoCompleteText.this.setText(str); + if (indexStart >= 0 && indexStart <= str.length()) { + ClearAutoCompleteText.this.setSelection(indexStart); + } + } + } + } + + public int getErrorTip() { + return errorTip; + } + + public void setErrorTip(int errorTip) { + this.errorTip = errorTip; + } + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearEditText.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearEditText.java new file mode 100644 index 0000000..3c6c5b0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearEditText.java @@ -0,0 +1,359 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.ActionMode; +import android.view.ActionMode.Callback; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnFocusChangeListener; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; + +public class ClearEditText extends android.support.v7.widget.AppCompatEditText implements OnFocusChangeListener, TextWatcher,Callback { + + // EditTxt右侧的删除按钮 + private Drawable mClearDrawable; + + private boolean hasFous; + + private int mLimitedLen = -1; + + private boolean mbPWDFilter = false; + + private boolean mbUnregFilter = false; + + private TextWatcher mTextWatcher; + + private ITextChangeListener mListener; + + private IFocusChangeListener mFocusListener; + + private boolean isVisiableClearIcon = true; + + public interface IFocusChangeListener{ + public void onClearTextFocusChange(View v, boolean hasFocus); + } + + public interface ITextChangeListener { + + public void afterChanged(EditText v, Editable s); + + public void beforeChanged(EditText v, CharSequence s, int start, int count, int after); + + public void onTextChanged(EditText v, CharSequence text, int start, int lengthBefore, int lengthAfter); + } + + public void setClearTextFocusChange(IFocusChangeListener listener){ + mFocusListener = listener; + } + + @SuppressWarnings("unchecked") + public void setTextChangeListener(ITextChangeListener l) { + mListener = l; + } + + public void setTextWathcher(TextWatcher textWatcher) { + mTextWatcher = textWatcher; + } + + public ClearEditText(Context context) { + this(context, null); + } + + public ClearEditText(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.editTextStyle); + } + + public ClearEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + // 获取EditText的DrawableRight, 假如没有设置我们就使用默认的图片,获取图片的顺序是左上右下(0.1.2.3) + mClearDrawable = getCompoundDrawables()[2]; + if (mClearDrawable == null) { + mClearDrawable = getResources().getDrawable(R.drawable.ic_password_clear); + } + + mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight()); + + //开启安全监控 + setFilterTouchesWhenObscured(true); + + // 默认设置隐藏图标 + setClearIconVisible(false); + + // 设置焦点改变的监听 + setOnFocusChangeListener(this); + + // 设置输入框里面内容发生改变的监听 + addTextChangedListener(this); + + // 默认设置不能copy +// setCopyAble(false); + } + + /** + * @说明: isInnerWidth, isInnerHeight为true, 触摸点在删除图标之内,则视为点击了删除图标 event.getX() 获取相应自身左上角的X坐标 + * event.getY() 获取相应自身左上角的Y坐标 getWidth() 获取控件的宽度 getHight() 获取控件的高度 getTotalPaddingRight() + * 获取删除图标左边边缘到控件右边缘的距离 getPaddubgRight() 获取删除图标右边边缘到控件右边缘的距离 isInnerWidth: getWidth() - + * getTotalPaddingRight() 计算删除图标左边缘到控件左边缘的距离 getWidth() - getPaddingRight() + * 计算删除图标右边缘到控件左边缘的距离 isInnerHight: `distance 删除图标顶部边缘带控件顶部边缘的距离 distance + height + * 删除图标底部边缘到控件顶部边缘的距离 + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + if (mClearDrawable != null) { + int x = (int) event.getX(); + int y = (int) event.getY(); + Rect rect = mClearDrawable.getBounds(); + int height = rect.height(); + int distance = (getHeight() - height) / 2; + boolean isInnerWidth = x > (getWidth() - getTotalPaddingRight()) + && x < (getWidth() - getPaddingRight()); + boolean isInnerHeight = y > distance && y < (distance + height); + + if (isInnerHeight && isInnerWidth) { + setText(""); + } + + } + } + return super.onTouchEvent(event); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + } + + public void setClearIconVisible(boolean visible) { + if(visible && !isVisiableClearIcon){ + return; + } + + Drawable right = visible ? mClearDrawable : null; + setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]); + } + + public boolean isVisiableClearIcon() { + return isVisiableClearIcon; + } + + public void setVisiableClearIcon(boolean visiableClearIcon) { + isVisiableClearIcon = visiableClearIcon; + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + this.hasFous = hasFocus; + if (hasFocus) { + setClearIconVisible(getText().length() > 0); + } else { + setClearIconVisible(false); + } + + if(mFocusListener != null){ + mFocusListener.onClearTextFocusChange(v, hasFocus); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + removeTextChangedListener(this); + if (mListener != null) { + mListener.beforeChanged(this, s, start, count, after); + } + + if (mTextWatcher != null) { + mTextWatcher.beforeTextChanged(s, start, count, after); + } + + addTextChangedListener(this); + + } + + @Override + public void afterTextChanged(Editable s) { + removeTextChangedListener(this); + filter(s); + if (mListener != null) { + mListener.afterChanged(this, s); + } + + if (mTextWatcher != null) { + mTextWatcher.afterTextChanged(s); + } + + addTextChangedListener(this); + } + + @Override + public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + + removeTextChangedListener(this); + + if (mListener != null) { + mListener.onTextChanged(this, text, start, lengthBefore, lengthAfter); + } + + if (mTextWatcher != null) { + mTextWatcher.onTextChanged(text, start, lengthBefore, lengthAfter); + } + addTextChangedListener(this); + + if (hasFous) { + setClearIconVisible(getText().toString().length() > 0); + } + + } + + /* 功能区 */ + + private void filter(Editable s) { + String str = s.toString(); + int indexStart = ClearEditText.this.getSelectionStart(); + + if (mbPWDFilter) { + str = StringUtils.strPwdFilter(str); + int iDelLen = s.length() - str.length(); + if (iDelLen > 0) { + ClearEditText.this.setText(str); + if (indexStart - iDelLen >= 0 && indexStart - iDelLen <= str.length()) { + ClearEditText.this.setSelection(indexStart - iDelLen); + indexStart -= iDelLen; + } + } + } else if (mbUnregFilter) { + str = StringUtils.strFilter(s.toString()); + int iDelLen = s.length() - str.length(); + if (iDelLen > 0) { + ClearEditText.this.setText(str); + if (indexStart - iDelLen >= 0 && indexStart - iDelLen <= str.length()) { + ClearEditText.this.setSelection(indexStart - iDelLen); + indexStart -= iDelLen; + } + } + } + + limitLenght(str, indexStart); + } + + /** + * 设置最大输入长度,1个中文计两个英文,且自动屏蔽不规则字符 + * + * @param maxlen + */ + public void setMaxLenth(int maxlen) { + if (maxlen > 0) { + mLimitedLen = maxlen; + } else { + mLimitedLen = 20; + } + } + + /** + * 输入框是否可以复制|粘贴(该方法只适合API11下的) + * + * @param copyAble + */ + public void setCopyAble(boolean copyAble) { + this.setLongClickable(copyAble); + if(copyAble){ + setCustomSelectionActionModeCallback(null); + }else{ + setCustomSelectionActionModeCallback(this); + setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + } + } + + /** + * 是否限制特殊字符输入 + * + * @param enbale + */ + public void setUnregFilterEnbale(boolean enbale) { + mbUnregFilter = enbale; + } + + /** + * 是否限中文及制特殊字符输入,常用于密码输入 + * + * @param enbale + */ + public void setCHFilterEnbale(boolean enbale) { + mbPWDFilter = enbale; + } + + private void limitLenght(String str, int indexStart) { + if (mLimitedLen > 0) { + + boolean bFlag = false; + if (calcultateLength(str) > mLimitedLen) { + bFlag = true; + } + while (calcultateLength(str) > mLimitedLen) { + if (indexStart > 0 && indexStart <= str.length()) { + str = str.substring(0, indexStart - 1) + str.substring(indexStart, str.length()); + } else { + str = str.substring(0, str.length() - 1); + } + indexStart = indexStart - 1; + } + + if (bFlag) { + setText(str); + if (indexStart >= 0 && indexStart <= str.length()) { + setSelection(indexStart); + } + } + } + } + + private int calcultateLength(CharSequence c) { + int len = 0; + for (int i = 0; i < c.length(); i++) { + int tmp = c.charAt(i); + if (tmp > 0 && tmp < 127) { + len++; + } else { + len += 2; + } + } + return len; + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearPasswordEditText.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearPasswordEditText.java new file mode 100644 index 0000000..1f237df --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ClearPasswordEditText.java @@ -0,0 +1,315 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.ActionMode; +import android.view.ActionMode.Callback; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnFocusChangeListener; + +import com.mm.android.deviceaddmodule.R; + +public class ClearPasswordEditText extends android.support.v7.widget.AppCompatEditText implements + OnFocusChangeListener, TextWatcher, Callback { + + private Bitmap mClearDrawable, mOpenDrawable, mShutDrawable, + mRightDrawable; + + private Paint mPaint; + + private boolean hasFous; + + private boolean mIsClearIconVisible = false; + + private boolean mIsPassWordShut = true; + + private TextWatcher mTextWatcher; + + private ClearEditText.ITextChangeListener mListener; + + /** + * 焦点改变监听,提供外部使用 + */ + private ClearEditText.IFocusChangeListener mOnFocusChangeEXListener; + + /** + * 设置焦点改变监听 + */ + public void setOnFocusChangeEXListener(ClearEditText.IFocusChangeListener listener) { + this.mOnFocusChangeEXListener = listener; + } + + @SuppressWarnings("unchecked") + public void setTextChangeListener(ClearEditText.ITextChangeListener l) { + mListener = l; + } + + public void setTextWathcher(TextWatcher textWatcher) { + mTextWatcher = textWatcher; + } + + public ClearPasswordEditText(Context context) { + this(context, null); + } + + public ClearPasswordEditText(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.editTextStyle); + } + + + public ClearPasswordEditText(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + mClearDrawable = BitmapFactory.decodeResource(getResources(), + R.drawable.mobile_common_icon_deleteinput); + mOpenDrawable = BitmapFactory.decodeResource(getResources(), + R.drawable.ic_password_visible); + mShutDrawable = BitmapFactory.decodeResource(getResources(), + R.drawable.ic_password_invisible); + + mRightDrawable = mShutDrawable; + + setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + setTypeface(Typeface.DEFAULT); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + //开启安全监控 + setFilterTouchesWhenObscured(true); + + // 密码输入框为自定义控件,初始化时调用setFilterTouchesWhenObscured(true)接口,开启安全监控 + setFilterTouchesWhenObscured(true); + + // 设置焦点改变的监听 + setOnFocusChangeListener(this); + + // 设置输入框里面内容发生改变的监听 + addTextChangedListener(this); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + if (mIsClearIconVisible) { + isClearIconChange(x, y); + } + + boolean change = isPassWordShutChange(x, y); + if (change) { + invalidate(); + } + + } + + return super.onTouchEvent(event); + } + + private boolean isPassWordShutChange(int x, int y) { + int height = mRightDrawable.getHeight(); + int distance = (getHeight() - height) / 10; + boolean isInnerWidth = x > (getWidth() - mRightDrawable.getWidth() - getPaddingRight() - 5) + && x < (getWidth() - getPaddingRight() + 20); + + boolean isInnerHeight = y > distance - 20 && y < (distance + height) + 20; + + + + if (isInnerHeight && isInnerWidth) { + int selIndexStart = getSelectionStart(); + int selIndexStop = getSelectionEnd(); + mIsPassWordShut = !mIsPassWordShut; + if (mIsPassWordShut) { + mRightDrawable = mShutDrawable; + setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD); + setTypeface(Typeface.DEFAULT); + + } else { + + mRightDrawable = mOpenDrawable; + setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + setTypeface(Typeface.DEFAULT); + } + setSelection(selIndexStart, selIndexStop); + return true; + } + return false; + } + + private void isClearIconChange(int x, int y) { + int height = mClearDrawable.getHeight(); + int distance = (getHeight() - height) / 2; + boolean isInnerWidth = x > (getWidth() - (mRightDrawable.getWidth() + + mClearDrawable.getWidth() + getPaddingRight() + 10)) + && x < (getWidth() - (mRightDrawable.getWidth() + + getPaddingRight() + 10)); + + boolean isInnerHeight = y > distance && y < (distance + height); + + if (isInnerHeight && isInnerWidth) { + setText(""); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + + + canvas.drawBitmap(mRightDrawable, + getScrollX() + getWidth() - mRightDrawable.getWidth() - getPaddingRight(), + (getHeight() - mRightDrawable.getHeight()) / 2, mPaint); + + + if (mIsClearIconVisible) { + canvas.drawBitmap( + mClearDrawable, + getScrollX()+ getWidth() + - (mRightDrawable.getWidth() + + mClearDrawable.getWidth() + + getPaddingRight() + 10), + (getHeight() - mClearDrawable.getHeight()) / 2, mPaint); + } + + } + + public int getCompoundPaddingRight() { + int paddingRight = super.getCompoundPaddingRight(); + + return paddingRight + mRightDrawable.getWidth() + mClearDrawable.getWidth() + 50; + } + + public void setCopyAble(boolean copyAble) { + this.setLongClickable(copyAble); + if (copyAble) { + setCustomSelectionActionModeCallback(null); + } else { + setCustomSelectionActionModeCallback(this); + } + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + removeTextChangedListener(this); + if (mListener != null) { + mListener.beforeChanged(this, s, start, count, after); + } + + if (mTextWatcher != null) { + mTextWatcher.beforeTextChanged(s, start, count, after); + } + + addTextChangedListener(this); + } + + @Override + public void afterTextChanged(Editable s) { + removeTextChangedListener(this); + if (mListener != null) { + mListener.afterChanged(this, s); + } + + if (mTextWatcher != null) { + mTextWatcher.afterTextChanged(s); + } + + addTextChangedListener(this); + } + + @Override + public void onTextChanged(CharSequence text, int start, int lengthBefore, + int lengthAfter) { + removeTextChangedListener(this); + + if (mListener != null) { + mListener.onTextChanged(this, text, start, lengthBefore, + lengthAfter); + } + + if (mTextWatcher != null) { + mTextWatcher.onTextChanged(text, start, lengthBefore, lengthAfter); + } + addTextChangedListener(this); + + if (hasFous) { + setClearIconVisible(getText().toString().length() > 0); + } + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + this.hasFous = hasFocus; + + if (hasFocus) { + setClearIconVisible(getText().length() > 0); + } else { + setClearIconVisible(false); + } + + if(mOnFocusChangeEXListener != null) { + mOnFocusChangeEXListener.onClearTextFocusChange(v,hasFocus); + } + } + + private void setClearIconVisible(boolean b) { + mIsClearIconVisible = b; + invalidate(); + } + + public void openEyeMode(boolean open){ + mIsPassWordShut = !open; + if (open) { + mRightDrawable = mOpenDrawable; + setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + setTypeface(Typeface.DEFAULT); + } else { + mRightDrawable = mShutDrawable; + setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD); + setTypeface(Typeface.DEFAULT); + } + invalidate(); + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonItem.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonItem.java new file mode 100644 index 0000000..d3be914 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonItem.java @@ -0,0 +1,466 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.support.annotation.DrawableRes; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.decode.FileImageDecoder; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; + +public class CommonItem extends RelativeLayout { + private View mTopLine; + private View mBottomLine; + private TextView mNameTv; + private TextView mSubTv; + private TextView mTitleTv; + private ImageView mImageView; + private ProgressBar mLoadingPb; + private TextView mSwitchTv; + + private OnSwitchClickListener mListener; + + public CommonItem(Context context) { + this(context, null); + } + + public CommonItem(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(context).inflate(R.layout.widget_common_itme, this); + initView(); + setListeners(); + } + + public TextView getTittle() { + return mTitleTv; + } + + private void initView() { + mTopLine = findViewById(R.id.top_line); + mBottomLine = findViewById(R.id.bottom_line); + mNameTv = (TextView) findViewById(R.id.name_tv); + mSubTv = (TextView) findViewById(R.id.sub_tv); + mTitleTv = (TextView) findViewById(R.id.title_tv); + mImageView = (ImageView) findViewById(R.id.img_iv); + mLoadingPb = (ProgressBar) findViewById(R.id.loading_pb); + mSwitchTv = (TextView) findViewById(R.id.switch_tv); + } + + private void setListeners() { + mSwitchTv.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonSwitchClick(CommonItem.this); + } + } + }); + } + + public void setOnSwitchClickListener(OnSwitchClickListener listener) { + mListener = listener; + } + + + public interface OnSwitchClickListener { + void onCommonSwitchClick(View view); + } + + + /** + * 设置标题 + * + * @param resId + */ + public void setTitle(int resId) { + if (mTitleTv == null || resId <= 0) { + return; + } + mTitleTv.setText(resId); + } + + /** + * 目前仅我的页面使用,增加了左侧的drawable不显示下划线l + * + * @param drawableLeft + */ + @SuppressLint("ResourceType") + public void setCompoundDrawableLeft(@DrawableRes int drawableLeft) { + if (mTitleTv == null) { + return; + } + mBottomLine.setVisibility(View.GONE); + if (drawableLeft <= 0) { + mTitleTv.setCompoundDrawablePadding(0); + mTitleTv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } else { + mTitleTv.setCompoundDrawablePadding((int) Utils.dp2px(13)); + mTitleTv.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, 0, 0, 0); + } + } + + /** + * 设置标题 + * + * @param title + */ + public void setTitle(String title) { + if (mTitleTv == null || title == null) { + return; + } + mTitleTv.setText(title); + } + + /** + * 设置名称 + * + * @param resId + */ + public void setName(int resId) { + if (mNameTv == null || resId <= 0) { + return; + } + mNameTv.setText(resId); + setNameVisible(true); + setImageVisible(false); + setLoadingVisible(false); + setSwitchVisible(false); + } + + /** + * 设置名称 + * + * @param name + */ + public void setName(String name) { + if (mNameTv == null || name == null) { + return; + } + mNameTv.setText(name); + setNameVisible(true); + setImageVisible(false); + setLoadingVisible(false); + setSwitchVisible(false); + } + + /** + * 设置名称 + */ + public String getName() { + if (mNameTv == null) { + return ""; + } + return mNameTv.getText().toString(); + } + + /** + * 设置箭头显示 + * + * @param visible + */ + public void setSubVisible(boolean visible) { + if (mSubTv == null) { + return; + } + if (visible) { + mSubTv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.device_manager_icon_nextarrow, 0); + } else { + mSubTv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + } + + /** + * 设置进度条显示 + * + * @param visible + */ + public void setLoadingVisible(boolean visible) { + if (mLoadingPb == null) { + return; + } + mLoadingPb.setVisibility(visible ? View.VISIBLE : View.GONE); + if (visible) { + setNameVisible(false); + setSwitchVisible(false); + setImageVisible(false); + } + } + + private void setNameVisible(boolean visible) { + if (mNameTv == null) { + return; + } + mNameTv.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + public void setSwitchVisible(boolean visible) { + if (mSwitchTv == null) { + return; + } + mSwitchTv.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + private void setImageVisible(boolean visible) { + if (mImageView == null) { + return; + } + mImageView.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + /** + * 设置顶部分割线显示 + * + * @param visible + */ + public void setTopLineVisible(boolean visible) { + if (mTopLine == null) { + return; + } + mTopLine.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + /** + * 设置底部分割线显示 + * + * @param visible + */ + public void setBottomLineVisible(boolean visible) { + if (mBottomLine == null) { + return; + } + mBottomLine.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + public void setBottomLineLeftMargin(int dp) { + if (mBottomLine == null) { + return; + } + + int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mBottomLine.getContext().getResources().getDisplayMetrics()); + setMargins(mBottomLine, px, 0, 0, 0); + } + + public void setNameRightMargin(int dp){ + if (mNameTv == null) { + return; + } + + int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mNameTv.getContext().getResources().getDisplayMetrics()); + setMargins(mNameTv, 0, 0, px, 0); + } + + + /** + * 设置无权限显示 + */ + public void setItemNoAuthority() { + setName(R.string.common_no_authority); + setItemEnable(false); + setTitleEnable(true); + } + + public void setTitleEnable(boolean enable) { + if (mTitleTv == null) { + return; + } + mTitleTv.setEnabled(enable); + } + + /** + * 设置置灰显示 + */ + public void setItemEnable(boolean enable) { +// setTitleEnable(enable); +// setNameEnable(enable); + setDevManagerItemEnable(enable, this, mSubTv); +// setSwitchEnable(enable); +// setSubVisible(enable); + setClickable(enable); + } + + public void setIteEnableWithoutClickEnable(boolean enable) { + setDevManagerItemEnable(enable, this, null); + } + + private void setDevManagerItemEnable(boolean enabled, ViewGroup viewGroup, TextView tv) { + UIUtils.setEnabledSub(enabled, viewGroup); + + if (tv == null) { + return; + } + if (enabled) { + tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.device_manager_icon_nextarrow, 0); + } else { + tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + } + + /** + * 设置是否可点击 + */ + public void setItemClickable(boolean clickable) { + setClickable(clickable); + setSubVisible(clickable); + } + + /** + * 设置离线显示 + */ + public void setItemOffLine() { + setName(R.string.common_offline); + setItemEnable(false); + } + + /** + * 设置封面图标显示 + * + * @param url + */ + public void setImage(String url, FileImageDecoder fileImageDecoder) { + setImageVisible(true); + if (!TextUtils.isEmpty(url)) { + ImageLoader.getInstance().displayImage(url, mImageView, + new SimpleImageLoadingListener() { + @Override + public void onLoadingStarted(String imageUrl, View view) { + + mLoadingPb.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadingComplete(String imageUrl, + View view, Bitmap loadImage) { + mLoadingPb.setVisibility(View.GONE); + } + + @Override + public void onLoadingFailed(String imageUrl, View view, + FailReason failReason) { + mImageView.setBackgroundResource(R.drawable.default_cover_small); + mLoadingPb.setVisibility(View.GONE); + } + }, fileImageDecoder); + } else { + mImageView.setBackgroundResource(R.drawable.default_cover_small); + } + setSwitchVisible(false); + setNameVisible(false); + } + + /** + * 设置封面图不显示 + */ + public void setImageInVisible() { + setImageVisible(false); + setNameVisible(false); + setSwitchVisible(false); + setLoadingVisible(false); + } + + /** + * 设置是否选中 + * + * @param isSelected + */ + public void setSwitchSelected(boolean isSelected) { + if (mSwitchTv == null) { + return; + } + mSwitchTv.setSelected(isSelected); + setSwitchVisible(true); + setNameVisible(false); + setLoadingVisible(false); + setSubVisible(false); + } + + /** + * 获取是否选中 + */ + public boolean isSwitchSelected() { + return mSwitchTv != null && mSwitchTv.isSelected(); + } + + /** + * 设置按钮是否可点击 + * + * @param enable + */ + public void setSwitchEnable(boolean enable) { + if (mSwitchTv == null) { + return; + } + mSwitchTv.setEnabled(enable); + } + + /** + * 是否显示红点 + * + * @param hasRedDot + */ + public void setNameRedDot(boolean hasRedDot) { + if (mNameTv == null) { + return; + } + if (hasRedDot) { + mNameTv.setCompoundDrawablesWithIntrinsicBounds( + 0, + 0, + R.drawable.common_newmessage, + 0); + } else { + mNameTv.setCompoundDrawablesWithIntrinsicBounds( + 0, + 0, + 0, + 0); + } + } + + // 设置view 的margin值 + public static void setMargins(View v, int l, int t, int r, int b) { + if (v.getLayoutParams() instanceof MarginLayoutParams) { + MarginLayoutParams p = (MarginLayoutParams) v.getLayoutParams(); + p.setMargins(l, t, r, b); + v.requestLayout(); + } + } + + //设置无箭头显示 + public void setNoArrowName(int resId) { + setName(resId); + setSubVisible(false); + setLoadingVisible(false); + } + + public void setRightDrawableCheck(boolean isCheck) { + setName(""); + if (isCheck) { + mNameTv.setCompoundDrawablesWithIntrinsicBounds( + 0, + 0, + R.drawable.setting_icon_check, + 0); + } else { + mNameTv.setCompoundDrawablesWithIntrinsicBounds( + 0, + 0, + 0, + 0); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonMenu4Lc.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonMenu4Lc.java new file mode 100644 index 0000000..407d7f9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonMenu4Lc.java @@ -0,0 +1,112 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * BottomMenuDialog按钮资源(注:TextAppearance中属性会被TextColor和TextSize属性覆盖) + */ +public class CommonMenu4Lc implements Parcelable { + private int mTextResId; //按钮文字字符串资源 + private int mTextColorResId; //按钮文字颜色资源 + private float mTextSize = -1; //按钮文字大小 + private int mBackgroundResId; //按钮背景资源 + private int mTextAppearanceResId; //文字外观Style + private int[] mMargins = new int[4]; //按钮Margins + + public CommonMenu4Lc() { + + } + + public CommonMenu4Lc(int strRes) { + mTextResId = strRes; + } + + protected CommonMenu4Lc(Parcel in) { + mTextResId = in.readInt(); + mTextColorResId = in.readInt(); + mTextSize = in.readFloat(); + mBackgroundResId = in.readInt(); + mTextAppearanceResId = in.readInt(); + mMargins = in.createIntArray(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public CommonMenu4Lc createFromParcel(Parcel in) { + return new CommonMenu4Lc(in); + } + + @Override + public CommonMenu4Lc[] newArray(int size) { + return new CommonMenu4Lc[size]; + } + }; + + public int getTextAppearance() { + return mTextAppearanceResId; + } + + public void setTextAppearance(int textAppearance) { + mTextAppearanceResId = textAppearance; + } + + public int getStringId() { + return mTextResId; + } + + public void setStringId(int stringId) { + mTextResId = stringId; + } + + public int getColorId() { + return mTextColorResId; + } + + public void setColorId(int colorId) { + mTextColorResId = colorId; + } + + public int getDrawId() { + return mBackgroundResId; + } + + public void setDrawId(int drawId) { + mBackgroundResId = drawId; + } + + public int[] getMargins() { + return mMargins; + } + + public void setMargins(int left, int top, int right, int bottom) { + mMargins[0] = left; + mMargins[1] = top; + mMargins[2] = right; + mMargins[3] = bottom; + } + + public float getTextSize() { + return mTextSize; + } + + public void setTextSize(int textSize) { + this.mTextSize = textSize; + } + + @Override + public int describeContents() { + + return 0; + } + + @Override + public void writeToParcel(Parcel arg0, int arg1) { + arg0.writeInt(mTextResId); + arg0.writeInt(mTextColorResId); + arg0.writeFloat(mTextSize); + arg0.writeInt(mBackgroundResId); + arg0.writeInt(mTextAppearanceResId); + arg0.writeIntArray(mMargins); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonRatioImageView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonRatioImageView.java new file mode 100644 index 0000000..cef0440 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonRatioImageView.java @@ -0,0 +1,67 @@ +/** + * All rights Reserved. + * 16:9宽高比的ImageView + */ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; + +import com.mm.android.deviceaddmodule.R; + +/** + * 自定义宽高比的ImageView,默认1:1 + + * 自定义属性: + * + 相对宽度 + 相对高度 + + * + * 应用: + * + * + */ +public class CommonRatioImageView extends android.support.v7.widget.AppCompatImageView { + + private float width_relative = 1.0f; + private float height_relative = 1.0f; + + public CommonRatioImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CommonRatioImageView); + if(array == null)return; + width_relative = array.getDimension(R.styleable.CommonRatioImageView_width_relative,1.0f); + height_relative = array.getDimension(R.styleable.CommonRatioImageView_height_relative,1.0f); + array.recycle(); + } + + public CommonRatioImageView(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CommonRatioImageView); + if(array == null)return; + width_relative = array.getDimension(R.styleable.CommonRatioImageView_width_relative,1.0f); + height_relative = array.getDimension(R.styleable.CommonRatioImageView_height_relative,1.0f); + array.recycle(); + } + + public CommonRatioImageView(Context context) { + super(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); + int heightSize = Math.round(widthSize * height_relative/width_relative); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSubTitle.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSubTitle.java new file mode 100644 index 0000000..a39d955 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSubTitle.java @@ -0,0 +1,843 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; + +/** + *

+ * 工具类使用说明:左按钮,左内按钮,中间按钮,右内按钮,右按钮,均支持图片和文字背景二选一,左右按钮默认支持图片,中间按钮默认支持文字 + *

+ *

+ * xml使用注意:需要在xml文件中使用style="@style/common_titile" + *

+ *

+ * 函数使用介绍: + *

+ *

+ * initView(int tvLeftResId, int tvRightResId, int tvCenterResId) 初始化控件:左按钮,中间按钮,右按钮,属于普通用法 + *

+ *

+ * getTextViewXXX() 获取xxx按钮,进行自定义功能扩展操作。例如,实现展开下来listview的功能 + *

+ *

+ * setTitleXXXView(int resId, int colorId, int textSizeDimenId) 设置xxx按钮的文字,文字颜色,文字大小 + *

+ *

+ * setTitleXXX(int resId) 设置xxx按钮图片或文字 + *

+ *

+ * setTextColorXXX(int colorId) 设置xxx按钮文字的颜色资源 + *

+ *

+ * setTextSizeXXX(int textSizeDimenId) 设置xxx按钮文字的大小 + *

+ *

+ * setTitleTextXXX(int resId) 通过resId设置xxx按钮的文字 + *

+ *

+ * setTitleTextXXX(String titleTextXXX) 通过String设置xxx按钮的文字 + *

+ *

+ * setVisibleXXX(int flag) 通过flag设置xxx是否隐藏,flag:View.GONE,View.INVISIBLE,View.VISIBLE; + *

+ */ +public class CommonSubTitle extends RelativeLayout +// implements OnClickListener +{ + /** + * 左侧按钮ID + */ + public static final int ID_LEFT = 0; + + /** + * 左侧内按钮ID + */ + public static final int ID_LEFT_2 = 1; + + /** + * 右侧按钮ID + */ + public static final int ID_RIGHT = 2; + + /** + * 右侧内按钮ID + */ + public static final int ID_RIGHT_2 = 3; + + /** + * 中间按钮ID, 暂时不加监听器 + */ + public static final int ID_CENTER = 4; + + /** + * 中间下方按钮ID, 暂时不加监听器 + */ + public static final int ID_CENTER_SUB = 5; + + /** + * 左侧按钮/ 左侧按钮LinearLayout + */ + private TextView mTitleLeftTv; + + private LinearLayout mTitleLeftLl; + + /** + * 左侧按钮(靠内) /左侧按钮(靠内)LinearLayout + */ + private TextView mTitleLeft2Tv; + + private LinearLayout mTitleLeft2Ll; + + /** + * 右侧按钮 /右侧按钮LinearLayout + */ + private TextView mTitleRightTv; + + private LinearLayout mTitleRightLl; + + /** + * 右侧按钮(靠内) /右侧按钮(靠内)LinearLayout + */ + private TextView mTitleRight2Tv; + + private LinearLayout mTitleRight2Ll; + + /** + * 大标题(上)/小标题(下)LinearLayout + */ + private LinearLayout mTitleCenterLl; + + private TextView mTitleCenterTv; + + private TextView mTitleCenterSubTv; + + /** + * 点击监听 + */ + private OnTitleSubClickListener mListener; + + private View mBottomV; + + /** + * 默认隐藏左2和右2的按钮 ,创建一个新的实例CommonTitle. + * + * @param context + * @param attrs + */ + public CommonSubTitle(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(context).inflate(R.layout.widget_common_sub_title, this); + initView(); + setListeners(); + setVisibleLeft2(View.GONE); + setVisibleRight2(View.GONE); + } + + private void initView() { + mBottomV = findViewById(R.id.v_bottom_line); + mTitleLeftLl = findViewById(R.id.ll_title_left); + mTitleLeft2Ll = findViewById(R.id.ll_title_left2); + mTitleRightLl = findViewById(R.id.ll_title_right); + mTitleRight2Ll = findViewById(R.id.ll_title_right2); + mTitleCenterLl = findViewById(R.id.ll_title_center); + + mTitleLeftTv = findViewById(R.id.tv_title_left); + mTitleLeft2Tv = findViewById(R.id.tv_title_left2); + mTitleRightTv = findViewById(R.id.tv_title_right); + mTitleRight2Tv = findViewById(R.id.tv_title_right2); + mTitleCenterTv = findViewById(R.id.tv_title_center); + mTitleCenterSubTv = findViewById(R.id.tv_title_center_sub); + + mTitleLeftTv.setTextColor(getResources().getColor(R.color.common_title_text_color)); + mTitleLeft2Tv.setTextColor(getResources().getColor(R.color.common_title_text_color)); + mTitleRightTv.setTextColor(getResources().getColor(R.color.common_title_text_color)); + mTitleRight2Tv.setTextColor(getResources().getColor(R.color.common_title_text_color)); + mTitleCenterTv.setTextColor(getResources().getColor(R.color.c2)); + + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources() + .getDimensionPixelSize(R.dimen.text_size_mid)); + mTitleLeft2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.text_size_mid)); + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.text_size_mid)); + mTitleRight2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.text_size_mid)); + mTitleCenterTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.text_size_large)); + } + + private void setListeners() { + mTitleLeftLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_LEFT); + } + + } + }); + + mTitleLeft2Ll.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_LEFT_2); + } + + } + }); + + mTitleRightLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_RIGHT); + } + + } + }); + + mTitleRight2Ll.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_RIGHT_2); + } + }); + + mTitleCenterLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_CENTER); + } + }); + } + + /** + *

+ * 初始化参数,按钮均可支持图片或者文字背景 + * @param tvLeftResId + * 左按钮 + * @param tvRightResId + * 右按钮 + * @param tvCenterResId + * 中间按钮 + */ + + public void initView(int tvLeftResId, int tvRightResId, int tvCenterResId) { + setTitleLeftView(tvLeftResId, 0, 0); + setTitleRightView(tvRightResId, 0, 0); + setTitleCenterView(tvCenterResId, 0, 0); + } + + public TextView getTextViewCenter() { + return mTitleCenterTv; + } + + public TextView getTextViewCenterSub() { + return mTitleCenterSubTv; + } + + /** + *

+ * 设置是否选中按钮 + *

+ * @param selected + * {true,false} + * @param id + * {ID_LEFT ,ID_LEFT_2,ID_RIGHT,ID_RIGHT_2,ID_CENTER} + */ + public void setTitleSelected(boolean selected, int id) { + View v = findViewByID(id); + if (v != null) { + v.setSelected(selected); + } + } + + /** + *

+ * 设置按钮是否可用 + *

+ */ + public void setTitleEnabled(boolean enabled, int id) { + View v = findParentViewById(id); + if (v != null) { + UIUtils.setEnabledEX(enabled, v); + } + } + + private View findParentViewById(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftLl; + case ID_LEFT_2: + return mTitleLeft2Ll; + case ID_RIGHT: + return mTitleRightLl; + case ID_RIGHT_2: + return mTitleRight2Ll; + case ID_CENTER: + return mTitleCenterLl; + default: + return null; + } + } + + private View findViewByID(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftTv; + case ID_LEFT_2: + return mTitleLeft2Tv; + case ID_RIGHT: + return mTitleRightTv; + case ID_RIGHT_2: + return mTitleRight2Tv; + case ID_CENTER: + return mTitleCenterTv; + case ID_CENTER_SUB: + return mTitleCenterSubTv; + default: + return null; + } + } + + /*------------------------------------------getTextView END------------------------------*/ + + /*-----------------------------------setTitleView START---------------------------------*/ + public void setTitleLeftView(int resId, int colorId, int textSizeDimenId) { + setTitleLeft(resId); + setTextColorLeft(colorId); + setTextSizeLeft(textSizeDimenId); + } + + public void setTitleRightView(int resId, int colorId, int textSizeDimenId) { + setTitleRight(resId); + setTextColorRight(colorId); + setTextSizeRight(textSizeDimenId); + } + + public void setTitleCenterView(int resId, int colorId, int textSizeDimenId) { + setTitleCenter(resId); + setTextColorCenter(colorId); + setTextSizeCenter(textSizeDimenId); + } + + /*-----------------------------------setTitleView END---------------------------------*/ + /*------------------------------------------setTitle START------------------------------*/ + /** + *

+ * 设置左边按钮图片或文字 + *

+ * @param leftResId + */ + public void setTitleLeft(int leftResId) { + if (mTitleLeftTv != null) { + if (leftResId != 0) { + if (mTitleLeftLl != null && mTitleLeftLl.getVisibility() != View.VISIBLE) + mTitleLeftLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(leftResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleLeftTv.setBackgroundResource(leftResId); + mTitleLeftTv.setText(null); + } else { + mTitleLeftTv.setText(leftResId); + mTitleLeftTv.setBackgroundResource(0); + } + } + } else { + if (mTitleLeftLl != null) + mTitleLeftLl.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置左边按钮图片或文字 + *

+ */ + public void setTitleLeft2(int left2ResId) { + if (mTitleLeft2Tv != null) { + if (left2ResId != 0) { + if (mTitleLeft2Ll != null && mTitleLeft2Ll.getVisibility() != View.VISIBLE) + mTitleLeft2Ll.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(left2ResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleLeft2Tv.setBackgroundResource(left2ResId); + mTitleLeft2Tv.setText(null); + } else { + mTitleLeft2Tv.setText(left2ResId); + mTitleLeft2Tv.setBackgroundResource(0); + } + } + } else { + if (mTitleLeft2Ll != null) + mTitleLeft2Ll.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置右边按钮图片或文字 + *

+ * + * @param rightResId + */ + public void setTitleRight(int rightResId) { + if (mTitleRightTv != null) { + if (rightResId != 0) { + if (mTitleRightLl != null && mTitleRightLl.getVisibility() != View.VISIBLE) + mTitleRightLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(rightResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleRightTv.setBackgroundResource(rightResId); + mTitleRightTv.setText(null); + } else { + mTitleRightTv.setText(rightResId); + mTitleRightTv.setBackgroundResource(0); + } + + } + } else { + if (mTitleRightLl != null) + mTitleRightLl.setVisibility(INVISIBLE); + } + } + } + + public void setTitleRight2(int right2ResId) { + if (mTitleRight2Tv != null) { + if (right2ResId != 0) { + if (mTitleRight2Ll != null && mTitleRight2Ll.getVisibility() != View.VISIBLE) + mTitleRight2Ll.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(right2ResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleRight2Tv.setBackgroundResource(right2ResId); + mTitleRight2Tv.setText(null); + } else { + mTitleRight2Tv.setText(right2ResId); + mTitleRight2Tv.setBackgroundResource(0); + } + } + } else { + if (mTitleRight2Ll != null) + mTitleRight2Ll.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置中间按钮图片或文字 + *

+ * + * @param centerResId + */ + public void setTitleCenter(int centerResId) { + if (mTitleCenterTv != null) { + if (centerResId != 0) { + if (mTitleCenterLl != null && mTitleCenterLl.getVisibility() != View.VISIBLE) + mTitleCenterLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(centerResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleCenterTv.setBackgroundResource(centerResId); + mTitleCenterTv.setText(null); + } else { + mTitleCenterTv.setText(centerResId); + mTitleCenterTv.setBackgroundResource(0); + } + } + } else { + if (mTitleCenterLl != null) + mTitleCenterLl.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置中间下方按钮图片或文字 + *

+ * + * @param centerResId + */ + public void setTitleCenterSub(int centerResId) { + if (mTitleCenterSubTv != null) { + if (centerResId != 0) { + if (mTitleCenterLl != null && mTitleCenterLl.getVisibility() != View.VISIBLE) + mTitleCenterLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(centerResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleCenterSubTv.setBackgroundResource(centerResId); + mTitleCenterSubTv.setText(null); + } else { + mTitleCenterSubTv.setText(centerResId); + mTitleCenterSubTv.setBackgroundResource(0); + } + } + } else { + if (mTitleCenterLl != null) + mTitleCenterLl.setVisibility(INVISIBLE); + } + } + } + + /*------------------------------------------setTitle END------------------------------*/ + /*-----------------------------------------setTextColor START--------------------------------------*/ + public void setTextColorLeft(int colorId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.common_title_text_color)); + } + } + + public void setTextColorLeft2(int colorId) { + if (mTitleLeft2Tv != null) { + mTitleLeft2Tv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.common_title_text_color)); + } + } + + public void setTextColorRight(int colorId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextColor(colorId != 0 ? getResources().getColorStateList(colorId) : getResources() + .getColorStateList(R.color.common_title_text_color)); + } + } + + public void setTextColorRight2(int colorId) { + if (mTitleRight2Tv != null) { + mTitleRight2Tv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c43)); + } + } + + public void setTextColorCenter(int colorId) { + if (mTitleCenterTv != null) { + mTitleCenterTv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c2)); + } + } + + public void setTextColorCenterSub(int colorId) { + if (mTitleCenterSubTv != null) { + mTitleCenterSubTv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c2)); + } + } + + /*-----------------------------------------setTextColor END--------------------------------------*/ + /*-----------------------------------------setTextSize START--------------------------------------*/ + public void setTextSizeLeft(int textSizeDimenId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_mid)); + } + } + + public void setTextSizeLeft2(int textSizeDimenId) { + if (mTitleLeft2Tv != null) { + mTitleLeft2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_mid)); + } + } + + public void setTextSizeRight(int textSizeDimenId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_mid)); + } + } + + public void setTextSizeRight2(int textSizeDimenId) { + if (mTitleRight2Tv != null) { + mTitleRight2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_mid)); + } + } + + public void setTextSizeCenter(int textSizeDimenId) { + if (mTitleCenterTv != null) { + mTitleCenterTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_large)); + } + } + + public void setTextSizeCenterSub(int textSizeDimenId) { + if (mTitleCenterSubTv != null) { + mTitleCenterSubTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.text_size_small)); + } + } + + /*-----------------------------------------setTextSize END--------------------------------------*/ + + /*-----------------------------------------setIcon START--------------------------------------*/ + + public void setIconLeft(int resId) { + if (mTitleLeftLl != null) { + if (mTitleLeftLl.getVisibility() != View.VISIBLE) { + mTitleLeftLl.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setIconLeft2(int resId) { + if (mTitleLeft2Ll != null) { + if (mTitleLeft2Ll.getVisibility() != View.VISIBLE) { + mTitleLeft2Ll.setVisibility(View.VISIBLE); + } + setTitleLeft2(resId); + } + } + + public void setIconRight(int resId) { + if (mTitleRightLl != null) { + if (mTitleRightLl.getVisibility() != View.VISIBLE) { + mTitleRightLl.setVisibility(View.VISIBLE); + } + setTitleRight(resId); + } + } + + public void setIconRight2(int resId) { + if (mTitleRight2Ll != null) { + if (mTitleRight2Ll.getVisibility() != View.VISIBLE) { + mTitleRight2Ll.setVisibility(View.VISIBLE); + } + setTitleRight2(resId); + } + } + + public void setIconCenter(int resId) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + setTitleCenter(resId); + } + } + + /*-----------------------------------------setIcon END--------------------------------------*/ + /*-----------------------------------------setTextById START--------------------------------------*/ + + public void setTitleTextLeft(int resId) { + if (mTitleLeftLl != null) { + if (mTitleLeftLl.getVisibility() != View.VISIBLE) { + mTitleLeftLl.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setTitleTextLeft2(int resId) { + if (mTitleLeft2Ll != null) { + if (mTitleLeft2Ll.getVisibility() != View.VISIBLE) { + mTitleLeft2Ll.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setTitleTextRight(int resId) { + if (mTitleRightLl != null) { + if (mTitleRightLl.getVisibility() != View.VISIBLE) { + mTitleRightLl.setVisibility(View.VISIBLE); + } + setTitleRight(resId); + } + } + + public void setTitleTextRight2(int resId) { + if (mTitleRight2Ll != null) { + if (mTitleRight2Ll.getVisibility() != View.VISIBLE) { + mTitleRight2Ll.setVisibility(View.VISIBLE); + } + setTitleRight2(resId); + } + } + + public void setTitleTextCenter(int resId) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + setTitleCenter(resId); + } + } + + public void setTitleTextCenterSub(int resId) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + setTitleCenterSub(resId); + } + } + + /*-----------------------------------------setTextById END--------------------------------------*/ + /*-----------------------------------------setTextByString START--------------------------------------*/ + public void setTitleTextLeft(String titleTextLeft) { + if (mTitleLeftTv != null) { + if (mTitleLeftTv.getVisibility() != View.VISIBLE) { + mTitleLeftTv.setVisibility(View.VISIBLE); + } + mTitleLeftTv.setText(titleTextLeft); + mTitleLeftTv.setBackgroundResource(0); + } + } + + public void setTitleTextLeft2(String titleTextLeft2) { + if (mTitleLeft2Tv != null) { + if (mTitleLeft2Tv.getVisibility() != View.VISIBLE) { + mTitleLeft2Tv.setVisibility(View.VISIBLE); + } + mTitleLeft2Tv.setText(titleTextLeft2); + mTitleLeft2Tv.setBackgroundResource(0); + } + } + + public void setTitleTextRight(String titleTextRight) { + if (mTitleRightTv != null) { + if (mTitleRightTv.getVisibility() != View.VISIBLE) { + mTitleRightTv.setVisibility(View.VISIBLE); + } + mTitleRightTv.setText(titleTextRight); + mTitleRightTv.setBackgroundResource(0); + } + } + + public void setTitleTextRight2(String titleTextRight2) { + if (mTitleRight2Tv != null) { + if (mTitleRight2Tv.getVisibility() != View.VISIBLE) { + mTitleRight2Tv.setVisibility(View.VISIBLE); + } + mTitleRight2Tv.setText(titleTextRight2); + mTitleRight2Tv.setBackgroundResource(0); + } + } + + public void setTitleTextCenter(String titleTextCenter) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + mTitleCenterTv.setText(titleTextCenter); + mTitleCenterTv.setBackgroundResource(0); + } + } + + public void setTitleTextCenterSub(String titleTextCenter) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + mTitleCenterSubTv.setText(titleTextCenter); + mTitleCenterSubTv.setBackgroundResource(0); + } + } + + /*-----------------------------------------setTextByString END--------------------------------------*/ + /*-----------------------------------------setVisible START--------------------------------------*/ + + public void setVisibleLeft(int flag) { + if (mTitleLeftLl != null) { + mTitleLeftLl.setVisibility(flag); + } + } + + public void setVisibleLeft2(int flag) { + if (mTitleLeft2Ll != null) { + mTitleLeft2Ll.setVisibility(flag); + } + } + + public void setVisibleRight(int flag) { + if (mTitleRightLl != null) { + mTitleRightLl.setVisibility(flag); + } + } + + public void setVisibleRight2(int flag) { + if (mTitleRight2Ll != null) { + mTitleRight2Ll.setVisibility(flag); + } + } + + public void setVisibleCenter(int flag) { + if (mTitleCenterLl != null) { + mTitleCenterLl.setVisibility(flag); + } + } + + public void setVisibleCenterSub(int flag) { + if (mTitleCenterSubTv != null) { + mTitleCenterSubTv.setVisibility(flag); + } + } + + public void setVisibleBottom(int flag) { + if (mBottomV != null) { + mBottomV.setVisibility(flag); + } + } + + /*-----------------------------------------setVisible END--------------------------------------*/ + public void setOnTitleSubClickListener(OnTitleSubClickListener listener) { + mListener = listener; + } + + public interface OnTitleSubClickListener { + public void onCommonTitleClick(int id); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSwitchTitle.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSwitchTitle.java new file mode 100644 index 0000000..a48752f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonSwitchTitle.java @@ -0,0 +1,485 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; + + +/** + *

+ * xml使用注意:需要在xml文件中使用style="@style/common_switch_titile" + *

+ *

+ * 函数使用介绍: + *

+ *

+ * initView(int left, int right, int midleft, int midright) 初始化控件:左按钮,中间左按钮,中间右按钮,右按钮,属于普通用法 + *

+ */ +public class CommonSwitchTitle extends RelativeLayout { + + /** + * 左侧按钮ID + */ + public static final int ID_LEFT = 0; + + /** + * 右侧按钮ID + */ + public static final int ID_MID_LEFT = 1; + + /** + * 左侧按钮ID + */ + public static final int ID_MID_RIGHT = 2; + + /** + * 左侧按钮ID + */ + public static final int ID_RIGHT = 3; + + /** + * 左侧按钮 + */ + private TextView mTitleLeftTv; + + private LinearLayout mTitleLeftLl; + + /** + * 右侧按钮 + */ + private TextView mTitleRightTv; + + private LinearLayout mTitleRightLl; + + /** + * 文字标题(左) + */ + private TextView mMidLeftTv; + + /** + * 文字标题(右) + */ + private TextView mMidRightTv; + + /** + * 点击监听 + */ + private OnTitleClickListener mListener; + /** + * 底部横线 + */ + private View mBottomV; + /** + * tab切换区域 + */ + private ViewGroup mSwitchBtnLl; + /** + * 标题 + */ + private TextView mTitleTv; + + /** + * 记录中间的左右是文字还是图片,主要兼容国内外差异 + */ + private boolean mIsMidLeftDrawable; + + public CommonSwitchTitle(Context context, AttributeSet attrs) { + super(context, attrs); + + LayoutInflater.from(context).inflate(R.layout.mobile_common_widget_switch_title, this); + initView(); + setListeners(); + } + + private void initView() { + mTitleLeftLl = findViewById(R.id.ll_title_left); + mTitleRightLl = findViewById(R.id.ll_title_right); + mTitleLeftTv = findViewById(R.id.tv_title_left); + mTitleRightTv = findViewById(R.id.tv_title_right); + mMidLeftTv = findViewById(R.id.tag_left); + mMidRightTv = findViewById(R.id.tag_right); + mBottomV = findViewById(R.id.bottom_divider); + mTitleLeftTv.setTextColor(getResources().getColor(R.color.c0)); + mTitleRightTv.setTextColor(getResources().getColor(R.color.c0)); + mMidLeftTv.setTextColor(getResources().getColor(R.color.common_title_tab_text_color)); + mMidRightTv.setTextColor(getResources().getColor(R.color.common_title_tab_text_color)); + + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources() + .getDimensionPixelSize(R.dimen.mobile_common_text_size_mid)); + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.mobile_common_text_size_mid)); + mMidLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.text_size_mid)); + mMidRightTv + .setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.text_size_mid)); + mSwitchBtnLl = findViewById(R.id.ll_switch_btn); + mTitleTv = findViewById(R.id.tv_title_center); + } + + + public void setSelect(boolean isRight) { + mSwitchBtnLl.setSelected(isRight); + mMidLeftTv.setTextColor(isRight ? getResources().getColor(R.color.c5) : getResources().getColor(R.color.c0)); + mMidRightTv.setTextColor(isRight?getResources().getColor(R.color.c0) : getResources().getColor(R.color.c5)); + } + + /** + * 切换标题栏展示样式 + * + * @param isSwitchMode + */ + public void changeTitleMode(boolean isSwitchMode) { + if (isSwitchMode) { + mSwitchBtnLl.setVisibility(VISIBLE); + mTitleTv.setVisibility(GONE); + } else { + mSwitchBtnLl.setVisibility(GONE); + mTitleTv.setVisibility(VISIBLE); + } + } + + /** + * 设置标题栏中间内容 + * + * @param resId + */ + public void setTitleCenter(int resId) { + mTitleTv.setText(getResources().getString(resId)); + } + + + private void setListeners() { + mTitleLeftLl.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_LEFT); + + } + }); + mTitleRightLl.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_RIGHT); + } + }); + mMidLeftTv.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (mIsMidLeftDrawable){ + UIUtils.setEnabled(false, v); + UIUtils.setEnabled(true, mMidRightTv); + }else{ + mSwitchBtnLl.setSelected(false); + } + + if (mListener != null) + mListener.onCommonTitleClick(ID_MID_LEFT); + } + }); + mMidRightTv.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (mIsMidLeftDrawable){ + UIUtils.setEnabled(false, v); + UIUtils.setEnabled(true, mMidLeftTv); + }else{ + mSwitchBtnLl.setSelected(true); + } + + if (mListener != null) + mListener.onCommonTitleClick(ID_MID_RIGHT); + } + }); + + } + + /** + * 初始化 + * + * @param left + * @param right + * @param midLeft + * @param midRight + */ + public void initView(int left, int right, int midLeft, int midRight) { + setTitleLeftView(left, 0, 0); + setTitleRightView(right, 0, 0); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(midLeft); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mIsMidLeftDrawable = true; + setMidLeftImageSrc(midLeft); + } else { + mIsMidLeftDrawable = false; + setMidLeftText(midLeft); + } + } + try { + drawable = getResources().getDrawable(midRight); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + setMidRightImageSrc(midRight); + } else { + setMidRightText(midRight); + } + } + } + + /*-----------------------------------setTitleXXXView setMidXXXView START---------------------------------*/ + public void setTitleLeftView(int resId, int colorId, int textSizeDimenId) { + setTitleLeft(resId); + setTextColorLeft(colorId); + setTextSizeLeft(textSizeDimenId); + } + + public void setTitleRightView(int resId, int colorId, int textSizeDimenId) { + setTitleRight(resId); + setTextColorRight(colorId); + setTextSizeRight(textSizeDimenId); + } + + + /*-----------------------------------setTitleXXXView setMidXXXView END---------------------------------*/ + /*------------------------------------------setTitle START------------------------------*/ + public void setTitleLeft(int leftResId) { + if (mTitleLeftTv != null) { + if (leftResId != 0) { + if (mTitleLeftLl != null && mTitleLeftLl.getVisibility() != View.VISIBLE) + mTitleLeftLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(leftResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleLeftTv.setBackgroundResource(leftResId); + mTitleLeftTv.setText(null); + } else { + mTitleLeftTv.setText(leftResId); + mTitleLeftTv.setBackgroundResource(0); + } + } + } else { + if (mTitleLeftLl != null) + mTitleLeftLl.setVisibility(INVISIBLE); + } + } + } + + public void setTitleRight(int rightResId) { + if (mTitleRightTv != null) { + if (rightResId != 0) { + if (mTitleRightLl != null && mTitleRightLl.getVisibility() != View.VISIBLE) + mTitleRightLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(rightResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleRightTv.setBackgroundResource(rightResId); + mTitleRightTv.setText(null); + } else { + mTitleRightTv.setText(rightResId); + mTitleRightTv.setBackgroundResource(0); + } + } + } else { + if (mTitleRightLl != null) + mTitleRightLl.setVisibility(INVISIBLE); + } + } + } + + public void setMidLeftText(@StringRes int midLeftResId) { + if (mMidLeftTv != null) { + if (midLeftResId != 0) { + if (mMidLeftTv.getVisibility() != View.VISIBLE) { + mMidLeftTv.setVisibility(View.VISIBLE); + } + mMidLeftTv.setText(midLeftResId); + } else { + mMidLeftTv.setVisibility(INVISIBLE); + } + } + } + + public void setMidLeftImageSrc(@DrawableRes int midLeftResId) { + if (mMidLeftTv != null) { + if (midLeftResId != 0) { + if (mMidLeftTv.getVisibility() != View.VISIBLE) { + mMidLeftTv.setVisibility(View.VISIBLE); + } + mMidLeftTv.setBackgroundResource(midLeftResId); + } else { + mMidLeftTv.setVisibility(INVISIBLE); + } + } + } + + public void setMidRightText(@StringRes int midRightResId) { + if (mMidRightTv != null) { + if (midRightResId != 0) { + if (mMidRightTv.getVisibility() != View.VISIBLE) { + mMidRightTv.setVisibility(View.VISIBLE); + } + mMidRightTv.setText(midRightResId); + } else { + mMidRightTv.setVisibility(INVISIBLE); + } + } + } + + public void setMidRightImageSrc(@DrawableRes int midRightResId) { + if (mMidRightTv != null) { + if (midRightResId != 0) { + if (mMidRightTv.getVisibility() != View.VISIBLE) { + mMidRightTv.setVisibility(View.VISIBLE); + } + mMidRightTv.setBackgroundResource(midRightResId); + } else { + mMidRightTv.setVisibility(INVISIBLE); + } + } + } + + /*-----------------------------------------setTextColor START--------------------------------------*/ + public void setTextColorLeft(int colorResId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextColor(colorResId != 0 ? getResources().getColor(colorResId) : getResources().getColor( + R.color.c0)); + } + } + + public void setTextColorRight(int colorResId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextColor(colorResId != 0 ? getResources().getColor(colorResId) : getResources().getColor( + R.color.c0)); + } + } + + + /*-----------------------------------------setTextColor END--------------------------------------*/ + /*-----------------------------------------setTextSize START--------------------------------------*/ + public void setTextSizeLeft(int textSizeDimenId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_text_size_mid)); + } + } + + public void setTextSizeRight(int textSizeDimenId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_text_size_mid)); + } + } + + + /*-----------------------------------------setTextSize END--------------------------------------*/ + /*-----------------------------------------setIcon START--------------------------------------*/ + + public void setIconLeft(int resId) { + if (mTitleLeftLl != null) { + if (mTitleLeftLl.getVisibility() != View.VISIBLE) { + mTitleLeftLl.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setIconRight(int resId) { + if (mTitleRightLl != null) { + if (mTitleRightLl.getVisibility() != View.VISIBLE) { + mTitleRightLl.setVisibility(View.VISIBLE); + } + setTitleRight(resId); + } + } + + + public void setVisibleBottomDivider(int flag) { + if (mBottomV != null) { + mBottomV.setVisibility(flag); + } + } + + + public void setEnabled(boolean enabled, int id) { + View parent = findParentViewById(id); + if (parent != null) { + + View v = findViewByID(id); + if (v != null) { + + parent.setEnabled(enabled); + v.setEnabled(enabled); + } + } + } + + + private View findParentViewById(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftLl; + + case ID_RIGHT: + return mTitleRightLl; + + default: + return null; + } + } + + public View findViewByID(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftTv; + case ID_RIGHT: + return mTitleRightTv; + case ID_MID_LEFT: + return mMidLeftTv; + case ID_MID_RIGHT: + return mMidRightTv; + default: + return null; + } + } + + public void setOnTitleClickListener(OnTitleClickListener listener) { + mListener = listener; + } + + public interface OnTitleClickListener { + void onCommonTitleClick(int id); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonTitle.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonTitle.java new file mode 100644 index 0000000..3ead001 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CommonTitle.java @@ -0,0 +1,841 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; + + +/** + *

+ * 工具类使用说明:左按钮,左内按钮,中间按钮,右内按钮,右按钮,均支持图片和文字背景二选一,左右按钮默认支持图片,中间按钮默认支持文字 + *

+ *

+ * xml使用注意:需要在xml文件中使用style="@style/common_titile" + *

+ *

+ * 函数使用介绍: + *

+ *

+ * initView(int tvLeftResId, int tvRightResId, int tvCenterResId) 初始化控件:左按钮,中间按钮,右按钮,属于普通用法 + *

+ *

+ * getTextViewXXX() 获取xxx按钮,进行自定义功能扩展操作。例如,实现展开下来listview的功能 + *

+ *

+ * setTitleXXXView(int resId, int colorId, int textSizeDimenId) 设置xxx按钮的文字,文字颜色,文字大小 + *

+ *

+ * setTitleXXX(int resId) 设置xxx按钮图片或文字 + *

+ *

+ * setTextColorXXX(int colorId) 设置xxx按钮文字的颜色资源 + *

+ *

+ * setTextSizeXXX(int textSizeDimenId) 设置xxx按钮文字的大小 + *

+ *

+ * setTitleTextXXX(int resId) 通过resId设置xxx按钮的文字 + *

+ *

+ * setTitleTextXXX(String titleTextXXX) 通过String设置xxx按钮的文字 + *

+ *

+ * setVisibleXXX(int flag) 通过flag设置xxx是否隐藏,flag:View.GONE,View.INVISIBLE,View.VISIBLE; + *

+ */ +public class CommonTitle extends RelativeLayout +// implements OnClickListener +{ + /** + * 左侧按钮ID + */ + public static final int ID_LEFT = 0; + + /** + * 左侧内按钮ID + */ + public static final int ID_LEFT_2 = 1; + + /** + * 右侧按钮ID + */ + public static final int ID_RIGHT = 2; + + /** + * 右侧内按钮ID + */ + public static final int ID_RIGHT_2 = 3; + + /** + * 中间按钮ID, 暂时不加监听器 + */ + public static final int ID_CENTER = 4; + + /** + * 左侧按钮/ 左侧按钮LinearLayout + */ + private TextView mTitleLeftTv; + + private LinearLayout mTitleLeftLl; + + /** + * 左侧按钮(靠内) /左侧按钮(靠内)LinearLayout + */ + private TextView mTitleLeft2Tv; + + private LinearLayout mTitleLeft2Ll; + + /** + * 右侧按钮 /右侧按钮LinearLayout + */ + private TextView mTitleRightTv; + + private LinearLayout mTitleRightLl; + + /** + * 右侧按钮(靠内) /右侧按钮(靠内)LinearLayout + */ + private TextView mTitleRight2Tv; + + private LinearLayout mTitleRight2Ll; + + /** + * 文字标题/文字标题LinearLayout + */ + private TextView mTitleCenterTv; + + private LinearLayout mTitleCenterLl; + + /** + * 点击监听 + */ + private OnTitleClickListener mListener; + + private View mBottomV; + private boolean mIsSupportChangeCenterWidth =false; + /** + * 默认隐藏左2和右2的按钮 ,创建一个新的实例CommonTitle. + * + * @param context + * @param attrs + */ + public CommonTitle(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(context).inflate(R.layout.mobile_common_widget_common_title, this); + initView(); + setListeners(); + setVisibleLeft2(View.GONE); + setVisibleRight2(View.GONE); + } + + private void initView() { + mBottomV = findViewById(R.id.v_bottom_line); + mTitleLeftLl = findViewById(R.id.ll_title_left); + mTitleLeft2Ll = findViewById(R.id.ll_title_left2); + mTitleRightLl = findViewById(R.id.ll_title_right); + mTitleRight2Ll = findViewById(R.id.ll_title_right2); + mTitleCenterLl = findViewById(R.id.ll_title_center); + + mTitleLeftTv = findViewById(R.id.tv_title_left); + mTitleLeft2Tv = findViewById(R.id.tv_title_left2); + mTitleRightTv = findViewById(R.id.tv_title_right); + mTitleRight2Tv = findViewById(R.id.tv_title_right2); + mTitleCenterTv = findViewById(R.id.tv_title_center); + + mTitleLeftTv.setTextColor(getResources().getColor(R.color.c43)); + mTitleLeft2Tv.setTextColor(getResources().getColor(R.color.c43)); + mTitleRightTv.setTextColor(getResources().getColor(R.color.c43)); + mTitleRight2Tv.setTextColor(getResources().getColor(R.color.c43)); + mTitleCenterTv.setTextColor(getResources().getColor(R.color.c2)); + + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + mTitleLeft2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + mTitleRight2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + mTitleCenterTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getResources().getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_large)); + + //横屏时不显示,只支持竖屏下的宽度设置。 //初始化时,写死中间标题的宽度 + DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); + int commonTitleWidth = dm.widthPixels; + if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){ + commonTitleWidth = dm.widthPixels; + }else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){ + commonTitleWidth = dm.heightPixels; + } + + int centerTitleWidth = commonTitleWidth - 4 * dp2px(dm, 48);// 减去4个按钮的占用空间 + + mTitleCenterTv.setWidth(centerTitleWidth); + } + + private int dp2px(DisplayMetrics dm , float dp){ + final float scale = dm.density; + return (int) (dp * scale + 0.5f); + } + + private void setListeners() { + mTitleLeftLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_LEFT); + } + + } + }); + + mTitleLeft2Ll.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_LEFT_2); + } + + } + }); + + mTitleRightLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onCommonTitleClick(ID_RIGHT); + } + + } + }); + + mTitleRight2Ll.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_RIGHT_2); + } + }); + + mTitleCenterLl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) + mListener.onCommonTitleClick(ID_CENTER); + } + }); + } + + /** + *

+ * 初始化参数,按钮均可支持图片或者文字背景 + *

+ * @param tvLeftResId + * 左按钮 + * @param tvRightResId + * 右按钮 + * @param tvCenterResId + * 中间按钮 + */ + + public void initView(int tvLeftResId, int tvRightResId, int tvCenterResId) { + setTitleLeftView(tvLeftResId, 0, 0); + setTitleRightView(tvRightResId, 0, 0); + setTitleCenterView(tvCenterResId, 0, 0); + } + + public TextView getTextViewRight() { + return mTitleRightTv; + } + + // + public TextView getTextViewRight2() { + return mTitleRight2Tv; + } + // + public TextView getTextViewCenter() { + return mTitleCenterTv; + } + + /** + *

+ * 设置是否选中按钮 + *

+ * @param selected + * {true,false} + * @param id + * {ID_LEFT ,ID_LEFT_2,ID_RIGHT,ID_RIGHT_2,ID_CENTER} + */ + public void setTitleSelected(boolean selected, int id) { + View v = findViewByID(id); + if (v != null) { + v.setSelected(selected); + } + } + + /** + *

+ * 设置按钮是否可用 + *

+ */ + + + public void setEnabled(boolean enabled, int id) { + View parent = findParentViewById(id); + if (parent != null) { + + View v = findViewByID(id); + if (v != null) { + + parent.setEnabled(enabled); + v.setEnabled(enabled); + } + } + + } + + public boolean isEnable(int id){ + View parent = findParentViewById(id); + if (parent != null) { + + View v = findViewByID(id); + if (v != null) { + return v.isEnabled(); + } + } + + return false; + } + + private View findParentViewById(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftLl; + case ID_LEFT_2: + return mTitleLeft2Ll; + case ID_RIGHT: + return mTitleRightLl; + case ID_RIGHT_2: + return mTitleRight2Ll; + case ID_CENTER: + return mTitleCenterLl; + default: + return null; + } + } + + private View findViewByID(int id) { + switch (id) { + case ID_LEFT: + return mTitleLeftTv; + case ID_LEFT_2: + return mTitleLeft2Tv; + case ID_RIGHT: + return mTitleRightTv; + case ID_RIGHT_2: + return mTitleRight2Tv; + case ID_CENTER: + return mTitleCenterTv; + default: + return null; + } + } + + /*------------------------------------------getTextView END------------------------------*/ + + /*-----------------------------------setTitleView START---------------------------------*/ + public void setTitleLeftView(int resId, int colorId, int textSizeDimenId) { + setTitleLeft(resId); + setTextColorLeft(colorId); + setTextSizeLeft(textSizeDimenId); + } + + public void setTitleRightView(int resId, int colorId, int textSizeDimenId) { + setTitleRight(resId); + setTextColorRight(colorId); + setTextSizeRight(textSizeDimenId); + } + + public void setTitleCenterView(int resId, int colorId, int textSizeDimenId) { + setTitleCenter(resId); + setTextColorCenter(colorId); + setTextSizeCenter(textSizeDimenId); + } + + /*-----------------------------------setTitleView END---------------------------------*/ + /*------------------------------------------setTitle START------------------------------*/ + /** + *

+ * 设置左边按钮图片或文字 + *

+ * @param leftResId + */ + public void setTitleLeft(int leftResId) { + if (mTitleLeftTv != null) { + if (leftResId != 0) { + if (mTitleLeftLl != null && mTitleLeftLl.getVisibility() != View.VISIBLE) + mTitleLeftLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(leftResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleLeftTv.setBackgroundResource(leftResId); + mTitleLeftTv.setText(null); + } else { + mTitleLeftTv.setText(leftResId); + mTitleLeftTv.setBackgroundResource(0); + } + } + } else { + if (mTitleLeftLl != null) + mTitleLeftLl.setVisibility(GONE); + } + } + } + + /** + *

+ * 设置左边按钮图片或文字 + *

+ * @param left2ResId + */ + public void setTitleLeft2(int left2ResId) { + if (mTitleLeft2Tv != null) { + if (left2ResId != 0) { + if (mTitleLeft2Ll != null && mTitleLeft2Ll.getVisibility() != View.VISIBLE) + mTitleLeft2Ll.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(left2ResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleLeft2Tv.setBackgroundResource(left2ResId); + mTitleLeft2Tv.setText(null); + } else { + mTitleLeft2Tv.setText(left2ResId); + mTitleLeft2Tv.setBackgroundResource(0); + } + } + } else { + if (mTitleLeft2Ll != null) + mTitleLeft2Ll.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置右边按钮图片或文字 + *

+ * @param rightResId + */ + public void setTitleRight(int rightResId) { + if (mTitleRightTv != null) { + if (rightResId != 0) { + if (mTitleRightLl != null && mTitleRightLl.getVisibility() != View.VISIBLE) + mTitleRightLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(rightResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleRightTv.setBackgroundResource(rightResId); + mTitleRightTv.setText(null); + } else { + mTitleRightTv.setText(rightResId); + mTitleRightTv.setBackgroundResource(0); + } + + } + } else { + if (mTitleRightLl != null) + mTitleRightLl.setVisibility(INVISIBLE); + } + } + } + + public void setTitleRight2(int right2ResId) { + if (mTitleRight2Tv != null) { + if (right2ResId != 0) { + if (mTitleRight2Ll != null && mTitleRight2Ll.getVisibility() != View.VISIBLE) + mTitleRight2Ll.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(right2ResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleRight2Tv.setBackgroundResource(right2ResId); + mTitleRight2Tv.setText(null); + } else { + mTitleRight2Tv.setText(right2ResId); + mTitleRight2Tv.setBackgroundResource(0); + } + } + } else { + if (mTitleRight2Ll != null) + mTitleRight2Ll.setVisibility(INVISIBLE); + } + } + } + + /** + *

+ * 设置中间按钮图片或文字 + *

+ * @param centerResId + */ + public void setTitleCenter(int centerResId) { + if (mTitleCenterTv != null) { + if (centerResId != 0) { + if (mTitleCenterLl != null && mTitleCenterLl.getVisibility() != View.VISIBLE) + mTitleCenterLl.setVisibility(VISIBLE); + Drawable drawable = null; + try { + drawable = getResources().getDrawable(centerResId); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (drawable != null) { + mTitleCenterTv.setBackgroundResource(centerResId); + mTitleCenterTv.setText(null); + } else { + mTitleCenterTv.setText(centerResId); + mTitleCenterTv.setBackgroundResource(0); + setTitleCenterWidth(); + } + } + } else { + if (mTitleCenterLl != null) + mTitleCenterLl.setVisibility(INVISIBLE); + } + } + } + + /*------------------------------------------setTitle END------------------------------*/ + /*-----------------------------------------setTextColor START--------------------------------------*/ + public void setTextColorLeft(int colorId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c50)); + } + } + + public void setTextColorLeft2(int colorId) { + if (mTitleLeft2Tv != null) { + mTitleLeft2Tv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c50)); + } + } + + public void setTextColorRight(int colorId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextColor(colorId != 0 ? getResources().getColorStateList(colorId) : getResources() + .getColorStateList(R.color.mobile_common_title_text_color_selector)); + } + } + + public void setTextColorRight2(int colorId) { + if (mTitleRight2Tv != null) { + mTitleRight2Tv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c43)); + } + } + + public void setTextColorCenter(int colorId) { + if (mTitleCenterTv != null) { + mTitleCenterTv.setTextColor(colorId != 0 ? getResources().getColor(colorId) : getResources().getColor( + R.color.c2)); + } + } + + /*-----------------------------------------setTextColor END--------------------------------------*/ + /*-----------------------------------------setTextSize START--------------------------------------*/ + public void setTextSizeLeft(int textSizeDimenId) { + if (mTitleLeftTv != null) { + mTitleLeftTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + } + } + + public void setTextSizeLeft2(int textSizeDimenId) { + if (mTitleLeft2Tv != null) { + mTitleLeft2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + } + } + + public void setTextSizeRight(int textSizeDimenId) { + if (mTitleRightTv != null) { + mTitleRightTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + } + } + + public void setTextSizeRight2(int textSizeDimenId) { + if (mTitleRight2Tv != null) { + mTitleRight2Tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_mid)); + } + } + + public void setTextSizeCenter(int textSizeDimenId) { + if (mTitleCenterTv != null) { + mTitleCenterTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, + textSizeDimenId != 0 ? getResources().getDimensionPixelSize(textSizeDimenId) : getResources() + .getDimensionPixelSize(R.dimen.mobile_common_common_title_text_size_large)); + } + } + + /*-----------------------------------------setTextSize END--------------------------------------*/ + + /*-----------------------------------------setIcon START--------------------------------------*/ + + public void setIconLeft(int resId) { + if (mTitleLeftLl != null) { + if (mTitleLeftLl.getVisibility() != View.VISIBLE) { + mTitleLeftLl.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setIconLeft2(int resId) { + if (mTitleLeft2Ll != null) { + if (mTitleLeft2Ll.getVisibility() != View.VISIBLE) { + mTitleLeft2Ll.setVisibility(View.VISIBLE); + } + setTitleLeft2(resId); + } + } + + public void setIconRight(int resId) { + if (mTitleRightLl != null) { + if (mTitleRightLl.getVisibility() != View.VISIBLE) { + mTitleRightLl.setVisibility(View.VISIBLE); + } + setTitleRight(resId); + } + } + + public void setIconRight2(int resId) { + if (mTitleRight2Ll != null) { + if (mTitleRight2Ll.getVisibility() != View.VISIBLE) { + mTitleRight2Ll.setVisibility(View.VISIBLE); + } + setTitleRight2(resId); + } + } + + public void setIconCenter(int resId) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + setTitleCenter(resId); + } + } + + /*-----------------------------------------setIcon END--------------------------------------*/ + /*-----------------------------------------setTextById START--------------------------------------*/ + + public void setTitleTextLeft(int resId) { + if (mTitleLeftLl != null) { + if (mTitleLeftLl.getVisibility() != View.VISIBLE) { + mTitleLeftLl.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setTitleTextLeft2(int resId) { + if (mTitleLeft2Ll != null) { + if (mTitleLeft2Ll.getVisibility() != View.VISIBLE) { + mTitleLeft2Ll.setVisibility(View.VISIBLE); + } + setTitleLeft(resId); + } + } + + public void setTitleTextRight(int resId) { + if (mTitleRightLl != null) { + if (mTitleRightLl.getVisibility() != View.VISIBLE) { + mTitleRightLl.setVisibility(View.VISIBLE); + } + setTitleRight(resId); + } + } + + public void setTitleTextRight2(int resId) { + if (mTitleRight2Ll != null) { + if (mTitleRight2Ll.getVisibility() != View.VISIBLE) { + mTitleRight2Ll.setVisibility(View.VISIBLE); + } + setTitleRight2(resId); + } + } + + public void setTitleTextCenter(int resId) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + setTitleCenter(resId); + } + } + + /*-----------------------------------------setTextById END--------------------------------------*/ + /*-----------------------------------------setTextByString START--------------------------------------*/ + public void setTitleTextLeft(String titleTextLeft) { + if (mTitleLeftTv != null) { + if (mTitleLeftTv.getVisibility() != View.VISIBLE) { + mTitleLeftTv.setVisibility(View.VISIBLE); + } + mTitleLeftTv.setText(titleTextLeft); + mTitleLeftTv.setBackgroundResource(0); + } + } + + public void setTitleTextLeft2(String titleTextLeft2) { + if (mTitleLeft2Tv != null) { + if (mTitleLeft2Tv.getVisibility() != View.VISIBLE) { + mTitleLeft2Tv.setVisibility(View.VISIBLE); + } + mTitleLeft2Tv.setText(titleTextLeft2); + mTitleLeft2Tv.setBackgroundResource(0); + } + } + + public void setTitleTextRight(String titleTextRight) { + if (mTitleRightTv != null) { + if (mTitleRightTv.getVisibility() != View.VISIBLE) { + mTitleRightTv.setVisibility(View.VISIBLE); + } + mTitleRightTv.setText(titleTextRight); + mTitleRightTv.setBackgroundResource(0); + } + } + + public void setTitleTextRight2(String titleTextRight2) { + if (mTitleRight2Tv != null) { + if (mTitleRight2Tv.getVisibility() != View.VISIBLE) { + mTitleRight2Tv.setVisibility(View.VISIBLE); + } + mTitleRight2Tv.setText(titleTextRight2); + mTitleRight2Tv.setBackgroundResource(0); + } + } + + public void setTitleTextCenter(String titleTextCenter) { + if (mTitleCenterLl != null) { + if (mTitleCenterLl.getVisibility() != View.VISIBLE) { + mTitleCenterLl.setVisibility(View.VISIBLE); + } + mTitleCenterTv.setText(titleTextCenter); + mTitleCenterTv.setBackgroundResource(0); + setTitleCenterWidth(); + } + } + /** + * + *

+ * 为了支持显示网页回调中标题字数过多的问题,增加动态修改中间的宽度功能 + * 只支持web修改标题宽度 + *

+ * @param isSupportChangeCenterWidth + */ + public void setChangeCenterWidthForWebView(boolean isSupportChangeCenterWidth){ + mIsSupportChangeCenterWidth = isSupportChangeCenterWidth; + } + + @Deprecated + private void setTitleCenterWidth(){ + + } + /*-----------------------------------------setTextByString END--------------------------------------*/ + /*-----------------------------------------setVisible START--------------------------------------*/ + + public void setVisibleLeft(int flag) { + if (mTitleLeftLl != null) { + mTitleLeftLl.setVisibility(flag); + } + } + + public void setVisibleLeft2(int flag) { + if (mTitleLeft2Ll != null) { + mTitleLeft2Ll.setVisibility(flag); + } + } + + public void setVisibleRight(int flag) { + if (mTitleRightLl != null) { + mTitleRightLl.setVisibility(flag); + } + } + + public void setEnableRight(boolean enable) { + if (mTitleRightLl != null) { + mTitleRightLl.setEnabled(enable); + } + } + + public boolean getEnableRight() { + return mTitleRightLl.isEnabled(); + } + + public void setVisibleRight2(int flag) { + if (mTitleRight2Ll != null) { + mTitleRight2Ll.setVisibility(flag); + } + } + + public void setVisibleCenter(int flag) { + if (mTitleCenterLl != null) { + mTitleCenterLl.setVisibility(flag); + } + } + + public void setVisibleBottom(int flag) { + if (mBottomV != null) { + mBottomV.setVisibility(flag); + } + } + + public boolean isIconLeftVisible(){ + if (mTitleLeftLl != null) { + return mTitleLeftLl.getVisibility() == VISIBLE; + } + return false; + } + + /*-----------------------------------------setVisible END--------------------------------------*/ + public void setOnTitleClickListener(OnTitleClickListener listener) { + mListener = listener; + } + + public interface OnTitleClickListener { + public void onCommonTitleClick(int id); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CustomSearchView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CustomSearchView.java new file mode 100644 index 0000000..1fc5b4e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/CustomSearchView.java @@ -0,0 +1,158 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +/** + * 通用搜索框 + */ + +public class CustomSearchView extends RelativeLayout implements View.OnClickListener, + ClearEditText.IFocusChangeListener, ClearEditText.ITextChangeListener, + TextView.OnEditorActionListener { + private ClearEditText mSearchInput; + private TextView mCancelTv; + private InputMethodManager mInputMethodManager; + private IOnTextChangeListener mTextChangeListener; + private IOnFocusChangeListener mFocusChangeListener; + + public CustomSearchView(Context context) { + this(context, null); + } + + public CustomSearchView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public interface IOnFocusChangeListener { + void onSearchFocusChange(View v, boolean hasFocus); + } + + public void setOnSearchFocusChangeListener(IOnFocusChangeListener listener) { + mFocusChangeListener = listener; + } + + public interface IOnTextChangeListener { + void onTextChange(View v, CharSequence ch); + } + + public void setOnTextChangedListener(IOnTextChangeListener listener) { + mTextChangeListener = listener; + } + + public CustomSearchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + LayoutInflater.from(context).inflate(R.layout.mobile_common_search_view, this); + initView(); + initData(); + } + + private void initView() { + mSearchInput = findViewById(R.id.common_search_input); + mCancelTv = findViewById(R.id.common_search_cancel); + + mCancelTv.setOnClickListener(this); + mSearchInput.setTextChangeListener(this); + mSearchInput.setOnClickListener(this); + mSearchInput.setClearTextFocusChange(this); + mSearchInput.setOnEditorActionListener(this); + } + + private void initData() { + mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + } + + @Override + public void onClick(View view) { + int id = view.getId(); + if (id == R.id.common_search_cancel) { + mSearchInput.clearFocus(); + } else if (id == R.id.common_search_input) { + mSearchInput.requestFocus(); + } + } + + @Override + public void onClearTextFocusChange(View v, boolean hasFocus) { + LogUtil.debugLog("33084", " onClearTextFocusChange hasFocus = " + hasFocus); + if (hasFocus) { + mCancelTv.setVisibility(View.VISIBLE); + } else { + mCancelTv.setVisibility(View.GONE); + mSearchInput.setText(""); + mInputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + + if (mFocusChangeListener != null) { + mFocusChangeListener.onSearchFocusChange(v, hasFocus); + } + } + + @Override + public void afterChanged(EditText v, Editable s) { + + } + + @Override + public void beforeChanged(EditText v, CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(EditText v, CharSequence text, int start, int lengthBefore, int lengthAfter) { + LogUtil.debugLog("33084", " onTextChanged"); + if (mTextChangeListener != null) { + mTextChangeListener.onTextChange(v, text); + } + } + + @Override + public boolean onEditorAction(TextView tv, int actionId, KeyEvent keyEvent) { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + if (mInputMethodManager != null) { + mInputMethodManager.hideSoftInputFromWindow(tv.getWindowToken(), 0); + } + return true; + } + return false; + } + + /** + * 设置提示语 + * + * @param resId + */ + public void setSearchTextHint(int resId) { + mSearchInput.setHint(getResources().getString(resId)); + } + + /** + * 获取输入框内容 + */ + public String getEditText() { + return mSearchInput.getText().toString(); + } + + private void onDestroyView() { + if (mInputMethodManager != null) { + mInputMethodManager = null; + } + if (mTextChangeListener != null) { + mTextChangeListener = null; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawableTextView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawableTextView.java new file mode 100644 index 0000000..0f3d93c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawableTextView.java @@ -0,0 +1,42 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.util.AttributeSet; + +public class DrawableTextView extends android.support.v7.widget.AppCompatTextView { + Rect mRect = new Rect(); + public DrawableTextView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + + @Override + protected void onDraw(Canvas canvas) { + + Drawable[] drawables = getCompoundDrawables(); + if(drawables != null){ + Drawable drawable = drawables[0]; + if(drawable != null){ + float textwidth = getPaint().measureText(getText().toString()); + int drawablePadding = getCompoundDrawablePadding(); + int drawableWidth = drawable.getIntrinsicWidth(); + float bodyWidth = textwidth + drawablePadding + drawableWidth; + canvas.translate((getWidth() - bodyWidth) / 2 , 0); + } else if((drawable = drawables[1]) != null){ + Rect rect = mRect; + getPaint().getTextBounds(getText().toString(), 0, getText().toString().length(), rect); + float textHeight = rect.height(); + int drawablePadding = getCompoundDrawablePadding(); + int drawableHeght = drawable.getIntrinsicHeight(); + float bodxinzaieight = textHeight + drawablePadding + drawableHeght; + canvas.translate(0, (getHeight() - bodxinzaieight) / 2); + } + } + + super.onDraw(canvas); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawerLayout.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawerLayout.java new file mode 100644 index 0000000..ab5d4cd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/DrawerLayout.java @@ -0,0 +1,2345 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.support.annotation.ColorInt; +import android.support.annotation.DrawableRes; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v4.view.AbsSavedState; +import android.support.v4.view.AccessibilityDelegateCompat; +import android.support.v4.view.GravityCompat; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; +import android.support.v4.widget.ViewDragHelper; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.WindowInsets; +import android.view.accessibility.AccessibilityEvent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; + +public class DrawerLayout extends ViewGroup { + private static final String TAG = "DrawerLayout"; + + private static final int[] THEME_ATTRS = { + android.R.attr.colorPrimaryDark + }; + + @IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING}) + @Retention(RetentionPolicy.SOURCE) + private @interface State {} + + /** + * Indicates that any drawers are in an idle, settled state. No animation is in progress. + */ + public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE; + + /** + * Indicates that a drawer is currently being dragged by the user. + */ + public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING; + + /** + * Indicates that a drawer is in the process of settling to a final position. + */ + public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING; + + @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN, + LOCK_MODE_UNDEFINED}) + @Retention(RetentionPolicy.SOURCE) + private @interface LockMode {} + + /** + * The drawer is unlocked. + */ + public static final int LOCK_MODE_UNLOCKED = 0; + + /** + * The drawer is locked closed. The user may not open it, though + * the app may open it programmatically. + */ + public static final int LOCK_MODE_LOCKED_CLOSED = 1; + + /** + * The drawer is locked open. The user may not close it, though the app + * may close it programmatically. + */ + public static final int LOCK_MODE_LOCKED_OPEN = 2; + + /** + * The drawer's lock state is reset to default. + */ + public static final int LOCK_MODE_UNDEFINED = 3; + + @IntDef(value = {Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END}, + flag = true) + @Retention(RetentionPolicy.SOURCE) + private @interface EdgeGravity {} + + + private static final int MIN_DRAWER_MARGIN = 0; // dp + private static final int DRAWER_ELEVATION = 10; //dp + + private static final int DEFAULT_SCRIM_COLOR = 0x99000000; + + /** + * Length of time to delay before peeking the drawer. + */ + private static final int PEEK_DELAY = 160; // ms + + /** + * Minimum velocity that will be detected as a fling + */ + private static final int MIN_FLING_VELOCITY = 400; // dips per second + + /** + * Experimental feature. + */ + private static final boolean ALLOW_EDGE_LOCK = false; + + private static final boolean CHILDREN_DISALLOW_INTERCEPT = true; + + private static final float TOUCH_SLOP_SENSITIVITY = 1.f; + + static final int[] LAYOUT_ATTRS = new int[] { + android.R.attr.layout_gravity + }; + + /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */ + static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19; + + /** Whether the drawer shadow comes from setting elevation on the drawer. */ + private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION = + Build.VERSION.SDK_INT >= 21; + + private final ChildAccessibilityDelegate mChildAccessibilityDelegate = + new ChildAccessibilityDelegate(); + private float mDrawerElevation; + + private int mMinDrawerMargin; + + private int mScrimColor = DEFAULT_SCRIM_COLOR; + private float mScrimOpacity; + private Paint mScrimPaint = new Paint(); + + private final ViewDragHelper mLeftDragger; + private final ViewDragHelper mRightDragger; + private final ViewDragCallback mLeftCallback; + private final ViewDragCallback mRightCallback; + private int mDrawerState; + private boolean mInLayout; + private boolean mFirstLayout = true; + + private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED; + private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED; + private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED; + private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED; + + private boolean mDisallowInterceptRequested; + private boolean mChildrenCanceledTouch; + + private @Nullable DrawerListener mListener; + private List mListeners; + + private float mInitialMotionX; + private float mInitialMotionY; + + private Drawable mStatusBarBackground; + private Drawable mShadowLeftResolved; + private Drawable mShadowRightResolved; + + private CharSequence mTitleLeft; + private CharSequence mTitleRight; + + private Object mLastInsets; + private boolean mDrawStatusBarBackground; + + /** Shadow drawables for different gravity */ + private Drawable mShadowStart = null; + private Drawable mShadowEnd = null; + private Drawable mShadowLeft = null; + private Drawable mShadowRight = null; + + private final ArrayList mNonDrawerViews; + + /** + * Listener for monitoring events about drawers. + */ + public interface DrawerListener { + /** + * Called when a drawer's position changes. + * @param drawerView The child view that was moved + * @param slideOffset The new offset of this drawer within its range, from 0-1 + */ + void onDrawerSlide(@NonNull View drawerView, float slideOffset); + + /** + * Called when a drawer has settled in a completely open state. + * The drawer is interactive at this point. + * + * @param drawerView Drawer view that is now open + */ + void onDrawerOpened(@NonNull View drawerView); + + /** + * Called when a drawer has settled in a completely closed state. + * + * @param drawerView Drawer view that is now closed + */ + void onDrawerClosed(@NonNull View drawerView); + + /** + * Called when the drawer motion state changes. The new state will + * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}. + * + * @param newState The new drawer motion state + */ + void onDrawerStateChanged(@State int newState); + } + + /** + * Stub/no-op implementations of all methods of {@link DrawerListener}. + * Override this if you only care about a few of the available callback methods. + */ + public abstract static class SimpleDrawerListener implements DrawerListener { + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + } + + @Override + public void onDrawerOpened(View drawerView) { + } + + @Override + public void onDrawerClosed(View drawerView) { + } + + @Override + public void onDrawerStateChanged(int newState) { + } + } + + public DrawerLayout(@NonNull Context context) { + this(context, null); + } + + public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); + final float density = getResources().getDisplayMetrics().density; + mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f); + final float minVel = MIN_FLING_VELOCITY * density; + + mLeftCallback = new ViewDragCallback(Gravity.LEFT); + mRightCallback = new ViewDragCallback(Gravity.RIGHT); + + mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback); + mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); + mLeftDragger.setMinVelocity(minVel); + mLeftCallback.setDragger(mLeftDragger); + + mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback); + mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT); + mRightDragger.setMinVelocity(minVel); + mRightCallback.setDragger(mRightDragger); + + // So that we can catch the back button + setFocusableInTouchMode(true); + + ViewCompat.setImportantForAccessibility(this, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + + ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate()); + setMotionEventSplittingEnabled(false); + if (ViewCompat.getFitsSystemWindows(this)) { + if (Build.VERSION.SDK_INT >= 21) { + setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @TargetApi(21) + @Override + public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) { + final DrawerLayout drawerLayout = (DrawerLayout) view; + drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0); + return insets.consumeSystemWindowInsets(); + } + }); + setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS); + try { + mStatusBarBackground = a.getDrawable(0); + } finally { + a.recycle(); + } + } else { + mStatusBarBackground = null; + } + } + + mDrawerElevation = DRAWER_ELEVATION * density; + + mNonDrawerViews = new ArrayList<>(); + } + + /** + * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the + * elevation change is only supported in API 21 and above. + * + * @param elevation The base depth position of the view, in pixels. + */ + public void setDrawerElevation(float elevation) { + mDrawerElevation = elevation; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (isDrawerView(child)) { + ViewCompat.setElevation(child, mDrawerElevation); + } + } + } + + /** + * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the + * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will + * be returned as the elevation. + * + * @return The base depth position of the view, in pixels. + */ + public float getDrawerElevation() { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + return mDrawerElevation; + } + return 0f; + } + + /** + * @hide Internal use only; called to apply window insets when configured + * with fitsSystemWindows="true" + */ + @RestrictTo(LIBRARY_GROUP) + public void setChildInsets(Object insets, boolean draw) { + mLastInsets = insets; + mDrawStatusBarBackground = draw; + setWillNotDraw(!draw && getBackground() == null); + requestLayout(); + } + + /** + * Set a simple drawable used for the left or right shadow. The drawable provided must have a + * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer + * instead of using the provided shadow drawable. + * + *

Note that for better support for both left-to-right and right-to-left layout + * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be + * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity + * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can + * auto-mirrored such that the drawable will be mirrored in RTL layout.

+ * + * @param shadowDrawable Shadow drawable to use at the edge of a drawer + * @param gravity Which drawer the shadow should apply to + */ + public void setDrawerShadow(Drawable shadowDrawable, @EdgeGravity int gravity) { + /* + * TODO Someone someday might want to set more complex drawables here. + * They're probably nuts, but we might want to consider registering callbacks, + * setting states, etc. properly. + */ + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + // No op. Drawer shadow will come from setting an elevation on the drawer. + return; + } + if ((gravity & GravityCompat.START) == GravityCompat.START) { + mShadowStart = shadowDrawable; + } else if ((gravity & GravityCompat.END) == GravityCompat.END) { + mShadowEnd = shadowDrawable; + } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) { + mShadowLeft = shadowDrawable; + } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) { + mShadowRight = shadowDrawable; + } else { + return; + } + resolveShadowDrawables(); + invalidate(); + } + + /** + * Set a simple drawable used for the left or right shadow. The drawable provided must have a + * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer + * instead of using the provided shadow drawable. + * + *

Note that for better support for both left-to-right and right-to-left layout + * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be + * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity + * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can + * auto-mirrored such that the drawable will be mirrored in RTL layout.

+ * + * @param resId Resource id of a shadow drawable to use at the edge of a drawer + * @param gravity Which drawer the shadow should apply to + */ + public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) { + setDrawerShadow(ContextCompat.getDrawable(getContext(), resId), gravity); + } + + /** + * Set a color to use for the scrim that obscures primary content while a drawer is open. + * + * @param color Color to use in 0xAARRGGBB format. + */ + public void setScrimColor(@ColorInt int color) { + mScrimColor = color; + invalidate(); + } + + /** + * Set a listener to be notified of drawer events. Note that this method is deprecated + * and you should use {@link #addDrawerListener(DrawerListener)} to add a listener and + * {@link #removeDrawerListener(DrawerListener)} to remove a registered listener. + * + * @param listener Listener to notify when drawer events occur + * @deprecated Use {@link #addDrawerListener(DrawerListener)} + * @see DrawerListener + * @see #addDrawerListener(DrawerListener) + * @see #removeDrawerListener(DrawerListener) + */ + @Deprecated + public void setDrawerListener(DrawerListener listener) { + // The logic in this method emulates what we had before support for multiple + // registered listeners. + if (mListener != null) { + removeDrawerListener(mListener); + } + if (listener != null) { + addDrawerListener(listener); + } + // Update the deprecated field so that we can remove the passed listener the next + // time we're called + mListener = listener; + } + + /** + * Adds the specified listener to the list of listeners that will be notified of drawer events. + * + * @param listener Listener to notify when drawer events occur. + * @see #removeDrawerListener(DrawerListener) + */ + public void addDrawerListener(@NonNull DrawerListener listener) { + if (listener == null) { + return; + } + if (mListeners == null) { + mListeners = new ArrayList<>(); + } + mListeners.add(listener); + } + + /** + * Removes the specified listener from the list of listeners that will be notified of drawer + * events. + * + * @param listener Listener to remove from being notified of drawer events + * @see #addDrawerListener(DrawerListener) + */ + public void removeDrawerListener(@NonNull DrawerListener listener) { + if (listener == null) { + return; + } + if (mListeners == null) { + // This can happen if this method is called before the first call to addDrawerListener + return; + } + mListeners.remove(listener); + } + + /** + * Enable or disable interaction with all drawers. + * + *

This allows the application to restrict the user's ability to open or close + * any drawer within this layout. DrawerLayout will still respond to calls to + * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking drawers open or closed will implicitly open or close + * any drawers as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + */ + public void setDrawerLockMode(@LockMode int lockMode) { + setDrawerLockMode(lockMode, Gravity.LEFT); + setDrawerLockMode(lockMode, Gravity.RIGHT); + } + + /** + * Enable or disable interaction with the given drawer. + * + *

This allows the application to restrict the user's ability to open or close + * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)}, + * {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking a drawer open or closed will implicitly open or close + * that drawer as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. + * Expresses which drawer to change the mode for. + * + * @see #LOCK_MODE_UNLOCKED + * @see #LOCK_MODE_LOCKED_CLOSED + * @see #LOCK_MODE_LOCKED_OPEN + */ + public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) { + final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity, + ViewCompat.getLayoutDirection(this)); + + switch (edgeGravity) { + case Gravity.LEFT: + mLockModeLeft = lockMode; + break; + case Gravity.RIGHT: + mLockModeRight = lockMode; + break; + case GravityCompat.START: + mLockModeStart = lockMode; + break; + case GravityCompat.END: + mLockModeEnd = lockMode; + break; + } + + if (lockMode != LOCK_MODE_UNLOCKED) { + // Cancel interaction in progress + final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger; + helper.cancel(); + } + switch (lockMode) { + case LOCK_MODE_LOCKED_OPEN: + final View toOpen = findDrawerWithGravity(absGravity); + if (toOpen != null) { + openDrawer(toOpen); + } + break; + case LOCK_MODE_LOCKED_CLOSED: + final View toClose = findDrawerWithGravity(absGravity); + if (toClose != null) { + closeDrawer(toClose); + } + break; + // default: do nothing + } + } + + /** + * Enable or disable interaction with the given drawer. + * + *

This allows the application to restrict the user's ability to open or close + * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)}, + * {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking a drawer open or closed will implicitly open or close + * that drawer as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + * @param drawerView The drawer view to change the lock mode for + * + * @see #LOCK_MODE_UNLOCKED + * @see #LOCK_MODE_LOCKED_CLOSED + * @see #LOCK_MODE_LOCKED_OPEN + */ + public void setDrawerLockMode(@LockMode int lockMode, @NonNull View drawerView) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a " + + "drawer with appropriate layout_gravity"); + } + final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity; + setDrawerLockMode(lockMode, gravity); + } + + /** + * Check the lock mode of the drawer with the given gravity. + * + * @param edgeGravity Gravity of the drawer to check + * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or + * {@link #LOCK_MODE_LOCKED_OPEN}. + */ + @LockMode + public int getDrawerLockMode(@EdgeGravity int edgeGravity) { + int layoutDirection = ViewCompat.getLayoutDirection(this); + + switch (edgeGravity) { + case Gravity.LEFT: + if (mLockModeLeft != LOCK_MODE_UNDEFINED) { + return mLockModeLeft; + } + int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) + ? mLockModeStart : mLockModeEnd; + if (leftLockMode != LOCK_MODE_UNDEFINED) { + return leftLockMode; + } + break; + case Gravity.RIGHT: + if (mLockModeRight != LOCK_MODE_UNDEFINED) { + return mLockModeRight; + } + int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) + ? mLockModeEnd : mLockModeStart; + if (rightLockMode != LOCK_MODE_UNDEFINED) { + return rightLockMode; + } + break; + case GravityCompat.START: + if (mLockModeStart != LOCK_MODE_UNDEFINED) { + return mLockModeStart; + } + int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) + ? mLockModeLeft : mLockModeRight; + if (startLockMode != LOCK_MODE_UNDEFINED) { + return startLockMode; + } + break; + case GravityCompat.END: + if (mLockModeEnd != LOCK_MODE_UNDEFINED) { + return mLockModeEnd; + } + int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) + ? mLockModeRight : mLockModeLeft; + if (endLockMode != LOCK_MODE_UNDEFINED) { + return endLockMode; + } + break; + } + + return LOCK_MODE_UNLOCKED; + } + + /** + * Check the lock mode of the given drawer view. + * + * @param drawerView Drawer view to check lock mode + * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or + * {@link #LOCK_MODE_LOCKED_OPEN}. + */ + @LockMode + public int getDrawerLockMode(@NonNull View drawerView) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a drawer"); + } + final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity; + return getDrawerLockMode(drawerGravity); + } + + /** + * Sets the title of the drawer with the given gravity. + *

+ * When accessibility is turned on, this is the title that will be used to + * identify the drawer to the active accessibility service. + * + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which + * drawer to set the title for. + * @param title The title for the drawer. + */ + public void setDrawerTitle(@EdgeGravity int edgeGravity, @Nullable CharSequence title) { + final int absGravity = GravityCompat.getAbsoluteGravity( + edgeGravity, ViewCompat.getLayoutDirection(this)); + if (absGravity == Gravity.LEFT) { + mTitleLeft = title; + } else if (absGravity == Gravity.RIGHT) { + mTitleRight = title; + } + } + + /** + * Returns the title of the drawer with the given gravity. + * + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which + * drawer to return the title for. + * @return The title of the drawer, or null if none set. + * @see #setDrawerTitle(int, CharSequence) + */ + @Nullable + public CharSequence getDrawerTitle(@EdgeGravity int edgeGravity) { + final int absGravity = GravityCompat.getAbsoluteGravity( + edgeGravity, ViewCompat.getLayoutDirection(this)); + if (absGravity == Gravity.LEFT) { + return mTitleLeft; + } else if (absGravity == Gravity.RIGHT) { + return mTitleRight; + } + return null; + } + + /** + * Resolve the shared state of all drawers from the component ViewDragHelpers. + * Should be called whenever a ViewDragHelper's state changes. + */ + void updateDrawerState(int forGravity, @State int activeState, View activeDrawer) { + final int leftState = mLeftDragger.getViewDragState(); + final int rightState = mRightDragger.getViewDragState(); + + final int state; + if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) { + state = STATE_DRAGGING; + } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) { + state = STATE_SETTLING; + } else { + state = STATE_IDLE; + } + + if (activeDrawer != null && activeState == STATE_IDLE) { + final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams(); + if (lp.onScreen == 0) { + dispatchOnDrawerClosed(activeDrawer); + } else if (lp.onScreen == 1) { + dispatchOnDrawerOpened(activeDrawer); + } + } + + if (state != mDrawerState) { + mDrawerState = state; + + if (mListeners != null) { + // Notify the listeners. Do that from the end of the list so that if a listener + // removes itself as the result of being called, it won't mess up with our iteration + int listenerCount = mListeners.size(); + for (int i = listenerCount - 1; i >= 0; i--) { + mListeners.get(i).onDrawerStateChanged(state); + } + } + } + } + + void dispatchOnDrawerClosed(View drawerView) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) { + lp.openState = 0; + + if (mListeners != null) { + // Notify the listeners. Do that from the end of the list so that if a listener + // removes itself as the result of being called, it won't mess up with our iteration + int listenerCount = mListeners.size(); + for (int i = listenerCount - 1; i >= 0; i--) { + mListeners.get(i).onDrawerClosed(drawerView); + } + } + + updateChildrenImportantForAccessibility(drawerView, false); + + // Only send WINDOW_STATE_CHANGE if the host has window focus. This + // may change if support for multiple foreground windows (e.g. IME) + // improves. + if (hasWindowFocus()) { + final View rootView = getRootView(); + if (rootView != null) { + rootView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + } + } + } + + void dispatchOnDrawerOpened(View drawerView) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) { + lp.openState = LayoutParams.FLAG_IS_OPENED; + if (mListeners != null) { + // Notify the listeners. Do that from the end of the list so that if a listener + // removes itself as the result of being called, it won't mess up with our iteration + int listenerCount = mListeners.size(); + for (int i = listenerCount - 1; i >= 0; i--) { + mListeners.get(i).onDrawerOpened(drawerView); + } + } + + updateChildrenImportantForAccessibility(drawerView, true); + + // Only send WINDOW_STATE_CHANGE if the host has window focus. + if (hasWindowFocus()) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + } + } + + private void updateChildrenImportantForAccessibility(View drawerView, boolean isDrawerOpen) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if ((!isDrawerOpen && !isDrawerView(child)) || (isDrawerOpen && child == drawerView)) { + // Drawer is closed and this is a content view or this is an + // open drawer view, so it should be visible. + ViewCompat.setImportantForAccessibility(child, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + } else { + ViewCompat.setImportantForAccessibility(child, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + } + } + + void dispatchOnDrawerSlide(View drawerView, float slideOffset) { + if (mListeners != null) { + // Notify the listeners. Do that from the end of the list so that if a listener + // removes itself as the result of being called, it won't mess up with our iteration + int listenerCount = mListeners.size(); + for (int i = listenerCount - 1; i >= 0; i--) { + mListeners.get(i).onDrawerSlide(drawerView, slideOffset); + } + } + } + + void setDrawerViewOffset(View drawerView, float slideOffset) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (slideOffset == lp.onScreen) { + return; + } + + lp.onScreen = slideOffset; + dispatchOnDrawerSlide(drawerView, slideOffset); + } + + float getDrawerViewOffset(View drawerView) { + return ((LayoutParams) drawerView.getLayoutParams()).onScreen; + } + + /** + * @return the absolute gravity of the child drawerView, resolved according + * to the current layout direction + */ + int getDrawerViewAbsoluteGravity(View drawerView) { + final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity; + return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this)); + } + + boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) { + final int absGravity = getDrawerViewAbsoluteGravity(drawerView); + return (absGravity & checkFor) == checkFor; + } + + View findOpenDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams childLp = (LayoutParams) child.getLayoutParams(); + if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) { + return child; + } + } + return null; + } + + void moveDrawerToOffset(View drawerView, float slideOffset) { + final float oldOffset = getDrawerViewOffset(drawerView); + final int width = drawerView.getWidth(); + final int oldPos = (int) (width * oldOffset); + final int newPos = (int) (width * slideOffset); + final int dx = newPos - oldPos; + + drawerView.offsetLeftAndRight( + checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx); + setDrawerViewOffset(drawerView, slideOffset); + } + + /** + * @param gravity the gravity of the child to return. If specified as a + * relative value, it will be resolved according to the current + * layout direction. + * @return the drawer with the specified gravity + */ + View findDrawerWithGravity(int gravity) { + final int absHorizGravity = GravityCompat.getAbsoluteGravity( + gravity, ViewCompat.getLayoutDirection(this)) & Gravity.HORIZONTAL_GRAVITY_MASK; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final int childAbsGravity = getDrawerViewAbsoluteGravity(child); + if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) { + return child; + } + } + return null; + } + + /** + * Simple gravity to string - only supports LEFT and RIGHT for debugging output. + * + * @param gravity Absolute gravity value + * @return LEFT or RIGHT as appropriate, or a hex string + */ + static String gravityToString(@EdgeGravity int gravity) { + if ((gravity & Gravity.LEFT) == Gravity.LEFT) { + return "LEFT"; + } + if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) { + return "RIGHT"; + } + return Integer.toHexString(gravity); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mFirstLayout = true; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { + if (isInEditMode()) { + // Don't crash the layout editor. Consume all of the space if specified + // or pick a magic number from thin air otherwise. + // TODO Better communication with tools of this bogus state. + // It will crash on a real device. + if (widthMode == MeasureSpec.AT_MOST) { + widthMode = MeasureSpec.EXACTLY; + } else if (widthMode == MeasureSpec.UNSPECIFIED) { + widthMode = MeasureSpec.EXACTLY; + widthSize = 300; + } + if (heightMode == MeasureSpec.AT_MOST) { + heightMode = MeasureSpec.EXACTLY; + } else if (heightMode == MeasureSpec.UNSPECIFIED) { + heightMode = MeasureSpec.EXACTLY; + heightSize = 300; + } + } else { + throw new IllegalArgumentException( + "DrawerLayout must be measured with MeasureSpec.EXACTLY."); + } + } + + setMeasuredDimension(widthSize, heightSize); + + final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this); + final int layoutDirection = ViewCompat.getLayoutDirection(this); + + // Only one drawer is permitted along each vertical edge (left / right). These two booleans + // are tracking the presence of the edge drawers. + boolean hasDrawerOnLeftEdge = false; + boolean hasDrawerOnRightEdge = false; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child.getVisibility() == GONE) { + continue; + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (applyInsets) { + final int cgrav = GravityCompat.getAbsoluteGravity(lp.gravity, layoutDirection); + if (ViewCompat.getFitsSystemWindows(child)) { + if (Build.VERSION.SDK_INT >= 21) { + WindowInsets wi = (WindowInsets) mLastInsets; + if (cgrav == Gravity.LEFT) { + wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), + wi.getSystemWindowInsetTop(), 0, + wi.getSystemWindowInsetBottom()); + } else if (cgrav == Gravity.RIGHT) { + wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), + wi.getSystemWindowInsetRight(), + wi.getSystemWindowInsetBottom()); + } + child.dispatchApplyWindowInsets(wi); + } + } else { + if (Build.VERSION.SDK_INT >= 21) { + WindowInsets wi = (WindowInsets) mLastInsets; + if (cgrav == Gravity.LEFT) { + wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), + wi.getSystemWindowInsetTop(), 0, + wi.getSystemWindowInsetBottom()); + } else if (cgrav == Gravity.RIGHT) { + wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), + wi.getSystemWindowInsetRight(), + wi.getSystemWindowInsetBottom()); + } + lp.leftMargin = wi.getSystemWindowInsetLeft(); + lp.topMargin = wi.getSystemWindowInsetTop(); + lp.rightMargin = wi.getSystemWindowInsetRight(); + lp.bottomMargin = wi.getSystemWindowInsetBottom(); + } + } + } + + if (isContentView(child)) { + // Content views get measured at exactly the layout's size. + final int contentWidthSpec = MeasureSpec.makeMeasureSpec( + widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY); + final int contentHeightSpec = MeasureSpec.makeMeasureSpec( + heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY); + child.measure(contentWidthSpec, contentHeightSpec); + } else if (isDrawerView(child)) { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + if (ViewCompat.getElevation(child) != mDrawerElevation) { + ViewCompat.setElevation(child, mDrawerElevation); + } + } + final @EdgeGravity int childGravity = + getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK; + // Note that the isDrawerView check guarantees that childGravity here is either + // LEFT or RIGHT + boolean isLeftEdgeDrawer = (childGravity == Gravity.LEFT); + if ((isLeftEdgeDrawer && hasDrawerOnLeftEdge) + || (!isLeftEdgeDrawer && hasDrawerOnRightEdge)) { + throw new IllegalStateException("Child drawer has absolute gravity " + + gravityToString(childGravity) + " but this " + TAG + " already has a " + + "drawer view along that edge"); + } + if (isLeftEdgeDrawer) { + hasDrawerOnLeftEdge = true; + } else { + hasDrawerOnRightEdge = true; + } + final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, + mMinDrawerMargin + lp.leftMargin + lp.rightMargin, + lp.width); + final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec, + lp.topMargin + lp.bottomMargin, + lp.height); + child.measure(drawerWidthSpec, drawerHeightSpec); + } else { + throw new IllegalStateException("Child " + child + " at index " + i + + " does not have a valid layout_gravity - must be Gravity.LEFT, " + + "Gravity.RIGHT or Gravity.NO_GRAVITY"); + } + } + } + + private void resolveShadowDrawables() { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + return; + } + mShadowLeftResolved = resolveLeftShadow(); + mShadowRightResolved = resolveRightShadow(); + } + + private Drawable resolveLeftShadow() { + int layoutDirection = ViewCompat.getLayoutDirection(this); + // Prefer shadows defined with start/end gravity over left and right. + if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (mShadowStart != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowStart, layoutDirection); + return mShadowStart; + } + } else { + if (mShadowEnd != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowEnd, layoutDirection); + return mShadowEnd; + } + } + return mShadowLeft; + } + + private Drawable resolveRightShadow() { + int layoutDirection = ViewCompat.getLayoutDirection(this); + if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (mShadowEnd != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowEnd, layoutDirection); + return mShadowEnd; + } + } else { + if (mShadowStart != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowStart, layoutDirection); + return mShadowStart; + } + } + return mShadowRight; + } + + /** + * Change the layout direction of the given drawable. + * Return true if auto-mirror is supported and drawable's layout direction can be changed. + * Otherwise, return false. + */ + private boolean mirror(Drawable drawable, int layoutDirection) { + if (drawable == null || !DrawableCompat.isAutoMirrored(drawable)) { + return false; + } + + DrawableCompat.setLayoutDirection(drawable, layoutDirection); + return true; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mInLayout = true; + final int width = r - l; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child.getVisibility() == GONE) { + continue; + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (isContentView(child)) { + child.layout(lp.leftMargin, lp.topMargin, + lp.leftMargin + child.getMeasuredWidth(), + lp.topMargin + child.getMeasuredHeight()); + } else { // Drawer, if it wasn't onMeasure would have thrown an exception. + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + int childLeft; + + final float newOffset; + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + childLeft = -childWidth + (int) (childWidth * lp.onScreen); + newOffset = (float) (childWidth + childLeft) / childWidth; + } else { // Right; onMeasure checked for us. + childLeft = width - (int) (childWidth * lp.onScreen); + newOffset = (float) (width - childLeft) / childWidth; + } + + final boolean changeOffset = newOffset != lp.onScreen; + + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (vgrav) { + default: + case Gravity.TOP: { + child.layout(childLeft, lp.topMargin, childLeft + childWidth, + lp.topMargin + childHeight); + break; + } + + case Gravity.BOTTOM: { + final int height = b - t; + child.layout(childLeft, + height - lp.bottomMargin - child.getMeasuredHeight(), + childLeft + childWidth, + height - lp.bottomMargin); + break; + } + + case Gravity.CENTER_VERTICAL: { + final int height = b - t; + int childTop = (height - childHeight) / 2; + + // Offset for margins. If things don't fit right because of + // bad measurement before, oh well. + if (childTop < lp.topMargin) { + childTop = lp.topMargin; + } else if (childTop + childHeight > height - lp.bottomMargin) { + childTop = height - lp.bottomMargin - childHeight; + } + child.layout(childLeft, childTop, childLeft + childWidth, + childTop + childHeight); + break; + } + } + + if (changeOffset) { + setDrawerViewOffset(child, newOffset); + } + + final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE; + if (child.getVisibility() != newVisibility) { + child.setVisibility(newVisibility); + } + } + } + mInLayout = false; + mFirstLayout = false; + } + + @Override + public void requestLayout() { + if (!mInLayout) { + super.requestLayout(); + } + } + + @Override + public void computeScroll() { + final int childCount = getChildCount(); + float scrimOpacity = 0; + for (int i = 0; i < childCount; i++) { + final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen; + scrimOpacity = Math.max(scrimOpacity, onscreen); + } + mScrimOpacity = scrimOpacity; + + boolean leftDraggerSettling = mLeftDragger.continueSettling(true); + boolean rightDraggerSettling = mRightDragger.continueSettling(true); + if (leftDraggerSettling || rightDraggerSettling) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + private static boolean hasOpaqueBackground(View v) { + final Drawable bg = v.getBackground(); + if (bg != null) { + return bg.getOpacity() == PixelFormat.OPAQUE; + } + return false; + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param bg Background drawable to draw behind the status bar + */ + public void setStatusBarBackground(@Nullable Drawable bg) { + mStatusBarBackground = bg; + invalidate(); + } + + /** + * Gets the drawable used to draw in the insets area for the status bar. + * + * @return The status bar background drawable, or null if none set + */ + @Nullable + public Drawable getStatusBarBackgroundDrawable() { + return mStatusBarBackground; + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param resId Resource id of a background drawable to draw behind the status bar + */ + public void setStatusBarBackground(int resId) { + mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null; + invalidate(); + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param color Color to use as a background drawable to draw behind the status bar + * in 0xAARRGGBB format. + */ + public void setStatusBarBackgroundColor(@ColorInt int color) { + mStatusBarBackground = new ColorDrawable(color); + invalidate(); + } + + @Override + public void onRtlPropertiesChanged(int layoutDirection) { + resolveShadowDrawables(); + } + + @Override + public void onDraw(Canvas c) { + super.onDraw(c); + if (mDrawStatusBarBackground && mStatusBarBackground != null) { + final int inset; + if (Build.VERSION.SDK_INT >= 21) { + inset = mLastInsets != null + ? ((WindowInsets) mLastInsets).getSystemWindowInsetTop() : 0; + } else { + inset = 0; + } + if (inset > 0) { + mStatusBarBackground.setBounds(0, 0, getWidth(), inset); + mStatusBarBackground.draw(c); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + final int height = getHeight(); + final boolean drawingContent = isContentView(child); + int clipLeft = 0, clipRight = getWidth(); + + final int restoreCount = canvas.save(); + if (drawingContent) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View v = getChildAt(i); + if (v == child || v.getVisibility() != VISIBLE + || !hasOpaqueBackground(v) || !isDrawerView(v) + || v.getHeight() < height) { + continue; + } + + if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) { + final int vright = v.getRight(); + if (vright > clipLeft) clipLeft = vright; + } else { + final int vleft = v.getLeft(); + if (vleft < clipRight) clipRight = vleft; + } + } + canvas.clipRect(clipLeft, 0, clipRight, getHeight()); + } + final boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restoreToCount(restoreCount); + + if (mScrimOpacity > 0 && drawingContent) { + final int baseAlpha = (mScrimColor & 0xff000000) >>> 24; + final int imag = (int) (baseAlpha * mScrimOpacity); + final int color = imag << 24 | (mScrimColor & 0xffffff); + mScrimPaint.setColor(color); + + canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint); + } else if (mShadowLeftResolved != null + && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth(); + final int childRight = child.getRight(); + final int drawerPeekDistance = mLeftDragger.getEdgeSize(); + final float alpha = + Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f)); + mShadowLeftResolved.setBounds(childRight, child.getTop(), + childRight + shadowWidth, child.getBottom()); + mShadowLeftResolved.setAlpha((int) (0xff * alpha)); + mShadowLeftResolved.draw(canvas); + } else if (mShadowRightResolved != null + && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) { + final int shadowWidth = mShadowRightResolved.getIntrinsicWidth(); + final int childLeft = child.getLeft(); + final int showing = getWidth() - childLeft; + final int drawerPeekDistance = mRightDragger.getEdgeSize(); + final float alpha = + Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f)); + mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(), + childLeft, child.getBottom()); + mShadowRightResolved.setAlpha((int) (0xff * alpha)); + mShadowRightResolved.draw(canvas); + } + return result; + } + + boolean isContentView(View child) { + return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY; + } + + boolean isDrawerView(View child) { + final int gravity = ((LayoutParams) child.getLayoutParams()).gravity; + final int absGravity = GravityCompat.getAbsoluteGravity(gravity, + ViewCompat.getLayoutDirection(child)); + if ((absGravity & Gravity.LEFT) != 0) { + // This child is a left-edge drawer + return true; + } + if ((absGravity & Gravity.RIGHT) != 0) { + // This child is a right-edge drawer + return true; + } + return false; + } + + @SuppressWarnings("ShortCircuitBoolean") + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + final int action = ev.getActionMasked(); + + // "|" used deliberately here; both methods should be invoked. + final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) + | mRightDragger.shouldInterceptTouchEvent(ev); + + boolean interceptForTap = false; + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + mInitialMotionX = x; + mInitialMotionY = y; + if (mScrimOpacity > 0) { + final View child = mLeftDragger.findTopChildUnder((int) x, (int) y); + if (child != null && isContentView(child)) { + interceptForTap = true; + } + } + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + + case MotionEvent.ACTION_MOVE: { + // If we cross the touch slop, don't perform the delayed peek for an edge touch. + if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) { + mLeftCallback.removeCallbacks(); + mRightCallback.removeCallbacks(); + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + closeDrawers(true); + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + } + } + + return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch; + }catch (IllegalArgumentException e){ + e.printStackTrace(); + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + mLeftDragger.processTouchEvent(ev); + mRightDragger.processTouchEvent(ev); + + final int action = ev.getAction(); + boolean wantTouchEvents = true; + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + mInitialMotionX = x; + mInitialMotionY = y; + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + + case MotionEvent.ACTION_UP: { + final float x = ev.getX(); + final float y = ev.getY(); + boolean peekingOnly = true; + final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y); + if (touchedView != null && isContentView(touchedView)) { + final float dx = x - mInitialMotionX; + final float dy = y - mInitialMotionY; + final int slop = mLeftDragger.getTouchSlop(); + if (dx * dx + dy * dy < slop * slop) { + // Taps close a dimmed open drawer but only if it isn't locked open. + final View openDrawer = findOpenDrawer(); + if (openDrawer != null) { + peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN; + } + } + } + closeDrawers(peekingOnly); + mDisallowInterceptRequested = false; + break; + } + + case MotionEvent.ACTION_CANCEL: { + closeDrawers(true); + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + } + + return wantTouchEvents; + }catch (IllegalArgumentException e){ + e.printStackTrace(); + } + return false; + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + if (CHILDREN_DISALLOW_INTERCEPT + || (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT) + && !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) { + // If we have an edge touch we want to skip this and track it for later instead. + super.requestDisallowInterceptTouchEvent(disallowIntercept); + } + mDisallowInterceptRequested = disallowIntercept; + if (disallowIntercept) { + closeDrawers(true); + } + } + + /** + * Close all currently open drawer views by animating them out of view. + */ + public void closeDrawers() { + closeDrawers(false); + } + + void closeDrawers(boolean peekingOnly) { + boolean needsInvalidate = false; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) { + continue; + } + + final int childWidth = child.getWidth(); + + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + needsInvalidate |= mLeftDragger.smoothSlideViewTo(child, + -childWidth, child.getTop()); + } else { + needsInvalidate |= mRightDragger.smoothSlideViewTo(child, + getWidth(), child.getTop()); + } + + lp.isPeeking = false; + } + + mLeftCallback.removeCallbacks(); + mRightCallback.removeCallbacks(); + + if (needsInvalidate) { + invalidate(); + } + } + + /** + * Open the specified drawer view by animating it into view. + * + * @param drawerView Drawer view to open + */ + public void openDrawer(@NonNull View drawerView) { + openDrawer(drawerView, true); + } + + /** + * Open the specified drawer view. + * + * @param drawerView Drawer view to open + * @param animate Whether opening of the drawer should be animated. + */ + public void openDrawer(@NonNull View drawerView, boolean animate) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer"); + } + + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (mFirstLayout) { + lp.onScreen = 1.f; + lp.openState = LayoutParams.FLAG_IS_OPENED; + + updateChildrenImportantForAccessibility(drawerView, true); + } else if (animate) { + lp.openState |= LayoutParams.FLAG_IS_OPENING; + + if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) { + mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop()); + } else { + mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(), + drawerView.getTop()); + } + } else { + moveDrawerToOffset(drawerView, 1.f); + updateDrawerState(lp.gravity, STATE_IDLE, drawerView); + drawerView.setVisibility(VISIBLE); + } + invalidate(); + } + + /** + * Open the specified drawer by animating it out of view. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * GravityCompat.START or GravityCompat.END may also be used. + */ + public void openDrawer(@EdgeGravity int gravity) { + openDrawer(gravity, true); + } + + /** + * Open the specified drawer. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * GravityCompat.START or GravityCompat.END may also be used. + * @param animate Whether opening of the drawer should be animated. + */ + public void openDrawer(@EdgeGravity int gravity, boolean animate) { + final View drawerView = findDrawerWithGravity(gravity); + if (drawerView == null) { + throw new IllegalArgumentException("No drawer view found with gravity " + + gravityToString(gravity)); + } + openDrawer(drawerView, animate); + } + + /** + * Close the specified drawer view by animating it into view. + * + * @param drawerView Drawer view to close + */ + public void closeDrawer(@NonNull View drawerView) { + closeDrawer(drawerView, true); + } + + /** + * Close the specified drawer view. + * + * @param drawerView Drawer view to close + * @param animate Whether closing of the drawer should be animated. + */ + public void closeDrawer(@NonNull View drawerView, boolean animate) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer"); + } + + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (mFirstLayout) { + lp.onScreen = 0.f; + lp.openState = 0; + } else if (animate) { + lp.openState |= LayoutParams.FLAG_IS_CLOSING; + + if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) { + mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(), + drawerView.getTop()); + } else { + mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop()); + } + } else { + moveDrawerToOffset(drawerView, 0.f); + updateDrawerState(lp.gravity, STATE_IDLE, drawerView); + drawerView.setVisibility(INVISIBLE); + } + invalidate(); + } + + /** + * Close the specified drawer by animating it out of view. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * GravityCompat.START or GravityCompat.END may also be used. + */ + public void closeDrawer(@EdgeGravity int gravity) { + closeDrawer(gravity, true); + } + + /** + * Close the specified drawer. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * GravityCompat.START or GravityCompat.END may also be used. + * @param animate Whether closing of the drawer should be animated. + */ + public void closeDrawer(@EdgeGravity int gravity, boolean animate) { + final View drawerView = findDrawerWithGravity(gravity); + if (drawerView == null) { + throw new IllegalArgumentException("No drawer view found with gravity " + + gravityToString(gravity)); + } + closeDrawer(drawerView, animate); + } + + /** + * Check if the given drawer view is currently in an open state. + * To be considered "open" the drawer must have settled into its fully + * visible state. To check for partial visibility use + * {@link #isDrawerVisible(android.view.View)}. + * + * @param drawer Drawer view to check + * @return true if the given drawer view is in an open state + * @see #isDrawerVisible(android.view.View) + */ + public boolean isDrawerOpen(@NonNull View drawer) { + if (!isDrawerView(drawer)) { + throw new IllegalArgumentException("View " + drawer + " is not a drawer"); + } + LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams(); + return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1; + } + + /** + * Check if the given drawer view is currently in an open state. + * To be considered "open" the drawer must have settled into its fully + * visible state. If there is no drawer with the given gravity this method + * will return false. + * + * @param drawerGravity Gravity of the drawer to check + * @return true if the given drawer view is in an open state + */ + public boolean isDrawerOpen(@EdgeGravity int drawerGravity) { + final View drawerView = findDrawerWithGravity(drawerGravity); + if (drawerView != null) { + return isDrawerOpen(drawerView); + } + return false; + } + + /** + * Check if a given drawer view is currently visible on-screen. The drawer + * may be only peeking onto the screen, fully extended, or anywhere inbetween. + * + * @param drawer Drawer view to check + * @return true if the given drawer is visible on-screen + * @see #isDrawerOpen(android.view.View) + */ + public boolean isDrawerVisible(@NonNull View drawer) { + if (!isDrawerView(drawer)) { + throw new IllegalArgumentException("View " + drawer + " is not a drawer"); + } + return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0; + } + + /** + * Check if a given drawer view is currently visible on-screen. The drawer + * may be only peeking onto the screen, fully extended, or anywhere in between. + * If there is no drawer with the given gravity this method will return false. + * + * @param drawerGravity Gravity of the drawer to check + * @return true if the given drawer is visible on-screen + */ + public boolean isDrawerVisible(@EdgeGravity int drawerGravity) { + final View drawerView = findDrawerWithGravity(drawerGravity); + if (drawerView != null) { + return isDrawerVisible(drawerView); + } + return false; + } + + private boolean hasPeekingDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); + if (lp.isPeeking) { + return true; + } + } + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams + ? new LayoutParams((LayoutParams) p) + : p instanceof ViewGroup.MarginLayoutParams + ? new LayoutParams((MarginLayoutParams) p) + : new LayoutParams(p); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) { + return; + } + + // Only the views in the open drawers are focusables. Add normal child views when + // no drawers are opened. + final int childCount = getChildCount(); + boolean isDrawerOpen = false; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (isDrawerView(child)) { + if (isDrawerOpen(child)) { + isDrawerOpen = true; + child.addFocusables(views, direction, focusableMode); + } + } else { + mNonDrawerViews.add(child); + } + } + + if (!isDrawerOpen) { + final int nonDrawerViewsCount = mNonDrawerViews.size(); + for (int i = 0; i < nonDrawerViewsCount; ++i) { + final View child = mNonDrawerViews.get(i); + if (child.getVisibility() == View.VISIBLE) { + child.addFocusables(views, direction, focusableMode); + } + } + } + + mNonDrawerViews.clear(); + } + + private boolean hasVisibleDrawer() { + return findVisibleDrawer() != null; + } + + View findVisibleDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (isDrawerView(child) && isDrawerVisible(child)) { + return child; + } + } + return null; + } + + void cancelChildViewTouch() { + // Cancel child touches + if (!mChildrenCanceledTouch) { + final long now = SystemClock.uptimeMillis(); + final MotionEvent cancelEvent = MotionEvent.obtain(now, now, + MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + getChildAt(i).dispatchTouchEvent(cancelEvent); + } + cancelEvent.recycle(); + mChildrenCanceledTouch = true; + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) { + event.startTracking(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + final View visibleDrawer = findVisibleDrawer(); + if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) { + closeDrawers(); + } + return visibleDrawer != null; + } + return super.onKeyUp(keyCode, event); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + final SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (ss.openDrawerGravity != Gravity.NO_GRAVITY) { + final View toOpen = findDrawerWithGravity(ss.openDrawerGravity); + if (toOpen != null) { + openDrawer(toOpen); + } + } + + if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) { + setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT); + } + if (ss.lockModeRight != LOCK_MODE_UNDEFINED) { + setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT); + } + if (ss.lockModeStart != LOCK_MODE_UNDEFINED) { + setDrawerLockMode(ss.lockModeStart, GravityCompat.START); + } + if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) { + setDrawerLockMode(ss.lockModeEnd, GravityCompat.END); + } + } + + @Override + protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + final SavedState ss = new SavedState(superState); + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + // Is the current child fully opened (that is, not closing)? + boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED); + // Is the current child opening? + boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING); + if (isOpenedAndNotClosing || isClosedAndOpening) { + // If one of the conditions above holds, save the child's gravity + // so that we open that child during state restore. + ss.openDrawerGravity = lp.gravity; + break; + } + } + + ss.lockModeLeft = mLockModeLeft; + ss.lockModeRight = mLockModeRight; + ss.lockModeStart = mLockModeStart; + ss.lockModeEnd = mLockModeEnd; + + return ss; + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + super.addView(child, index, params); + + final View openDrawer = findOpenDrawer(); + if (openDrawer != null || isDrawerView(child)) { + // A drawer is already open or the new view is a drawer, so the + // new view should start out hidden. + ViewCompat.setImportantForAccessibility(child, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } else { + // Otherwise this is a content view and no drawer is open, so the + // new view should start out visible. + ViewCompat.setImportantForAccessibility(child, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + + // We only need a delegate here if the framework doesn't understand + // NO_HIDE_DESCENDANTS importance. + if (!CAN_HIDE_DESCENDANTS) { + ViewCompat.setAccessibilityDelegate(child, mChildAccessibilityDelegate); + } + } + + static boolean includeChildForAccessibility(View child) { + // If the child is not important for accessibility we make + // sure this hides the entire subtree rooted at it as the + // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not + // supported on older platforms but we want to hide the entire + // content and not opened drawers if a drawer is opened. + return ViewCompat.getImportantForAccessibility(child) + != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + && ViewCompat.getImportantForAccessibility(child) + != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO; + } + + /** + * State persisted across instances + */ + protected static class SavedState extends AbsSavedState { + int openDrawerGravity = Gravity.NO_GRAVITY; + @LockMode int lockModeLeft; + @LockMode int lockModeRight; + @LockMode int lockModeStart; + @LockMode int lockModeEnd; + + public SavedState(@NonNull Parcel in, @Nullable ClassLoader loader) { + super(in, loader); + openDrawerGravity = in.readInt(); + lockModeLeft = in.readInt(); + lockModeRight = in.readInt(); + lockModeStart = in.readInt(); + lockModeEnd = in.readInt(); + } + + public SavedState(@NonNull Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(openDrawerGravity); + dest.writeInt(lockModeLeft); + dest.writeInt(lockModeRight); + dest.writeInt(lockModeStart); + dest.writeInt(lockModeEnd); + } + + public static final Creator CREATOR = new ClassLoaderCreator() { + @Override + public SavedState createFromParcel(Parcel in, ClassLoader loader) { + return new SavedState(in, loader); + } + + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in, null); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + private class ViewDragCallback extends ViewDragHelper.Callback { + private final int mAbsGravity; + private ViewDragHelper mDragger; + + private final Runnable mPeekRunnable = new Runnable() { + @Override public void run() { + peekDrawer(); + } + }; + + ViewDragCallback(int gravity) { + mAbsGravity = gravity; + } + + public void setDragger(ViewDragHelper dragger) { + mDragger = dragger; + } + + public void removeCallbacks() { + DrawerLayout.this.removeCallbacks(mPeekRunnable); + } + + @Override + public boolean tryCaptureView(View child, int pointerId) { + // Only capture views where the gravity matches what we're looking for. + // This lets us use two ViewDragHelpers, one for each side drawer. + return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity) + && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED; + } + + @Override + public void onViewDragStateChanged(int state) { + updateDrawerState(mAbsGravity, state, mDragger.getCapturedView()); + } + + @Override + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { + float offset; + final int childWidth = changedView.getWidth(); + + // This reverses the positioning shown in onLayout. + if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) { + offset = (float) (childWidth + left) / childWidth; + } else { + final int width = getWidth(); + offset = (float) (width - left) / childWidth; + } + setDrawerViewOffset(changedView, offset); + changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE); + invalidate(); + } + + @Override + public void onViewCaptured(View capturedChild, int activePointerId) { + final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams(); + lp.isPeeking = false; + + closeOtherDrawer(); + } + + private void closeOtherDrawer() { + final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT; + final View toClose = findDrawerWithGravity(otherGrav); + if (toClose != null) { + closeDrawer(toClose); + } + } + + @Override + public void onViewReleased(View releasedChild, float xvel, float yvel) { + // Offset is how open the drawer is, therefore left/right values + // are reversed from one another. + final float offset = getDrawerViewOffset(releasedChild); + final int childWidth = releasedChild.getWidth(); + + int left; + if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) { + left = xvel > 0 || (xvel == 0 && offset > 0.5f) ? 0 : -childWidth; + } else { + final int width = getWidth(); + left = xvel < 0 || (xvel == 0 && offset > 0.5f) ? width - childWidth : width; + } + + mDragger.settleCapturedViewAt(left, releasedChild.getTop()); + invalidate(); + } + + @Override + public void onEdgeTouched(int edgeFlags, int pointerId) { + postDelayed(mPeekRunnable, PEEK_DELAY); + } + + void peekDrawer() { + final View toCapture; + final int childLeft; + final int peekDistance = mDragger.getEdgeSize(); + final boolean leftEdge = mAbsGravity == Gravity.LEFT; + if (leftEdge) { + toCapture = findDrawerWithGravity(Gravity.LEFT); + childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance; + } else { + toCapture = findDrawerWithGravity(Gravity.RIGHT); + childLeft = getWidth() - peekDistance; + } + // Only peek if it would mean making the drawer more visible and the drawer isn't locked + if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft) + || (!leftEdge && toCapture.getLeft() > childLeft)) + && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) { + final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams(); + mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop()); + lp.isPeeking = true; + invalidate(); + + closeOtherDrawer(); + + cancelChildViewTouch(); + } + } + + @Override + public boolean onEdgeLock(int edgeFlags) { + if (ALLOW_EDGE_LOCK) { + final View drawer = findDrawerWithGravity(mAbsGravity); + if (drawer != null && !isDrawerOpen(drawer)) { + closeDrawer(drawer); + } + return true; + } + return false; + } + + @Override + public void onEdgeDragStarted(int edgeFlags, int pointerId) { + final View toCapture; + if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) { + toCapture = findDrawerWithGravity(Gravity.LEFT); + } else { + toCapture = findDrawerWithGravity(Gravity.RIGHT); + } + + if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) { + mDragger.captureChildView(toCapture, pointerId); + } + } + + @Override + public int getViewHorizontalDragRange(View child) { + return isDrawerView(child) ? child.getWidth() : 0; + } + + @Override + public int clampViewPositionHorizontal(View child, int left, int dx) { + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + return Math.max(-child.getWidth(), Math.min(left, 0)); + } else { + final int width = getWidth(); + return Math.max(width - child.getWidth(), Math.min(left, width)); + } + } + + @Override + public int clampViewPositionVertical(View child, int top, int dy) { + return child.getTop(); + } + } + + public static class LayoutParams extends ViewGroup.MarginLayoutParams { + private static final int FLAG_IS_OPENED = 0x1; + private static final int FLAG_IS_OPENING = 0x2; + private static final int FLAG_IS_CLOSING = 0x4; + + public int gravity = Gravity.NO_GRAVITY; + float onScreen; + boolean isPeeking; + int openState; + + public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) { + super(c, attrs); + + final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + this.gravity = a.getInt(0, Gravity.NO_GRAVITY); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(int width, int height, int gravity) { + this(width, height); + this.gravity = gravity; + } + + public LayoutParams(@NonNull LayoutParams source) { + super(source); + this.gravity = source.gravity; + } + + public LayoutParams(@NonNull ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) { + super(source); + } + } + + class AccessibilityDelegate extends AccessibilityDelegateCompat { + private final Rect mTmpRect = new Rect(); + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { + if (CAN_HIDE_DESCENDANTS) { + super.onInitializeAccessibilityNodeInfo(host, info); + } else { + // Obtain a node for the host, then manually generate the list + // of children to only include non-obscured views. + final AccessibilityNodeInfoCompat superNode = + AccessibilityNodeInfoCompat.obtain(info); + super.onInitializeAccessibilityNodeInfo(host, superNode); + + info.setSource(host); + final ViewParent parent = ViewCompat.getParentForAccessibility(host); + if (parent instanceof View) { + info.setParent((View) parent); + } + copyNodeInfoNoChildren(info, superNode); + superNode.recycle(); + + addChildrenForAccessibility(info, (ViewGroup) host); + } + + info.setClassName(DrawerLayout.class.getName()); + + // This view reports itself as focusable so that it can intercept + // the back button, but we should prevent this view from reporting + // itself as focusable to accessibility services. + info.setFocusable(false); + info.setFocused(false); + info.removeAction(AccessibilityActionCompat.ACTION_FOCUS); + info.removeAction(AccessibilityActionCompat.ACTION_CLEAR_FOCUS); + } + + @Override + public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(host, event); + + event.setClassName(DrawerLayout.class.getName()); + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { + // Special case to handle window state change events. As far as + // accessibility services are concerned, state changes from + // DrawerLayout invalidate the entire contents of the screen (like + // an Activity or Dialog) and they should announce the title of the + // new content. + if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + final List eventText = event.getText(); + final View visibleDrawer = findVisibleDrawer(); + if (visibleDrawer != null) { + final int edgeGravity = getDrawerViewAbsoluteGravity(visibleDrawer); + final CharSequence title = getDrawerTitle(edgeGravity); + if (title != null) { + eventText.add(title); + } + } + + return true; + } + + return super.dispatchPopulateAccessibilityEvent(host, event); + } + + @Override + public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, + AccessibilityEvent event) { + if (CAN_HIDE_DESCENDANTS || includeChildForAccessibility(child)) { + return super.onRequestSendAccessibilityEvent(host, child, event); + } + return false; + } + + private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) { + final int childCount = v.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = v.getChildAt(i); + if (includeChildForAccessibility(child)) { + info.addChild(child); + } + } + } + + /** + * This should really be in AccessibilityNodeInfoCompat, but there unfortunately + * seem to be a few elements that are not easily cloneable using the underlying API. + * Leave it private here as it's not general-purpose useful. + */ + private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest, + AccessibilityNodeInfoCompat src) { + final Rect rect = mTmpRect; + + src.getBoundsInParent(rect); + dest.setBoundsInParent(rect); + + src.getBoundsInScreen(rect); + dest.setBoundsInScreen(rect); + + dest.setVisibleToUser(src.isVisibleToUser()); + dest.setPackageName(src.getPackageName()); + dest.setClassName(src.getClassName()); + dest.setContentDescription(src.getContentDescription()); + + dest.setEnabled(src.isEnabled()); + dest.setClickable(src.isClickable()); + dest.setFocusable(src.isFocusable()); + dest.setFocused(src.isFocused()); + dest.setAccessibilityFocused(src.isAccessibilityFocused()); + dest.setSelected(src.isSelected()); + dest.setLongClickable(src.isLongClickable()); + + dest.addAction(src.getActions()); + } + } + + static final class ChildAccessibilityDelegate extends AccessibilityDelegateCompat { + @Override + public void onInitializeAccessibilityNodeInfo(View child, + AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(child, info); + + if (!includeChildForAccessibility(child)) { + // If we are ignoring the sub-tree rooted at the child, + // break the connection to the rest of the node tree. + // For details refer to includeChildForAccessibility. + info.setParent(null); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/FilletCornerImageView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/FilletCornerImageView.java new file mode 100644 index 0000000..33b9eb9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/FilletCornerImageView.java @@ -0,0 +1,96 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.AttributeSet; + +import com.mm.android.deviceaddmodule.R; + + +/** + * 自定义 ImageView 控件,实现了圆角和边框,以及按下变色 + * + * 修改设置选中 颜色和 按下颜色 的方法 ,通过系统api调用, 移除java代码依赖, 只需要依赖xml和attr配置 + */ +public class FilletCornerImageView extends android.support.v7.widget.AppCompatImageView { + // 图片的宽高 + private int width; + private int height; + // 圆角半径 + private int radius; + private Path mPath; + public FilletCornerImageView(Context context) { + super(context); + init(context, null); + } + + public FilletCornerImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public FilletCornerImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + //初始化默认值 + mPath = new Path(); + radius = 16; + // 获取控件的属性值 + if (attrs != null) { + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FilletCornerImageView); + radius = array.getDimensionPixelOffset(R.styleable.FilletCornerImageView_fillet_radius, radius); + array.recycle(); + } + + setClickable(true); + setDrawingCacheEnabled(true); + setWillNotDraw(false); + } + Paint paint = new Paint(); + + @Override + protected void onDraw(Canvas canvas) { + + if(width 0) { + Paint paint = new Paint(); + paint.setStrokeWidth(borderWidth); + paint.setStyle(Paint.Style.STROKE); + paint.setColor(borderColor); + paint.setAntiAlias(true); + // 根据控件类型的属性去绘制圆形或者矩形 + if (shapeType == 1) { + canvas.drawCircle(width / 2, height / 2, (width - borderWidth) / 2, paint); + } else if (shapeType == 2) { + // 当ShapeType = 1 时 图片为圆角矩形 + RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, + getHeight() - borderWidth / 2); + canvas.drawRoundRect(rectf, radius, radius, paint); + } + } + } + + /** + * 重写父类的 onSizeChanged 方法,检测控件宽高的变化 + * + * @param w + * @param h + * @param oldw + * @param oldh + */ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + width = w; + height = h; + } + + + /** + * 这里是参考其他开发者获取Bitmap内容的方法, 之前是因为没有考虑到 Glide 加载的图片 + * 导致drawable 类型是属于 SquaringDrawable 类型,导致强转失败 + * 这里是通过drawable不同的类型来进行获取Bitmap + * + * @param drawable + * @return + */ + private Bitmap getBitmapFromDrawable(Drawable drawable) { + try { + Bitmap bitmap; + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } else if (drawable instanceof ColorDrawable) { + bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), + BITMAP_CONFIG); + } + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } catch (OutOfMemoryError e) { + e.printStackTrace(); + return null; + } + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + setBorderColor(selected); + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + if(isSelected()){ + return; + } + setBorderColor(pressed); + } + + private void setBorderColor(boolean selected) { + if(selected){ + borderColor = borderSelectedColor; + }else{ + borderColor = borderUnSelectedColor; + } + invalidate(); + } + + + public void setRadius(int radius){ + this.radius = radius; + invalidate(); + } + + public void setShapeType(int type){ + this.shapeType = type; + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/PullToRefreshRecyclerView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/PullToRefreshRecyclerView.java new file mode 100644 index 0000000..37e198e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/PullToRefreshRecyclerView.java @@ -0,0 +1,89 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; + +import com.lechange.pulltorefreshlistview.Mode; +import com.lechange.pulltorefreshlistview.Orientation; +import com.lechange.pulltorefreshlistview.PullToRefreshBase; + +public class PullToRefreshRecyclerView extends PullToRefreshBase { + + + public PullToRefreshRecyclerView(Context context) { + super(context); + } + + public PullToRefreshRecyclerView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public PullToRefreshRecyclerView(Context context, Mode mode) { + super(context, mode); + } + + @Override + public Orientation getPullToRefreshScrollDirection() { + return Orientation.VERTICAL; + } + + @Override + protected RecyclerView createRefreshableView(Context context, AttributeSet attrs) { + RecyclerView recyclerView = new RecyclerView(context); + return recyclerView; + } + + + @Override + protected boolean isReadyForPullStart() { + return isFirstItemVisible(); + } + + public boolean isFirstItemVisible() { + final RecyclerView.Adapter adapter = getRefreshableView().getAdapter(); + + //如果未设置Adapter或者Adpter没有数据可以下拉刷新 + if(null == adapter || adapter.getItemCount() == 0){ + return true; + }else{ + if(getFristVisiblePosition() == 0){ + return mRefreshableView.getChildAt(0).getTop() >= mRefreshableView.getTop(); + } + } + + return false; + } + + public int getFristVisiblePosition() { + View firstVisibleChild = mRefreshableView.getChildAt(0); + return firstVisibleChild != null ? mRefreshableView.getChildPosition(firstVisibleChild) : -1; + } + + @Override + protected boolean isReadyForPullEnd() { + return isLastItemVisible(); + } + + public boolean isLastItemVisible() { + final RecyclerView.Adapter adapter = getRefreshableView().getAdapter(); + + //如果未设置Adapter或者Adpter没有数据可以下拉刷新 + if(null == adapter || adapter.getItemCount() == 0){ + return true; + }else{ + if(getLastVisiblePosition() == adapter.getItemCount() - 1){ + return mRefreshableView.getChildAt(mRefreshableView.getChildCount() - 1).getBottom() <= mRefreshableView.getBottom(); + } + } + + return false; + } + + public int getLastVisiblePosition() { + View lastVisibleChild = mRefreshableView.getChildAt(mRefreshableView.getChildCount() - 1); + return lastVisibleChild != null ? mRefreshableView.getChildPosition(lastVisibleChild) : -1; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/SMSValidEditText.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/SMSValidEditText.java new file mode 100644 index 0000000..cb0c62c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/SMSValidEditText.java @@ -0,0 +1,143 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.os.CountDownTimer; +import android.text.InputFilter; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; + +public class SMSValidEditText extends LinearLayout implements OnClickListener{ + + private final static int TIME = 60000 + 500; + + private EditText mSMSValidEt; + + private TextView mTimeCountTv; + + private TimeCount mTimeCount; + + private SMSValidOnclick mListener; + + public interface SMSValidOnclick{ + + public void requestValidateCode(); + } + + public void setSMSValidOnclick(SMSValidOnclick listener){ + mListener = listener; + } + + public SMSValidEditText(Context context) { + this(context, null); + } + + public SMSValidEditText(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SMSValidEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + LayoutInflater.from(context).inflate(R.layout.sms_valid_view, this); + initView(); + + mListener = new DefaultSMSValidOnclick(); + mTimeCount = new TimeCount(TIME, 1000); + + } + + public void startTimeCount(){ + mTimeCount.start(); + } + + private void initView() { + mSMSValidEt = findViewById(R.id.et_sms_valid); + + mTimeCountTv = findViewById(R.id.tv_sms_valid_tip); + + mTimeCountTv.setOnClickListener(this); + } + + public String getValidCode(){ + return mSMSValidEt.getText().toString(); + } + + public void setValidText(int valid){ + mTimeCount.cancel(); + mTimeCountTv.setText(valid); + mTimeCountTv.setEnabled(true); + mTimeCountTv.setClickable(true); + } + + class TimeCount extends CountDownTimer { + + public TimeCount(long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + } + + @Override + public void onTick(long millisUntilFinished) { + mTimeCountTv.setClickable(false); + mTimeCountTv.setEnabled(false); + millisUntilFinished -= 650; + mTimeCountTv.setText(getResources().getString(R.string.valid_code_retrieve_valid_num, millisUntilFinished / 1000)); + + if((millisUntilFinished / 1000) == 0){ + mTimeCountTv.setText(getResources().getString(R.string.device_manager_regain)); + mTimeCountTv.setEnabled(true); + mTimeCountTv.setClickable(true); + } + + } + + @Override + public void onFinish() { + mTimeCountTv.setText(getResources().getString(R.string.device_manager_regain)); + mTimeCountTv.setEnabled(true); + mTimeCountTv.setClickable(true); + + } + + } + + @Override + public void onClick(View v) { + mListener.requestValidateCode(); + } + + //取消倒计时 + public void cancelCountDown(){ + if(mTimeCount != null){ + mTimeCount.cancel(); + } + } + + public void addTextWatcher(TextWatcher watcher){ + mSMSValidEt.addTextChangedListener(watcher); + } + + public void setHintText(int hint){ + mSMSValidEt.setHint(hint); + } + + public void setFilters(InputFilter[] inputFilters) { + mSMSValidEt.setFilters(inputFilters); + } + + static class DefaultSMSValidOnclick implements SMSValidOnclick{ + + @Override + public void requestValidateCode() { + + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ScrollListView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ScrollListView.java new file mode 100644 index 0000000..00c83b1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ScrollListView.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ListView; + +public class ScrollListView extends ListView { + + public ScrollListView(Context context, AttributeSet attrs) { + super(context, attrs); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/Space.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/Space.java new file mode 100644 index 0000000..3d34618 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/Space.java @@ -0,0 +1,55 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +public class Space extends View { + + public Space(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + if (getVisibility() == VISIBLE) { + setVisibility(INVISIBLE); + } + } + + public Space(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public Space(Context context) { + this(context, null); + } + + /** + * Compare to: {@link View#getDefaultSize(int, int)} + * If mode is AT_MOST, return the child size instead of the parent size + * (unless it is too big). + */ + private static int getDefaultSize2(int size, int measureSpec) { + int result = size; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + switch (specMode) { + case MeasureSpec.UNSPECIFIED: + result = size; + break; + case MeasureSpec.AT_MOST: + result = Math.min(size, specSize); + break; + case MeasureSpec.EXACTLY: + result = specSize; + break; + } + return result; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension( + getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec), + getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec)); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/VerticalSeekBar.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/VerticalSeekBar.java new file mode 100644 index 0000000..731d246 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/VerticalSeekBar.java @@ -0,0 +1,206 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.support.v7.widget.AppCompatSeekBar; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewConfiguration; +import android.view.ViewParent; + +/** + * 垂直的seekbar + *

+ */ +public class VerticalSeekBar extends AppCompatSeekBar { + private boolean mIsDragging; + private float mTouchDownY; + private int mScaledTouchSlop; + private boolean isInScrollingContainer = false; + private OnSeekBarChangeListener mOnSeekBarChangeListener; + private boolean isInScrollingContainer() { + return isInScrollingContainer; + } + + public void setInScrollingContainer(boolean isInScrollingContainer) { + this.isInScrollingContainer = isInScrollingContainer; + } + + /** + * On touch, this offset plus the scaled value from the position of the + * touch will form the progress value. Usually 0. + */ + private float mTouchProgressOffset; + + public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + + } + + public VerticalSeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public VerticalSeekBar(Context context) { + super(context); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + + super.onSizeChanged(h, w, oldh, oldw); + + } + + @Override + protected synchronized void onMeasure(int widthMeasureSpec, + int heightMeasureSpec) { + super.onMeasure(heightMeasureSpec, widthMeasureSpec); + setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); + } + + @Override + protected synchronized void onDraw(Canvas canvas) { + canvas.rotate(-90); + canvas.translate(-getHeight(), 0); + super.onDraw(canvas); + } + + @Override + public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) { + super.setOnSeekBarChangeListener(l); + mOnSeekBarChangeListener = l; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!isEnabled()) { + return false; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (isInScrollingContainer()) { + + mTouchDownY = event.getY(); + } else { + setPressed(true); + + invalidate(); + onStartTrackingTouch(); + trackTouchEvent(event); + attemptClaimDrag(); + + onSizeChanged(getWidth(), getHeight(), 0, 0); + } + break; + + case MotionEvent.ACTION_MOVE: + if (mIsDragging) { + trackTouchEvent(event); + + } else { + final float y = event.getY(); + if (Math.abs(y - mTouchDownY) > mScaledTouchSlop) { + setPressed(true); + + invalidate(); + onStartTrackingTouch(); + trackTouchEvent(event); + attemptClaimDrag(); + + } + } + onSizeChanged(getWidth(), getHeight(), 0, 0); + break; + + case MotionEvent.ACTION_UP: + if (mIsDragging) { + trackTouchEvent(event); + onStopTrackingTouch(); + setPressed(false); + + } else { + // Touch up when we never crossed the touch slop threshold + // should + // be interpreted as a tap-seek to that location. + onStartTrackingTouch(); + trackTouchEvent(event); + onStopTrackingTouch(); + + } + onSizeChanged(getWidth(), getHeight(), 0, 0); + // ProgressBar doesn't know to repaint the thumb drawable + // in its inactive state when the touch stops (because the + // value has not apparently changed) + invalidate(); + break; + } + return true; + + } + + private void trackTouchEvent(MotionEvent event) { + final int height = getHeight(); + final int top = getPaddingTop(); + final int bottom = getPaddingBottom(); + final int available = height - top - bottom; + + int y = (int) event.getY(); + + float scale; + float progress = 0; + + // 下面是最小值 + if (y > height - bottom) { + scale = 0.0f; + } else if (y < top) { + scale = 1.0f; + } else { + scale = (float) (available - y + top) / (float) available; + progress = mTouchProgressOffset; + } + + final int max = getMax(); + progress += scale * max; + + setProgress((int) progress); + + } + + /** + * This is called when the user has started touching this widget. + */ + private void onStartTrackingTouch() { + mIsDragging = true; + if (mOnSeekBarChangeListener != null) + mOnSeekBarChangeListener.onStartTrackingTouch(this); + } + + /** + * This is called when the user either releases his touch or the touch is + * canceled. + */ + private void onStopTrackingTouch() { + mIsDragging = false; + if (mOnSeekBarChangeListener != null) + mOnSeekBarChangeListener.onStopTrackingTouch(this); + } + + private void attemptClaimDrag() { + ViewParent p = getParent(); + if (p != null) { + p.requestDisallowInterceptTouchEvent(true); + } + } + + @Override + public synchronized void setProgress(int progress) { + + super.setProgress(progress); + onSizeChanged(getWidth(), getHeight(), 0, 0); + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/WheelPicker.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/WheelPicker.java new file mode 100644 index 0000000..7e73ef8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/WheelPicker.java @@ -0,0 +1,965 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Handler; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.Scroller; + +import com.mm.android.deviceaddmodule.R; + +import java.text.Format; +import java.util.List; + +/** + * 滚动选择器 + */ +public class WheelPicker extends View { + + /** + * 数据集合 + */ + private List mDataList; + + private Format mDataFormat; + + /** + * Item的Text的颜色 + */ + @ColorInt + private int mTextColor; + + private int mTextSize; + + private Paint mTextPaint; + /** + * 字体渐变,开启后越靠近边缘,字体越模糊 + */ + private boolean mIsTextGradual; + + /** + * 选中的Item的Text颜色 + */ + @ColorInt + private int mSelectedItemTextColor; + + /** + * 选中的Item的Text大小 + */ + private int mSelectedItemTextSize; + + private Paint mSelectedItemPaint; + /** + * 指示器文字 + * 会在中心文字后边多绘制一个文字。 + */ + private String mIndicatorText; + + /** + * 指示器文字颜色 + */ + @ColorInt + private int mIndicatorTextColor; + + /** + * 指示器文字大小 + */ + private int mIndicatorTextSize; + + private int mIndicatorTextMargin; + + private Paint mIndicatorPaint; + + private Paint mPaint; + + /** + * 最大的一个Item的文本的宽高 + */ + private int mTextMaxWidth, mTextMaxHeight; + /** + * 输入的一段文字,可以用来测量 mTextMaxWidth + */ + private String mItemMaximumWidthText; + + /** + * 显示的Item一半的数量(中心Item上下两边分别的数量) + * 总显示的数量为 mHalfVisibleItemCount * 2 + 1 + */ + private int mHalfVisibleItemCount; + + /** + * 两个Item之间的高度间隔 + */ + private int mItemHeightSpace, mItemWidthSpace; + + private int mItemHeight; + + /** + * 当前的Item的位置 + */ + private int mCurrentPosition; + + /** + * 是否将中间的Item放大 + */ + private boolean mIsZoomInSelectedItem; + + /** + * 整个控件的可绘制面积 + */ + private Rect mDrawnRect; + + /** + * 中心被选中的Item的坐标矩形 + */ + private Rect mSelectedItemRect; + + /** + * 第一个Item的绘制Text的坐标 + */ + private int mFirstItemDrawX, mFirstItemDrawY; + + /** + * 中心的Item绘制text的Y轴坐标 + */ + private int mCenterItemDrawnY; + + private Scroller mScroller; + + private int mTouchSlop; + + /** + * 该标记的作用是,令mTouchSlop仅在一个滑动过程中生效一次。 + */ + private boolean mTouchSlopFlag; + + private VelocityTracker mTracker; + + private int mTouchDownY; + /** + * Y轴Scroll滚动的位移 + */ + private int mScrollOffsetY; + + /** + * 最后手指Down事件的Y轴坐标,用于计算拖动距离 + */ + private int mLastDownY; + + /** + * 是否循环读取 + */ + private boolean mIsCyclic = true; + + + /** + * 最大可以Fling的距离 + */ + private int mMaxFlingY, mMinFlingY; + + /** + * 选中边框的颜色 + */ + @ColorInt + private int mSelectedBorderColor; + + /** + * 滚轮滑动时的最小/最大速度 + */ + private int mMinimumVelocity = 50, mMaximumVelocity = 8888; + + /** + * 是否是手动停止滚动 + */ + private boolean mIsAbortScroller; + + private LinearGradient mLinearGradient; + + private Handler mHandler = new Handler(); + + private OnWheelChangeListener mOnWheelChangeListener; + + private Runnable mScrollerRunnable = new Runnable() { + @Override + public void run() { + + if (mScroller.computeScrollOffset()) { + + mScrollOffsetY = mScroller.getCurrY(); + postInvalidate(); + mHandler.postDelayed(this, 16); + } + if (mScroller.isFinished() || (mScroller.getFinalY() == mScroller.getCurrY() + && mScroller.getFinalX() == mScroller.getCurrX())) { + + if (mItemHeight == 0) { + return; + } + int position = -mScrollOffsetY / mItemHeight; + position = fixItemPosition(position); + if (mCurrentPosition != position) { + mCurrentPosition = position; + if (mOnWheelChangeListener == null) { + return; + } + mOnWheelChangeListener.onWheelSelected(mDataList.get(position), + position); + } + } + } + }; + + public WheelPicker(Context context) { + this(context, null); + } + + public WheelPicker(Context context, @Nullable AttributeSet attrs) { + this(context, attrs,0); + } + + public WheelPicker(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + initPaint(); + mLinearGradient = new LinearGradient(mTextColor, mSelectedItemTextColor); + mDrawnRect = new Rect(); + mSelectedItemRect = new Rect(); + mScroller = new Scroller(context); + + ViewConfiguration configuration = ViewConfiguration.get(context); + mTouchSlop = configuration.getScaledTouchSlop(); + } + + private void initAttrs(Context context, @Nullable AttributeSet attrs) { + if (attrs == null) { + return; + } + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WheelPicker); + mTextSize = a.getDimensionPixelSize(R.styleable.WheelPicker_itemTextSize, + getResources().getDimensionPixelSize(R.dimen.wheel_picker_text_size)); + mTextColor = a.getColor(R.styleable.WheelPicker_itemTextColor, + Color.BLACK); + mIsTextGradual = a.getBoolean(R.styleable.WheelPicker_textGradual, true); + mIsCyclic = a.getBoolean(R.styleable.WheelPicker_wheelCyclic, false); + mHalfVisibleItemCount = a.getInteger(R.styleable.WheelPicker_halfVisibleItemCount, 2); + mSelectedItemTextColor = a.getColor(R.styleable.WheelPicker_selectedTextColor, Color.BLACK); + try { + mSelectedItemTextSize = a.getDimensionPixelSize(R.styleable.WheelPicker_selectedTextSize, + getResources().getDimensionPixelSize(R.dimen.wheel_picker_selected_text_size)); + mCurrentPosition = a.getInteger(R.styleable.WheelPicker_currentItemPosition, 0); + mItemWidthSpace = a.getDimensionPixelSize(R.styleable.WheelPicker_itemWidthSpace, + getResources().getDimensionPixelOffset(R.dimen.mobile_common_dp_30)); + mItemHeightSpace = a.getDimensionPixelSize(R.styleable.WheelPicker_itemHeightSpace, + getResources().getDimensionPixelOffset(R.dimen.mobile_common_dp_6)); + mSelectedBorderColor = a.getColor(R.styleable.WheelPicker_selectedBorderColor, context.getResources().getColor(R.color.c51)); + } catch (Resources.NotFoundException e) { + e.printStackTrace(); + } + mIsZoomInSelectedItem = a.getBoolean(R.styleable.WheelPicker_zoomInSelectedItem, true); + mIndicatorText = a.getString(R.styleable.WheelPicker_indicatorText); + mIndicatorTextColor = a.getColor(R.styleable.WheelPicker_indicatorTextColor, mSelectedItemTextColor); + mIndicatorTextSize = a.getDimensionPixelSize(R.styleable.WheelPicker_indicatorTextSize, mTextSize); + mIndicatorTextMargin = 10; + a.recycle(); + } + + public void computeTextSize() { + mTextMaxWidth = mTextMaxHeight = 0; + if (mDataList.size() == 0) { + return; + } + + //这里使用最大的,防止文字大小超过布局大小。 + mPaint.setTextSize(mSelectedItemTextSize > mTextSize ? mSelectedItemTextSize : mTextSize); + + if (!TextUtils.isEmpty(mItemMaximumWidthText)) { + mTextMaxWidth = (int) mPaint.measureText(mItemMaximumWidthText); + } else { + mTextMaxWidth = (int) mPaint.measureText(mDataList.get(0).toString()); + } + Paint.FontMetrics metrics = mPaint.getFontMetrics(); + mTextMaxHeight = (int) (metrics.bottom - metrics.top); + } + + private void initPaint() { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG); + mTextPaint.setStyle(Paint.Style.FILL); + mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint.setColor(mTextColor); + mTextPaint.setTextSize(mTextSize); + mSelectedItemPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG); + mSelectedItemPaint.setStyle(Paint.Style.FILL); + mSelectedItemPaint.setTextAlign(Paint.Align.CENTER); + mSelectedItemPaint.setColor(mSelectedItemTextColor); + mSelectedItemPaint.setTextSize(mSelectedItemTextSize); + mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG); + mIndicatorPaint.setStyle(Paint.Style.FILL); + mIndicatorPaint.setTextAlign(Paint.Align.LEFT); + mIndicatorPaint.setColor(mIndicatorTextColor); + mIndicatorPaint.setTextSize(mIndicatorTextSize); + } + + /** + * 计算实际的大小 + * @param specMode 测量模式 + * @param specSize 测量的大小 + * @param size 需要的大小 + * @return 返回的数值 + */ + private int measureSize(int specMode, int specSize, int size) { + if (specMode == MeasureSpec.EXACTLY) { + return specSize; + } else { + return Math.min(specSize, size); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); + int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); + int specHeightSize = MeasureSpec.getSize(heightMeasureSpec); + int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); + + int width = mTextMaxWidth + mItemWidthSpace; + int height = (mTextMaxHeight + mItemHeightSpace) * getVisibleItemCount(); + + width += getPaddingLeft() + getPaddingRight(); + height += getPaddingTop() + getPaddingBottom(); + setMeasuredDimension(measureSize(specWidthMode, specWidthSize, width), + measureSize(specHeightMode, specHeightSize, height)); + } + + /** + * 计算Fling极限 + * 如果为Cyclic模式则为Integer的极限值,如果正常模式,则为一整个数据集的上下限。 + */ + private void computeFlingLimitY() { + mMinFlingY = mIsCyclic ? Integer.MIN_VALUE : + - mItemHeight * (mDataList.size() - 1); + mMaxFlingY = mIsCyclic ? Integer.MAX_VALUE : 0; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mDrawnRect.set(getPaddingLeft(), getPaddingTop(), + getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + mItemHeight = mDrawnRect.height() / getVisibleItemCount(); + mFirstItemDrawX = mDrawnRect.centerX(); + mFirstItemDrawY = (int) ((mItemHeight - (mSelectedItemPaint.ascent() + mSelectedItemPaint.descent())) / 2); + //中间的Item边框 + mSelectedItemRect.set(getPaddingLeft(), mItemHeight * mHalfVisibleItemCount, + getWidth() - getPaddingRight(), mItemHeight + mItemHeight * mHalfVisibleItemCount); + computeFlingLimitY(); + mCenterItemDrawnY = mFirstItemDrawY + mItemHeight * mHalfVisibleItemCount; + + mScrollOffsetY = -mItemHeight * mCurrentPosition; + } + + /** + * 修正坐标值,让其回到dateList的范围内 + * @param position 修正前的值 + * @return 修正后的值 + */ + private int fixItemPosition(int position) { + if (position < 0) { + //将数据集限定在0 ~ mDataList.size()-1之间 + position = mDataList.size() + (position % mDataList.size()); + + } + if (position >= mDataList.size()){ + //将数据集限定在0 ~ mDataList.size()-1之间 + position = position % mDataList.size(); + } + return position; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(mSelectedBorderColor); + canvas.drawRect(mSelectedItemRect, mPaint); + + if(mDrawnRect != null){ + canvas.drawRect(mDrawnRect, mPaint); + } + + + mPaint.setTextAlign(Paint.Align.CENTER); + int drawnSelectedPos = - mScrollOffsetY / mItemHeight; + mPaint.setStyle(Paint.Style.FILL); + //首尾各多绘制一个用于缓冲 + for (int drawDataPos = drawnSelectedPos - mHalfVisibleItemCount - 1; + drawDataPos <= drawnSelectedPos + mHalfVisibleItemCount + 1; drawDataPos++) { + int position = drawDataPos; + if (mIsCyclic) { + position = fixItemPosition(position); + } else { + if (position < 0 || position > mDataList.size() - 1) { + continue; + } + } + + T data = mDataList.get(position); + int itemDrawY = mFirstItemDrawY + (drawDataPos + mHalfVisibleItemCount) * mItemHeight + mScrollOffsetY; + //距离中心的Y轴距离 + int distanceY = Math.abs(mCenterItemDrawnY - itemDrawY); + + if (mIsTextGradual) { + //文字颜色渐变要在设置透明度上边,否则会被覆盖 + //计算文字颜色渐变 + if (distanceY < mItemHeight) { //距离中心的高度小于一个ItemHeight才会开启渐变 + float colorRatio = 1 - (distanceY / (float) mItemHeight); + mSelectedItemPaint.setColor(mLinearGradient.getColor(colorRatio)); + mTextPaint.setColor(mLinearGradient.getColor(colorRatio)); + } else { + mSelectedItemPaint.setColor(mSelectedItemTextColor); + mTextPaint.setColor(mTextColor); + } + //计算透明度渐变 + float alphaRatio; + if (itemDrawY > mCenterItemDrawnY && mDrawnRect != null) { + alphaRatio = (mDrawnRect.height() - itemDrawY) / + (float) (mDrawnRect.height() - (mCenterItemDrawnY)); + } else { + alphaRatio = itemDrawY / (float) mCenterItemDrawnY; + } + + alphaRatio = alphaRatio < 0 ? 0 :alphaRatio; + mSelectedItemPaint.setAlpha((int) (alphaRatio * 255)); + mTextPaint.setAlpha((int) (alphaRatio * 255)); + } + + //开启此选项,会将越靠近中心的Item字体放大 + if (mIsZoomInSelectedItem) { + if (distanceY < mItemHeight) { + float addedSize = (mItemHeight - distanceY) / (float) mItemHeight * (mSelectedItemTextSize - mTextSize); + mSelectedItemPaint.setTextSize(mTextSize + addedSize); + mTextPaint.setTextSize(mTextSize + addedSize); + } else { + mSelectedItemPaint.setTextSize(mTextSize); + mTextPaint.setTextSize(mTextSize); + } + } else { + mSelectedItemPaint.setTextSize(mTextSize); + mTextPaint.setTextSize(mTextSize); + } + String drawText = mDataFormat == null ? data.toString() : mDataFormat.format(data); + if (drawText == null) + drawText = ""; + + //文字超出部分省略号代替 + if (mDrawnRect != null) { + float width = Math.abs(mDrawnRect.right - mDrawnRect.left); + if (width > 0 && !TextUtils.isEmpty(drawText)) { + float textWidth = mTextPaint.measureText(drawText); + if (textWidth > width) { + int subIndex = mTextPaint.breakText(drawText, 0, drawText.length(), true, width, null); + if (subIndex > 3 && subIndex <= drawText.length()) + drawText = drawText.substring(0, subIndex - 3) + "..."; + } + } + } + + //在中间位置的Item作为被选中的。 + if (distanceY < mItemHeight / 2) { + canvas.drawText(drawText, mFirstItemDrawX, itemDrawY, mSelectedItemPaint); + } else { + canvas.drawText(drawText, mFirstItemDrawX, itemDrawY, mTextPaint); + } + } + if (!TextUtils.isEmpty(mIndicatorText)) { + canvas.drawText(mIndicatorText, mFirstItemDrawX + mTextMaxWidth / 2 + mIndicatorTextMargin, mCenterItemDrawnY, mIndicatorPaint); + } + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mTracker == null) { + mTracker = VelocityTracker.obtain(); + } + mTracker.addMovement(event); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (!mScroller.isFinished()) { + mScroller.abortAnimation(); + mIsAbortScroller = true; + } else { + mIsAbortScroller = false; + } + mTracker.clear(); + mTouchDownY = mLastDownY = (int) event.getY(); + mTouchSlopFlag = true; + break; + case MotionEvent.ACTION_MOVE: + if (mTouchSlopFlag && Math.abs(mTouchDownY - event.getY()) < mTouchSlop) { + break; + } + mTouchSlopFlag = false; + float move = event.getY() - mLastDownY; + move = (move * 6) / 10; //减少滚动的距离 + mScrollOffsetY += move; + mLastDownY = (int) event.getY(); + invalidate(); + break; + case MotionEvent.ACTION_UP: + if (!mIsAbortScroller && mTouchDownY == mLastDownY) { + performClick(); + if (event.getY() > mSelectedItemRect.bottom) { + int scrollItem = (int) (event.getY() - mSelectedItemRect.bottom) / mItemHeight + 1; + mScroller.startScroll(0, mScrollOffsetY, 0, + -scrollItem * mItemHeight); + + } else if (event.getY() < mSelectedItemRect.top) { + int scrollItem = (int) (mSelectedItemRect.top - event.getY()) / mItemHeight + 1; + mScroller.startScroll(0, mScrollOffsetY, 0, + scrollItem * mItemHeight); + } + } else { + mTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int velocity = (int) mTracker.getYVelocity(); + if (Math.abs(velocity) > mMinimumVelocity) { + mScroller.fling(0, mScrollOffsetY, 0, velocity, + 0, 0, mMinFlingY, mMaxFlingY); + mScroller.setFinalY(mScroller.getFinalY() + + computeDistanceToEndPoint(mScroller.getFinalY() % mItemHeight)); + } else { + mScroller.startScroll(0, mScrollOffsetY, 0, + computeDistanceToEndPoint(mScrollOffsetY % mItemHeight)); + } + } + if (!mIsCyclic) { + if (mScroller.getFinalY() > mMaxFlingY) { + mScroller.setFinalY(mMaxFlingY); + } else if (mScroller.getFinalY() < mMinFlingY) { + mScroller.setFinalY(mMinFlingY); + } + } + mHandler.post(mScrollerRunnable); + mTracker.recycle(); + mTracker = null; + break; + } + return true; + } + + @Override + public boolean performClick() { + return super.performClick(); + } + + private int computeDistanceToEndPoint(int remainder) { + if (Math.abs(remainder) > mItemHeight / 2) { + if (mScrollOffsetY < 0) { + return -mItemHeight - remainder; + } else { + return mItemHeight - remainder; + } + } else { + return -remainder; + } + } + + + public void setOnWheelChangeListener(OnWheelChangeListener onWheelChangeListener) { + mOnWheelChangeListener = onWheelChangeListener; + } + + public Paint getTextPaint() { + return mTextPaint; + } + + public Paint getSelectedItemPaint() { + return mSelectedItemPaint; + } + + public Paint getPaint() { + return mPaint; + } + + public Paint getIndicatorPaint() { + return mIndicatorPaint; + } + + public List getDataList() { + return mDataList; + } + + public void setDataList(@NonNull List dataList) { + mDataList = dataList; + if (dataList.size() == 0) { + return; + } + int maxWidth = 0; + for (T t:mDataList) { + int tem = (int) mPaint.measureText(t.toString()); + if (maxWidth < tem) { + maxWidth = tem; + mItemMaximumWidthText = t.toString(); + } + } + computeTextSize(); + computeFlingLimitY(); + requestLayout(); + postInvalidate(); + } + + public int getTextColor() { + return mTextColor; + } + + /** + * 一般列表的文本颜色 + * @param textColor 文本颜色 + */ + public void setTextColor(@ColorInt int textColor) { + if (mTextColor == textColor) { + return; + } + mTextPaint.setColor(textColor); + mTextColor = textColor; + mLinearGradient.setStartColor(textColor); + postInvalidate(); + } + + public int getTextSize() { + return mTextSize; + } + + /** + * 一般列表的文本大小 + * @param textSize 文字大小 + */ + public void setTextSize(int textSize) { + if (mTextSize == textSize) { + return; + } + mTextSize = textSize; + mTextPaint.setTextSize(textSize); + computeTextSize(); + postInvalidate(); + } + + public int getSelectedItemTextColor() { + return mSelectedItemTextColor; + } + + /** + * 设置被选中时候的文本颜色 + * @param selectedItemTextColor 文本颜色 + */ + public void setSelectedItemTextColor(@ColorInt int selectedItemTextColor) { + if (mSelectedItemTextColor == selectedItemTextColor) { + return; + } + mSelectedItemPaint.setColor(selectedItemTextColor); + mSelectedItemTextColor = selectedItemTextColor; + mLinearGradient.setEndColor(selectedItemTextColor); + postInvalidate(); + } + + public int getSelectedItemTextSize() { + return mSelectedItemTextSize; + } + + /** + * 设置被选中时候的文本大小 + * @param selectedItemTextSize 文字大小 + */ + public void setSelectedItemTextSize(int selectedItemTextSize) { + if (mSelectedItemTextSize == selectedItemTextSize) { + return; + } + mSelectedItemPaint.setTextSize(selectedItemTextSize); + mSelectedItemTextSize = selectedItemTextSize; + computeTextSize(); + postInvalidate(); + } + + + public String getItemMaximumWidthText() { + return mItemMaximumWidthText; + } + + /** + * 设置输入的一段文字,用来测量 mTextMaxWidth + * @param itemMaximumWidthText 文本内容 + */ + public void setItemMaximumWidthText(String itemMaximumWidthText) { + mItemMaximumWidthText = itemMaximumWidthText; + requestLayout(); + postInvalidate(); + } + + public int getHalfVisibleItemCount() { + return mHalfVisibleItemCount; + } + + /** + * 显示的个数等于上下两边Item的个数+ 中间的Item + * @return 总显示的数量 + */ + public int getVisibleItemCount() { + return mHalfVisibleItemCount * 2 + 1; + } + + /** + * 设置显示数据量的个数的一半。 + * 为保证总显示个数为奇数,这里将总数拆分,总数为 mHalfVisibleItemCount * 2 + 1 + * @param halfVisibleItemCount 总数量的一半 + */ + public void setHalfVisibleItemCount(int halfVisibleItemCount) { + if (mHalfVisibleItemCount == halfVisibleItemCount) { + return; + } + mHalfVisibleItemCount = halfVisibleItemCount; + requestLayout(); + } + + public int getItemWidthSpace() { + return mItemWidthSpace; + } + + public void setItemWidthSpace(int itemWidthSpace) { + if (mItemWidthSpace == itemWidthSpace) { + return; + } + mItemWidthSpace = itemWidthSpace; + requestLayout(); + } + + public int getItemHeightSpace() { + return mItemHeightSpace; + } + + /** + * 设置两个Item之间的间隔 + * @param itemHeightSpace 间隔值 + */ + public void setItemHeightSpace(int itemHeightSpace) { + if (mItemHeightSpace == itemHeightSpace) { + return; + } + mItemHeightSpace = itemHeightSpace; + requestLayout(); + } + + public int getCurrentPosition() { + return mCurrentPosition; + } + + /** + * 设置当前选中的列表项,将滚动到所选位置 + * @param currentPosition 设置的当前位置 + */ + public void setCurrentPosition(int currentPosition) { + setCurrentPosition(currentPosition, true); + } + + /** + * 设置当前选中的列表位置 + * @param currentPosition 设置的当前位置 + * @param smoothScroll 是否平滑滚动 + */ + public synchronized void setCurrentPosition(int currentPosition, boolean smoothScroll) { + if (currentPosition > mDataList.size() - 1) { + currentPosition = mDataList.size() - 1; + } + if (currentPosition < 0) { + currentPosition = 0; + } + if (mCurrentPosition == currentPosition) { + return; + } + if (!mScroller.isFinished()) { + mScroller.abortAnimation(); + } + + //如果mItemHeight=0代表还没有绘制完成,这时平滑滚动没有意义 + if (smoothScroll && mItemHeight > 0) { + mScroller.startScroll(0, mScrollOffsetY, 0, (mCurrentPosition - currentPosition) * mItemHeight); +// mScroller.setFinalY(mScroller.getFinalY() + +// computeDistanceToEndPoint(mScroller.getFinalY() % mItemHeight)); + int finalY = -currentPosition * mItemHeight; + mScroller.setFinalY(finalY); + mHandler.post(mScrollerRunnable); + } else { + mCurrentPosition = currentPosition; + mScrollOffsetY = -mItemHeight * mCurrentPosition; + postInvalidate(); + if (mOnWheelChangeListener != null) { + mOnWheelChangeListener.onWheelSelected(mDataList.get(currentPosition), currentPosition); + } + } + } + + public boolean isZoomInSelectedItem() { + return mIsZoomInSelectedItem; + } + + public void setZoomInSelectedItem(boolean zoomInSelectedItem) { + if (mIsZoomInSelectedItem == zoomInSelectedItem) { + return; + } + mIsZoomInSelectedItem = zoomInSelectedItem; + postInvalidate(); + } + + public boolean isCyclic() { + return mIsCyclic; + } + + /** + * 设置是否循环滚动。 + * @param cyclic 上下边界是否相邻 + */ + public void setCyclic(boolean cyclic) { + if (mIsCyclic == cyclic) { + return; + } + mIsCyclic = cyclic; + computeFlingLimitY(); + requestLayout(); + } + + public int getMinimumVelocity() { + return mMinimumVelocity; + } + + /** + * 设置最小滚动速度,如果实际速度小于此速度,将不会触发滚动。 + * @param minimumVelocity 最小速度 + */ + public void setMinimumVelocity(int minimumVelocity) { + mMinimumVelocity = minimumVelocity; + } + + public int getMaximumVelocity() { + return mMaximumVelocity; + } + + /** + * 设置最大滚动的速度,实际滚动速度的上限 + * @param maximumVelocity 最大滚动速度 + */ + public void setMaximumVelocity(int maximumVelocity) { + mMaximumVelocity = maximumVelocity; + } + + public boolean isTextGradual() { + return mIsTextGradual; + } + + /** + * 设置文字渐变,离中心越远越淡。 + * @param textGradual 是否渐变 + */ + public void setTextGradual(boolean textGradual) { + if (mIsTextGradual == textGradual) { + return; + } + mIsTextGradual = textGradual; + postInvalidate(); + } + + public void setIndicatorText(String indicatorText) { + mIndicatorText = indicatorText; + postInvalidate(); + } + + public void setIndicatorTextColor(int indicatorTextColor) { + mIndicatorTextColor = indicatorTextColor; + mIndicatorPaint.setColor(mIndicatorTextColor); + postInvalidate(); + } + + public void setIndicatorTextSize(int indicatorTextSize) { + mIndicatorTextSize = indicatorTextSize; + mIndicatorPaint.setTextSize(mIndicatorTextSize); + postInvalidate(); + } + + /** + * 设置数据集格式 + * @param dataFormat 格式 + */ + public void setDataFormat(Format dataFormat) { + mDataFormat = dataFormat; + postInvalidate(); + } + + public Format getDataFormat() { + return mDataFormat; + } + + public interface OnWheelChangeListener { + void onWheelSelected(T item, int position); + } + + /** + * 颜色线性渐变工具 + * Created by ycuwq on 2018/1/6. + */ + private class LinearGradient { + private int mStartColor; + private int mEndColor; + private int mRedStart; + private int mBlueStart; + private int mGreenStart; + private int mRedEnd; + private int mBlueEnd; + private int mGreenEnd; + + private LinearGradient(@ColorInt int startColor, @ColorInt int endColor) { + mStartColor = startColor; + mEndColor = endColor; + updateColor(); + } + + public void setStartColor(@ColorInt int startColor) { + mStartColor = startColor; + updateColor(); + } + + public void setEndColor(@ColorInt int endColor) { + mEndColor = endColor; + updateColor(); + } + + private void updateColor() { + mRedStart = Color.red(mStartColor); + mBlueStart = Color.blue(mStartColor); + mGreenStart = Color.green(mStartColor); + mRedEnd = Color.red(mEndColor); + mBlueEnd = Color.blue(mEndColor); + mGreenEnd = Color.green(mEndColor); + } + + public int getColor(float ratio) { + int red = (int) (mRedStart + ((mRedEnd - mRedStart) * ratio + 0.3)); + int greed = (int) (mGreenStart + ((mGreenEnd - mGreenStart) * ratio + 0.3)); + int blue = (int) (mBlueStart + ((mBlueEnd - mBlueStart) * ratio + 0.3)); + return Color.argb(125,red, greed, blue); + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ZoomInScrollView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ZoomInScrollView.java new file mode 100644 index 0000000..ad2f9f5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/ZoomInScrollView.java @@ -0,0 +1,166 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.ScrollView; + +public class ZoomInScrollView extends ScrollView { + private View mHeaderView; + private int mHeaderWidth; + private int mHeaderHeight; + /** + * 是否正在下拉 + */ + private boolean mIsPulling; + private int mLastY; + //滑动放大系数,系数越大,滑动时放大程度越大 + private float mScaleRatio = 0.4f; + // 最大的放大倍数 + private float mScaleTimes = 2.0f; + // 回弹时间系数,系数越小,回弹越快 + private float mReplyRatio = 0.5f; + + public ZoomInScrollView(Context context) { + this(context, null); + } + + public ZoomInScrollView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ZoomInScrollView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mSlop = ViewConfiguration.get(context).getScaledEdgeSlop(); + } + + public void setHeaderView(View headerView) { + mHeaderView = headerView; + mHeaderWidth = mHeaderView.getMeasuredWidth(); + mHeaderHeight = mHeaderView.getMeasuredHeight(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + //设置不可过度滚动,否则上移后下拉会出现部分空白的情况 + setOverScrollMode(OVER_SCROLL_NEVER); + View child = getChildAt(0); + if (child != null && child instanceof ViewGroup) { + //获取默认第一个子View + mHeaderView = ((ViewGroup) child).getChildAt(0); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mHeaderWidth = mHeaderView.getMeasuredWidth(); + mHeaderHeight = mHeaderView.getMeasuredHeight(); + } + + private float mDownX; + private float mDownY; + private int mSlop; + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + switch (ev.getAction()){ + case MotionEvent.ACTION_DOWN: + mDownX = ev.getX(); + mDownY = ev.getY(); + break; + case MotionEvent.ACTION_MOVE: + if(Math.abs(Math.abs(ev.getX() - mDownX)) > mSlop || Math.abs(Math.abs(ev.getY() - mDownY)) > mSlop ){ + return true; + } + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (mHeaderView == null) + return super.onTouchEvent(ev); + switch (ev.getAction()) { + case MotionEvent.ACTION_MOVE: + if (!mIsPulling) { + //第一次下拉 + if (getScrollY() == 0) { + //在顶部的时候,记录顶部位置 + mLastY = (int) ev.getY(); + } else { + break; + } + } + if (ev.getY() - mLastY < 0) + return super.onTouchEvent(ev); + int distance = (int) ((ev.getY() - mLastY) * mScaleRatio); + mIsPulling = true; + setZoom(distance); + return true; + case MotionEvent.ACTION_UP: + mIsPulling = false; + replyView(); + break; + } + return super.onTouchEvent(ev); + } + + /** + * 放大view + */ + private void setZoom(float s) { + float scaleTimes = (float) ((mHeaderWidth + s) / (mHeaderWidth * 1.0)); +// 如超过最大放大倍数,直接返回 + if (scaleTimes > mScaleTimes) return; + + ViewGroup.LayoutParams layoutParams = mHeaderView.getLayoutParams(); + layoutParams.width = (int) (mHeaderWidth + s); + layoutParams.height = (int) (mHeaderHeight * ((mHeaderWidth + s) / mHeaderWidth)); +// 设置控件水平居中 + ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - mHeaderWidth) / 2, 0, 0, 0); + mHeaderView.setLayoutParams(layoutParams); + } + + /** + * 回弹 + */ + private void replyView() { + final float distance = mHeaderView.getMeasuredWidth() - mHeaderWidth; + // 设置动画 + ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio)); + anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + setZoom((Float) animation.getAnimatedValue()); + } + }); + anim.start(); + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + if (onScrollListener != null) onScrollListener.onScroll(l, t, oldl, oldt); + } + + private OnScrollListener onScrollListener; + + public void setOnScrollListener(OnScrollListener onScrollListener) { + this.onScrollListener = onScrollListener; + } + + /** + * 滑动监听 + */ + public interface OnScrollListener { + void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheel.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheel.java new file mode 100644 index 0000000..22a0d20 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheel.java @@ -0,0 +1,864 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.LinearLayout; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters.WheelViewAdapter; + +import java.util.LinkedList; +import java.util.List; + + +/** + * Abstract spinner spinnerwheel view + * This class should be subclassed. + * + + */ +public abstract class AbstractWheel extends View { + + private static int itemID = -1; + + @SuppressWarnings("unused") + private final String LOG_TAG = AbstractWheel.class.getName() + " #" + (++itemID); + + //---------------------------------- + // Default properties values + //---------------------------------- + + /** Default count of visible items */ + private static final int DEF_VISIBLE_ITEMS = 4; + private static final boolean DEF_IS_CYCLIC = false; + + //---------------------------------- + // Class properties + //---------------------------------- + + protected int mCurrentItemIdx = 0; + + // Count of visible items + protected int mVisibleItems; + // Should all items be visible + protected boolean mIsAllVisible; + + protected boolean mIsCyclic; + + // Scrolling + protected WheelScroller mScroller; + protected boolean mIsScrollingPerformed; + protected int mScrollingOffset; + + // Items layout + protected LinearLayout mItemsLayout; + + // The number of first item in layout + protected int mFirstItemIdx; + + // View adapter + protected WheelViewAdapter mViewAdapter; + + protected int mLayoutHeight; + protected int mLayoutWidth; + + // Recycle + private WheelRecycler mRecycler = new WheelRecycler(this); + + // Listeners + private List changingListeners = new LinkedList<>(); + private List scrollingListeners = new LinkedList<>(); + private List clickingListeners = new LinkedList<>(); + + //XXX: I don't like listeners the way as they are now. -df + + // Adapter listener + private DataSetObserver mDataObserver; + + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Create a new AbstractWheel instance + * + * @param context the application environment. + * @param attrs a collection of attributes. + * @param defStyle The default style to apply to this view. + */ + public AbstractWheel(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + initAttributes(attrs, defStyle); + initData(context); + } + + //-------------------------------------------------------------------------- + // + // Initiating data and assets at start up + // + //-------------------------------------------------------------------------- + + /** + * Initiates data and parameters from styles + * + * @param attrs a collection of attributes. + * @param defStyle The default style to apply to this view. + */ + protected void initAttributes(AttributeSet attrs, int defStyle) { + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MobileCommonAbstractWheelView, defStyle, 0); + mVisibleItems = a.getInt(R.styleable.MobileCommonAbstractWheelView_visibleItems, DEF_VISIBLE_ITEMS); + mIsAllVisible = a.getBoolean(R.styleable.MobileCommonAbstractWheelView_isAllVisible, false); + mIsCyclic = a.getBoolean(R.styleable.MobileCommonAbstractWheelView_isCyclic, DEF_IS_CYCLIC); + + a.recycle(); + } + + /** + * Initiates data + * + * @param context the context + */ + protected void initData(Context context) { + + mDataObserver = new DataSetObserver() { + @Override + public void onChanged() { + invalidateItemsLayout(false); + } + + @Override + public void onInvalidated() { + invalidateItemsLayout(true); + } + }; + + // creating new scroller + mScroller = createScroller(new WheelScroller.ScrollingListener() { + + public void onStarted() { + mIsScrollingPerformed = true; + notifyScrollingListenersAboutStart(); + onScrollStarted(); + } + + public void onTouch() { + onScrollTouched(); + } + + public void onTouchUp() { + if (!mIsScrollingPerformed) + onScrollTouchedUp(); // if scrolling IS performed, whe should use onFinished instead + } + + public void onScroll(int distance) { + doScroll(distance); + + int dimension = getBaseDimension(); + if (mScrollingOffset > dimension) { + mScrollingOffset = dimension; + mScroller.stopScrolling(); + } else if (mScrollingOffset < - dimension) { + mScrollingOffset = - dimension; + mScroller.stopScrolling(); + } + } + + public void onFinished() { + if (mIsScrollingPerformed) { + notifyScrollingListenersAboutEnd(); + mIsScrollingPerformed = false; + onScrollFinished(); + } + + mScrollingOffset = 0; + invalidate(); + } + + public void onJustify() { + if (Math.abs(mScrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) { + mScroller.scroll(mScrollingOffset, 0); + } + } + }); + } + + @Override + public Parcelable onSaveInstanceState() { + //begin boilerplate code that allows parent classes to save state + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + //end + + ss.currentItem = this.getCurrentItem(); + + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + //begin boilerplate code so parent classes can restore state + if(!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + final SavedState ss = (SavedState)state; + super.onRestoreInstanceState(ss.getSuperState()); + //end + + mCurrentItemIdx = ss.currentItem; + + // dirty hack to re-draw child items correctly + postDelayed(new Runnable() { + @Override + public void run() { + invalidateItemsLayout(false); + } + }, 100); + } + + static class SavedState extends BaseSavedState { + int currentItem; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + this.currentItem = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(this.currentItem); + } + + //required field that makes Parcelables from a Parcel + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + abstract protected void recreateAssets(int width, int height); + + abstract public void removeBitmap(); + + //-------------------------------------------------------------------------- + // + // Scroller operations + // + //-------------------------------------------------------------------------- + + /** + * Creates scroller appropriate for specific wheel implementation. + * + * @param scrollingListener listener to be passed to the scroller + * @return Initialized scroller to be used + */ + abstract protected WheelScroller createScroller(WheelScroller.ScrollingListener scrollingListener); + + /* These methods are not abstract, as we may want to override only some of them */ + protected void onScrollStarted() {} + protected void onScrollTouched() {} + protected void onScrollTouchedUp() {} + protected void onScrollFinished() {} + + /** + * Stops scrolling + */ + public void stopScrolling() { + mScroller.stopScrolling(); + } + + /** + * Set the the specified scrolling interpolator + * @param interpolator the interpolator + */ + public void setInterpolator(Interpolator interpolator) { + mScroller.setInterpolator(interpolator); + } + + /** + * Scroll the spinnerwheel + * @param itemsToScroll items to scroll + * @param time scrolling duration + */ + public void scroll(int itemsToScroll, int time) { + int distance = itemsToScroll * getItemDimension() - mScrollingOffset; + onScrollTouched(); // we have to emulate touch when scrolling spinnerwheel programmatically to light up stuff + mScroller.scroll(distance, time); + } + + /** + * Scrolls the spinnerwheel + * @param delta the scrolling value + */ + private void doScroll(int delta) { + mScrollingOffset += delta; + + int itemDimension = getItemDimension(); + int count = mScrollingOffset / itemDimension; + + int pos = mCurrentItemIdx - count; + int itemCount = mViewAdapter.getItemsCount(); + + int fixPos = mScrollingOffset % itemDimension; + if (Math.abs(fixPos) <= itemDimension / 2) { + fixPos = 0; + } + if (mIsCyclic && itemCount > 0) { + if (fixPos > 0) { + pos--; + count++; + } else if (fixPos < 0) { + pos++; + count--; + } + // fix position by rotating + while (pos < 0) { + pos += itemCount; + } + pos %= itemCount; + } else { + if (pos < 0) { + count = mCurrentItemIdx; + pos = 0; + } else if (pos >= itemCount) { + count = mCurrentItemIdx - itemCount + 1; + pos = itemCount - 1; + } else if (pos > 0 && fixPos > 0) { + pos--; + count++; + } else if (pos < itemCount - 1 && fixPos < 0) { + pos++; + count--; + } + } + + int offset = mScrollingOffset; + if (pos != mCurrentItemIdx) { + setCurrentItem(pos, false); + } else { + invalidate(); + } + + // update offset + int baseDimension = getBaseDimension(); + mScrollingOffset = offset - count * itemDimension; + if (mScrollingOffset > baseDimension) { + mScrollingOffset = mScrollingOffset % baseDimension + baseDimension; + } + } + + //-------------------------------------------------------------------------- + // + // Base measurements + // + //-------------------------------------------------------------------------- + + /** + * Returns base dimension of the spinnerwheel — width for horizontal spinnerwheel, height for + * vertical + * + * @return width or height of the spinnerwheel + */ + abstract protected int getBaseDimension(); + + /** + * Returns base dimension of base item — width for horizontal spinnerwheel, height for vertical + * + * @return width or height of base item + */ + abstract protected int getItemDimension(); + + /** + * Processes MotionEvent and returns relevant position — x for horizontal spinnerwheel, y for + * vertical + * + * @param event + * MotionEvent to be processed + * @return relevant position of the MotionEvent + */ + abstract protected float getMotionEventPosition(MotionEvent event); + + + //-------------------------------------------------------------------------- + // + // Layout creation and measurement operations + // + //-------------------------------------------------------------------------- + + /** + * Creates item layouts if necessary + */ + abstract protected void createItemsLayout(); + + /** + * Sets layout width and height + */ + abstract protected void doItemsLayout(); + + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (changed) { + int w = r - l; + int h = b - t; + doItemsLayout(); + if (mLayoutWidth != w || mLayoutHeight != h) { + recreateAssets(getMeasuredWidth(), getMeasuredHeight()); + } + mLayoutWidth = w; + mLayoutHeight = h; + } + } + + /** + * Invalidates items layout + * + * @param clearCaches if true then cached views will be cleared + */ + public void invalidateItemsLayout(boolean clearCaches) { + if (clearCaches) { + mRecycler.clearAll(); + if (mItemsLayout != null) { + mItemsLayout.removeAllViews(); + } + mScrollingOffset = 0; + } else if (mItemsLayout != null) { + // cache all items + mRecycler.recycleItems(mItemsLayout, mFirstItemIdx, new ItemsRange()); + } + invalidate(); + } + + + //-------------------------------------------------------------------------- + // + // Getters and setters + // + //-------------------------------------------------------------------------- + + /** + * Gets count of visible items + * + * @return the count of visible items + */ + public int getVisibleItems() { + return mVisibleItems; + } + + /** + * Sets the desired count of visible items. + * Actual amount of visible items depends on spinnerwheel layout parameters. + * To apply changes and rebuild view call measure(). + * + * @param count the desired count for visible items + */ + public void setVisibleItems(int count) { + mVisibleItems = count; + } + + /** + * Sets all items to have no dim and makes them visible + * @param isAllVisible + */ + public void setAllItemsVisible(boolean isAllVisible){ + mIsAllVisible = isAllVisible; + invalidateItemsLayout(false); + } + + /** + * Gets view adapter + * @return the view adapter + */ + public WheelViewAdapter getViewAdapter() { + return mViewAdapter; + } + + + /** + * Sets view adapter. Usually new adapters contain different views, so + * it needs to rebuild view by calling measure(). + * + * @param viewAdapter the view adapter + */ + public void setViewAdapter(WheelViewAdapter viewAdapter) { + if (this.mViewAdapter != null) { + this.mViewAdapter.unregisterDataSetObserver(mDataObserver); + } + this.mViewAdapter = viewAdapter; + if (this.mViewAdapter != null) { + this.mViewAdapter.registerDataSetObserver(mDataObserver); + } + invalidateItemsLayout(true); + } + + /** + * Gets current value + * + * @return the current value + */ + public int getCurrentItem() { + return mCurrentItemIdx; + } + + /** + * Sets the current item. Does nothing when index is wrong. + * + * @param index the item index + * @param animated the animation flag + */ + public void setCurrentItem(int index, boolean animated) { + if (mViewAdapter == null || mViewAdapter.getItemsCount() == 0) { + return; // throw? + } + + int itemCount = mViewAdapter.getItemsCount(); + if (index < 0 || index >= itemCount) { + if (mIsCyclic) { + while (index < 0) { + index += itemCount; + } + index %= itemCount; + } else{ + return; // throw? + } + } + if (index != mCurrentItemIdx) { + if (animated) { + int itemsToScroll = index - mCurrentItemIdx; + if (mIsCyclic) { + int scroll = itemCount + Math.min(index, mCurrentItemIdx) - Math.max(index, mCurrentItemIdx); + if (scroll < Math.abs(itemsToScroll)) { + itemsToScroll = itemsToScroll < 0 ? scroll : -scroll; + } + } + scroll(itemsToScroll, 0); + } else { + mScrollingOffset = 0; + final int old = mCurrentItemIdx; + mCurrentItemIdx = index; + notifyChangingListeners(old, mCurrentItemIdx); + invalidate(); + } + } + } + + /** + * Sets the current item w/o animation. Does nothing when index is wrong. + * + * @param index the item index + */ + public void setCurrentItem(int index) { + setCurrentItem(index, false); + } + + /** + * Tests if spinnerwheel is cyclic. That means before the 1st item there is shown the last one + * @return true if spinnerwheel is cyclic + */ + public boolean isCyclic() { + return mIsCyclic; + } + + /** + * Set spinnerwheel cyclic flag + * @param isCyclic the flag to set + */ + public void setCyclic(boolean isCyclic) { + this.mIsCyclic = isCyclic; + invalidateItemsLayout(false); + } + + + //-------------------------------------------------------------------------- + // + // Listener operations + // + //-------------------------------------------------------------------------- + + /** + * Adds spinnerwheel changing listener + * @param listener the listener + */ + public void addChangingListener(OnWheelChangedListener listener) { + changingListeners.add(listener); + } + + /** + * Removes spinnerwheel changing listener + * @param listener the listener + */ + public void removeChangingListener(OnWheelChangedListener listener) { + changingListeners.remove(listener); + } + + /** + * Notifies changing listeners + * @param oldValue the old spinnerwheel value + * @param newValue the new spinnerwheel value + */ + protected void notifyChangingListeners(int oldValue, int newValue) { + for (OnWheelChangedListener listener : changingListeners) { + listener.onChanged(this, oldValue, newValue); + } + } + + /** + * Adds spinnerwheel scrolling listener + * @param listener the listener + */ + public void addScrollingListener(OnWheelScrollListener listener) { + scrollingListeners.add(listener); + } + + /** + * Removes spinnerwheel scrolling listener + * @param listener the listener + */ + public void removeScrollingListener(OnWheelScrollListener listener) { + scrollingListeners.remove(listener); + } + + /** + * Notifies listeners about starting scrolling + */ + protected void notifyScrollingListenersAboutStart() { + for (OnWheelScrollListener listener : scrollingListeners) { + listener.onScrollingStarted(this); + } + } + + /** + * Notifies listeners about ending scrolling + */ + protected void notifyScrollingListenersAboutEnd() { + for (OnWheelScrollListener listener : scrollingListeners) { + listener.onScrollingFinished(this); + } + } + + /** + * Adds spinnerwheel clicking listener + * @param listener the listener + */ + public void addClickingListener(OnWheelClickedListener listener) { + clickingListeners.add(listener); + } + + /** + * Removes spinnerwheel clicking listener + * @param listener the listener + */ + public void removeClickingListener(OnWheelClickedListener listener) { + clickingListeners.remove(listener); + } + + /** + * Notifies listeners about clicking + * @param item clicked item + */ + protected void notifyClickListenersAboutClick(int item) { + for (OnWheelClickedListener listener : clickingListeners) { + listener.onItemClicked(this, item); + } + } + + + //-------------------------------------------------------------------------- + // + // Rebuilding items + // + //-------------------------------------------------------------------------- + + /** + * Rebuilds spinnerwheel items if necessary. Caches all unused items. + * + * @return true if items are rebuilt + */ + protected boolean rebuildItems() { + boolean updated; + ItemsRange range = getItemsRange(); + + if (mItemsLayout != null) { + int first = mRecycler.recycleItems(mItemsLayout, mFirstItemIdx, range); + updated = mFirstItemIdx != first; + mFirstItemIdx = first; + } else { + createItemsLayout(); + updated = true; + } + + if (!updated) { + updated = mFirstItemIdx != range.getFirst() || mItemsLayout.getChildCount() != range.getCount(); + } + + if (mFirstItemIdx > range.getFirst() && mFirstItemIdx <= range.getLast()) { + for (int i = mFirstItemIdx - 1; i >= range.getFirst(); i--) { + if (!addItemView(i, true)) { + break; + } + mFirstItemIdx = i; + } + } else { + mFirstItemIdx = range.getFirst(); + } + + int first = mFirstItemIdx; + for (int i = mItemsLayout.getChildCount(); i < range.getCount(); i++) { + if (!addItemView(mFirstItemIdx + i, false) && mItemsLayout.getChildCount() == 0) { + first++; + } + } + mFirstItemIdx = first; + + return updated; + } + + //---------------------------------- + // ItemsRange operations + //---------------------------------- + + /** + * Calculates range for spinnerwheel items + * @return the items range + */ + private ItemsRange getItemsRange() { + if (mIsAllVisible) { + int baseDimension = getBaseDimension(); + int itemDimension = getItemDimension(); + if (itemDimension != 0) + mVisibleItems = baseDimension / itemDimension + 1; + } + + int start = mCurrentItemIdx - mVisibleItems / 2; + int end = start + mVisibleItems - (mVisibleItems % 2 == 0 ? 0 : 1); + if (mScrollingOffset != 0) { + if (mScrollingOffset > 0) { + start--; + } else { + end++; + } + } + if (!isCyclic()) { + if (start < 0) + start = 0; + if (mViewAdapter != null && end > mViewAdapter.getItemsCount()) + end = mViewAdapter.getItemsCount(); + } + return new ItemsRange(start, end - start + 1); + } + + /** + * Checks whether item index is valid + * @param index the item index + * @return true if item index is not out of bounds or the spinnerwheel is cyclic + */ + protected boolean isValidItemIndex(int index) { + return (mViewAdapter != null) && (mViewAdapter.getItemsCount() > 0) && + (mIsCyclic || (index >= 0 && index < mViewAdapter.getItemsCount())); + } + + //---------------------------------- + // Operations with item view + //---------------------------------- + + /** + * Adds view for item to items layout + * @param index the item index + * @param first the flag indicates if view should be first + * @return true if corresponding item exists and is added + */ + private boolean addItemView(int index, boolean first) { + View view = getItemView(index); + if (view != null) { + if (first) { + mItemsLayout.addView(view, 0); + } else { + mItemsLayout.addView(view); + } + return true; + } + return false; + } + + /** + * Returns view for specified item + * @param index the item index + * @return item view or empty view if index is out of bounds + */ + private View getItemView(int index) { + if (mViewAdapter == null || mViewAdapter.getItemsCount() == 0) { + return null; + } + int count = mViewAdapter.getItemsCount(); + if (!isValidItemIndex(index)) { + return mViewAdapter.getEmptyItem( mRecycler.getEmptyItem(), mItemsLayout); + } else { + while (index < 0) { + index = count + index; + } + } + index %= count; + return mViewAdapter.getItem(index, mRecycler.getItem(), mItemsLayout); + } + + + //-------------------------------------------------------------------------- + // + // Intercepting and processing touch event + // + //-------------------------------------------------------------------------- + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!isEnabled() || getViewAdapter() == null) { + return true; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + break; + + case MotionEvent.ACTION_UP: + if (!mIsScrollingPerformed) { + int distance = (int) getMotionEventPosition(event) - getBaseDimension() / 2; + if (distance > 0) { + distance += getItemDimension() / 2; + } else { + distance -= getItemDimension() / 2; + } + int items = distance / getItemDimension(); + if (items != 0 && isValidItemIndex(mCurrentItemIdx + items)) { + notifyClickListenersAboutClick(mCurrentItemIdx + items); + } + } + break; + } + return mScroller.onTouchEvent(event); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheelView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheelView.java new file mode 100644 index 0000000..86fa730 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/AbstractWheelView.java @@ -0,0 +1,299 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.drawable.Drawable; +import android.support.annotation.Keep; +import android.util.AttributeSet; + +import com.mm.android.deviceaddmodule.R; + + +/** + * Abstract spinner spinnerwheel view. + * This class should be subclassed. + * + */ +public abstract class AbstractWheelView extends AbstractWheel { + + private static int itemID = -1; + + @SuppressWarnings("unused") + private final String LOG_TAG = AbstractWheelView.class.getName() + " #" + (++itemID); + + //---------------------------------- + // Default properties values + //---------------------------------- + + protected static final int DEF_ITEMS_DIMMED_ALPHA = 50; // 60 in ICS + + protected static final int DEF_SELECTION_DIVIDER_ACTIVE_ALPHA = 70; + + protected static final int DEF_SELECTION_DIVIDER_DIMMED_ALPHA = 255; + + protected static final int DEF_ITEM_OFFSET_PERCENT = 10; + + protected static final int DEF_ITEM_PADDING = 10; + + protected static final int DEF_SELECTION_DIVIDER_SIZE = 2; + + //---------------------------------- + // Class properties + //---------------------------------- + + // configurable properties + + /** The alpha of the selector spinnerwheel when it is dimmed. */ + protected int mItemsDimmedAlpha; + + /** The alpha of separators spinnerwheel when they are shown. */ + protected int mSelectionDividerActiveAlpha; + + /** The alpha of separators when they are is dimmed. */ + protected int mSelectionDividerDimmedAlpha; + + /** Top and bottom items offset */ + protected int mItemOffsetPercent; + + /** Left and right padding value */ + protected int mItemsPadding; + + /** Divider for showing item to be selected while scrolling */ + protected Drawable mSelectionDivider; + + // the rest + + /** + * The {@link android.graphics.Paint} for drawing the selector. + */ + protected Paint mSelectorWheelPaint; + + /** + * The {@link android.graphics.Paint} for drawing the separators. + */ + protected Paint mSeparatorsPaint; + + protected Animator mDimSelectorWheelAnimator; + + protected Animator mDimSeparatorsAnimator; + + /** + * The property for setting the selector paint. + */ + protected static final String PROPERTY_SELECTOR_PAINT_COEFF = "selectorPaintCoeff"; + + /** + * The property for setting the separators paint. + */ + protected static final String PROPERTY_SEPARATORS_PAINT_ALPHA = "separatorsPaintAlpha"; + + + protected Bitmap mSpinBitmap; +// protected Bitmap mSeparatorsBitmap; + + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + public AbstractWheelView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + //-------------------------------------------------------------------------- + // + // Initiating assets and setters for paints + // + //-------------------------------------------------------------------------- + + @Override + protected void initAttributes(AttributeSet attrs, int defStyle) { + super.initAttributes(attrs, defStyle); + + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MobileCommonAbstractWheelView, defStyle, 0); + mItemsDimmedAlpha = a.getInt(R.styleable.MobileCommonAbstractWheelView_itemsDimmedAlpha, DEF_ITEMS_DIMMED_ALPHA); + mSelectionDividerActiveAlpha = a.getInt(R.styleable.MobileCommonAbstractWheelView_selectionDividerActiveAlpha, DEF_SELECTION_DIVIDER_ACTIVE_ALPHA); + mSelectionDividerDimmedAlpha = a.getInt(R.styleable.MobileCommonAbstractWheelView_selectionDividerDimmedAlpha, DEF_SELECTION_DIVIDER_DIMMED_ALPHA); + mItemOffsetPercent = a.getInt(R.styleable.MobileCommonAbstractWheelView_itemOffsetPercent, DEF_ITEM_OFFSET_PERCENT); + mItemsPadding = a.getDimensionPixelSize(R.styleable.MobileCommonAbstractWheelView_itemsPadding, DEF_ITEM_PADDING); + mSelectionDivider = a.getDrawable(R.styleable.MobileCommonAbstractWheelView_selectionDivider); + a.recycle(); + } + + @Override + protected void initData(Context context) { + super.initData(context); + + // creating animators + mDimSelectorWheelAnimator = ObjectAnimator.ofFloat(this, PROPERTY_SELECTOR_PAINT_COEFF, 1, 0); + + mDimSeparatorsAnimator = ObjectAnimator.ofInt(this, PROPERTY_SEPARATORS_PAINT_ALPHA, + mSelectionDividerActiveAlpha, mSelectionDividerDimmedAlpha + ); + + // creating paints + mSeparatorsPaint = new Paint(); + mSeparatorsPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + mSeparatorsPaint.setAlpha(mSelectionDividerDimmedAlpha); + + mSelectorWheelPaint = new Paint(); + mSelectorWheelPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + } + + /** + * Recreates assets (like bitmaps) when layout size has been changed + * + * @param width New spinnerwheel width + * @param height New spinnerwheel height + */ + @Override + protected void recreateAssets(int width, int height) { + if(mSpinBitmap == null){ + try { + mSpinBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + }catch (IllegalArgumentException e){ + e.printStackTrace(); + } + + } + +// if(mSeparatorsBitmap == null){ +// mSeparatorsBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); +// } + setSelectorPaintCoeff(0); + } + + /** + * Sets the alpha of the {@link Paint} for drawing separators + * spinnerwheel. + * @param alpha alpha value from 0 to 255 + */ + @SuppressWarnings("unused") // Called via reflection + @Keep + public void setSeparatorsPaintAlpha(int alpha) { + mSeparatorsPaint.setAlpha(alpha); + invalidate(); + } + + @Override + public void removeBitmap(){ + if(mSpinBitmap != null && !mSpinBitmap.isRecycled()){ + mSpinBitmap.recycle(); + mSpinBitmap = null; + } +// +// if(mSeparatorsBitmap != null && !mSeparatorsBitmap.isRecycled()){ +// mSeparatorsBitmap.recycle(); +// mSeparatorsBitmap = null; +// } + } + + /** + * Sets the coeff of the {@link Paint} for drawing + * the selector spinnerwheel. + * + * @param coeff Coefficient from 0 (selector is passive) to 1 (selector is active) + */ + @Keep + abstract public void setSelectorPaintCoeff(float coeff); + + + //-------------------------------------------------------------------------- + // + // Processing scroller events + // + //-------------------------------------------------------------------------- + + @Override + protected void onScrollTouched() { + mDimSelectorWheelAnimator.cancel(); + mDimSeparatorsAnimator.cancel(); + setSelectorPaintCoeff(1); + setSeparatorsPaintAlpha(mSelectionDividerActiveAlpha); + } + + @Override + protected void onScrollTouchedUp() { + super.onScrollTouchedUp(); + fadeSelectorWheel(750); + lightSeparators(750); + } + + @Override + protected void onScrollFinished() { + fadeSelectorWheel(500); + lightSeparators(500); + } + + //---------------------------------- + // Animating components + //---------------------------------- + + /** + * Fade the selector spinnerwheel via an animation. + * + * @param animationDuration The duration of the animation. + */ + private void fadeSelectorWheel(long animationDuration) { + mDimSelectorWheelAnimator.setDuration(animationDuration); + mDimSelectorWheelAnimator.start(); + } + + /** + * Fade the selector spinnerwheel via an animation. + * + * @param animationDuration The duration of the animation. + */ + private void lightSeparators(long animationDuration) { + mDimSeparatorsAnimator.setDuration(animationDuration); + mDimSeparatorsAnimator.start(); + } + + + //-------------------------------------------------------------------------- + // + // Layout measuring + // + //-------------------------------------------------------------------------- + + /** + * Perform layout measurements + */ + abstract protected void measureLayout(); + + + //-------------------------------------------------------------------------- + // + // Drawing stuff + // + //-------------------------------------------------------------------------- + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mViewAdapter != null && mViewAdapter.getItemsCount() > 0) { + if (rebuildItems()) { + measureLayout(); + } + doItemsLayout(); + drawItems(canvas); + } + } + + /** + * Draws items on specified canvas + * + * @param canvas the canvas for drawing + */ + abstract protected void drawItems(Canvas canvas); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/ItemsRange.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/ItemsRange.java new file mode 100644 index 0000000..2e3125c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/ItemsRange.java @@ -0,0 +1,62 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + + /** + * Range for visible items. + */ + public class ItemsRange { + // First item number + private int first; + + // Items count + private int count; + + /** + * Default constructor. Creates an empty range + */ + public ItemsRange() { + this(0, 0); + } + + /** + * Constructor + * @param first the number of first item + * @param count the count of items + */ + public ItemsRange(int first, int count) { + this.first = first; + this.count = count; + } + + /** + * Gets number of first item + * @return the number of the first item + */ + public int getFirst() { + return first; + } + + /** + * Gets number of last item + * @return the number of last item + */ + public int getLast() { + return getFirst() + getCount() - 1; + } + + /** + * Get items count + * @return the count of items + */ + public int getCount() { + return count; + } + + /** + * Tests whether item is contained by range + * @param index the item number + * @return true if item is contained + */ + public boolean contains(int index) { + return index >= getFirst() && index <= getLast(); + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelChangedListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelChangedListener.java new file mode 100644 index 0000000..2208d80 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelChangedListener.java @@ -0,0 +1,17 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +/** + * Wheel changed listener interface. + *

The onChanged() method is called whenever current spinnerwheel positions is changed: + *

  • New Wheel position is set + *
  • Wheel view is scrolled + */ +public interface OnWheelChangedListener { + /** + * Callback method to be invoked when current item changed + * @param wheel the spinnerwheel view whose state has changed + * @param oldValue the old value of current item + * @param newValue the new value of current item + */ + void onChanged(AbstractWheel wheel, int oldValue, int newValue); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelClickedListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelClickedListener.java new file mode 100644 index 0000000..3b2b5f4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelClickedListener.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +/** + * Wheel clicked listener interface. + *

    The onItemClicked() method is called whenever a spinnerwheel item is clicked + *

  • New Wheel position is set + *
  • Wheel view is scrolled + */ +public interface OnWheelClickedListener { + /** + * Callback method to be invoked when current item clicked + * @param wheel the spinnerwheel view + * @param itemIndex the index of clicked item + */ + void onItemClicked(AbstractWheel wheel, int itemIndex); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelScrollListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelScrollListener.java new file mode 100644 index 0000000..5b22252 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/OnWheelScrollListener.java @@ -0,0 +1,18 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +/** + * Wheel scrolled listener interface. + */ +public interface OnWheelScrollListener { + /** + * Callback method to be invoked when scrolling started. + * @param wheel the spinnerwheel view whose state has changed. + */ + void onScrollingStarted(AbstractWheel wheel); + + /** + * Callback method to be invoked when scrolling ended. + * @param wheel the spinnerwheel view whose state has changed. + */ + void onScrollingFinished(AbstractWheel wheel); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalScroller.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalScroller.java new file mode 100644 index 0000000..47cd20a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalScroller.java @@ -0,0 +1,48 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.view.MotionEvent; + +public class WheelHorizontalScroller extends WheelScroller { + + /** + * Constructor + * + * @param context + * the current context + * @param listener + * the scrolling listener + */ + public WheelHorizontalScroller(Context context, ScrollingListener listener) { + super(context, listener); + } + + @Override + protected int getCurrentScrollerPosition() { + return scroller.getCurrX(); + } + + @Override + protected int getFinalScrollerPosition() { + return scroller.getFinalX(); + } + + @Override + protected float getMotionEventPosition(MotionEvent event) { + // should be overriden + return event.getX(); + } + + @Override + protected void scrollerStartScroll(int distance, int time) { + scroller.startScroll(0, 0, distance, 0, time); + } + + @Override + protected void scrollerFling(int position, int velocityX, int velocityY) { + final int maxPosition = 0x7FFFFFFF; + final int minPosition = -maxPosition; + scroller.fling(position, 0, -velocityX, 0, minPosition, maxPosition, 0, + 0); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalView.java new file mode 100644 index 0000000..380c9f3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelHorizontalView.java @@ -0,0 +1,340 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.LinearLayout; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +public class WheelHorizontalView extends AbstractWheelView { + + private static int itemID = -1; + + @SuppressWarnings("unused") + private final String LOG_TAG = WheelVerticalView.class.getName() + " #" + (++itemID); + + /** + * The width of the selection divider. + */ + protected int mSelectionDividerWidth; + + // Item width + private int itemWidth = 0; + + //-------------------------------------------------------------------------- + // + // Constructors + // + //-------------------------------------------------------------------------- + + /** + * Create a new wheel horizontal view. + * + * @param context The application environment. + */ + public WheelHorizontalView(Context context) { + this(context, null); + } + + /** + * Create a new wheel horizontal view. + * + * @param context The application environment. + * @param attrs A collection of attributes. + */ + public WheelHorizontalView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.abstractWheelViewStyle); + } + + /** + * Create a new wheel horizontal view. + * + * @param context the application environment. + * @param attrs a collection of attributes. + * @param defStyle The default style to apply to this view. + */ + public WheelHorizontalView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + + //-------------------------------------------------------------------------- + // + // Initiating assets and setter for selector paint + // + //-------------------------------------------------------------------------- + + @Override + protected void initAttributes(AttributeSet attrs, int defStyle) { + super.initAttributes(attrs, defStyle); + + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MobileCommonWheelHorizontalView, defStyle, 0); + mSelectionDividerWidth = a.getDimensionPixelSize(R.styleable.MobileCommonWheelHorizontalView_selectionDividerWidth, DEF_SELECTION_DIVIDER_SIZE); + a.recycle(); + } + + @Override + public void setSelectorPaintCoeff(float coeff) { + if (mItemsDimmedAlpha >= 100) + return; + + LinearGradient shader; + + int w = getMeasuredWidth(); + int iw = getItemDimension(); + float p1 = (1 - iw/(float) w)/2; + float p2 = (1 + iw/(float) w)/2; + float z = mItemsDimmedAlpha * (1 - coeff); + float c1f = z + 255 * coeff; + + if (mVisibleItems == 2) { + int c1 = Math.round( c1f ) << 24; + int c2 = Math.round( z ) << 24; + int[] colors = {c2, c1, 0xff000000, 0xff000000, c1, c2}; + float[] positions = { 0, p1, p1, p2, p2, 1}; + shader = new LinearGradient(0, 0, w, 0, colors, positions, Shader.TileMode.CLAMP); + } else { + float p3 = (1 - iw*3/(float) w)/2; + float p4 = (1 + iw*3/(float) w)/2; + + float s = 255 * p3/p1; + float c3f = s * coeff ; // here goes some optimized stuff + float c2f = z + c3f; + + int c1 = Math.round( c1f ) << 24; + int c2 = Math.round( c2f ) << 24; + int c3 = Math.round( c3f ) << 24; + + int[] colors = { c2, c2, c2, c2, 0xff000000, 0xff000000, c2, c2, c2, c2 }; + float[] positions = { 0, p3, p3, p1, p1, p2, p2, p4, p4, 1 }; + shader = new LinearGradient(0, 0, w, 0, colors, positions, Shader.TileMode.CLAMP); + } + mSelectorWheelPaint.setShader(shader); + invalidate(); + } + + + //-------------------------------------------------------------------------- + // + // Scroller-specific methods + // + //-------------------------------------------------------------------------- + + @Override + protected WheelScroller createScroller(WheelScroller.ScrollingListener scrollingListener) { + return new WheelHorizontalScroller(getContext(), scrollingListener); + } + + @Override + protected float getMotionEventPosition(MotionEvent event) { + return event.getX(); + } + + + //-------------------------------------------------------------------------- + // + // Base measurements + // + //-------------------------------------------------------------------------- + + @Override + protected int getBaseDimension() { + return getWidth(); + } + + /** + * Returns height of spinnerwheel item + * @return the item width + */ + @Override + protected int getItemDimension() { + if (itemWidth != 0) { + return itemWidth; + } + + if (mItemsLayout != null && mItemsLayout.getChildAt(0) != null) { + itemWidth = mItemsLayout.getChildAt(0).getMeasuredWidth(); + return itemWidth; + } + + return getBaseDimension() / mVisibleItems; + } + + //-------------------------------------------------------------------------- + // + // Debugging stuff + // + //-------------------------------------------------------------------------- + + + @Override + protected void onScrollTouchedUp() { + super.onScrollTouchedUp(); + int cnt = mItemsLayout.getChildCount(); + View itm; + LogUtil.errorLog(LOG_TAG, " ----- layout: " + mItemsLayout.getMeasuredWidth() + mItemsLayout.getMeasuredHeight()); + LogUtil.errorLog(LOG_TAG, " -------- dumping " + cnt + " items"); + for (int i = 0; i < cnt; i++) { + itm = mItemsLayout.getChildAt(i); + LogUtil.errorLog(LOG_TAG, " item #" + i + ": " + itm.getWidth() + "x" + itm.getHeight()); + itm.forceLayout(); // forcing layout without re-rendering parent + } + LogUtil.errorLog(LOG_TAG, " ---------- dumping finished "); + } + + + //-------------------------------------------------------------------------- + // + // Layout creation and measurement operations + // + //-------------------------------------------------------------------------- + + /** + * Creates item layouts if necessary + */ + @Override + protected void createItemsLayout() { + if (mItemsLayout == null) { + mItemsLayout = new LinearLayout(getContext()); + mItemsLayout.setOrientation(LinearLayout.HORIZONTAL); + } + } + + @Override + protected void doItemsLayout() { + mItemsLayout.layout(0, 0, getMeasuredWidth(), getMeasuredHeight() - 2 * mItemsPadding); + } + + @Override + protected void measureLayout() { + mItemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + // XXX: Locating bug + mItemsLayout.measure( + View.MeasureSpec.makeMeasureSpec(getWidth() + getItemDimension(), View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(getHeight(), View.MeasureSpec.AT_MOST)); + } + + //XXX: Most likely, measurements of mItemsLayout or/and its children are done inconrrectly. + // Investigate and fix it + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = View.MeasureSpec.getMode(widthMeasureSpec); + int heightMode = View.MeasureSpec.getMode(heightMeasureSpec); + int widthSize = View.MeasureSpec.getSize(widthMeasureSpec); + int heightSize = View.MeasureSpec.getSize(heightMeasureSpec); + + rebuildItems(); // rebuilding before measuring + + int height = calculateLayoutHeight(heightSize, heightMode); + + int width; + if (widthMode == View.MeasureSpec.EXACTLY) { + width = widthSize; + } else { + width = Math.max( + getItemDimension() * (mVisibleItems - mItemOffsetPercent / 100), + getSuggestedMinimumWidth() + ); + + if (widthMode == View.MeasureSpec.AT_MOST) { + width = Math.min(width, widthSize); + } + } + setMeasuredDimension(width, height); + } + + + /** + * Calculates control height and creates text layouts + * @param heightSize the input layout height + * @param mode the layout mode + * @return the calculated control height + */ + private int calculateLayoutHeight(int heightSize, int mode) { + mItemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + mItemsLayout.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(heightSize, View.MeasureSpec.UNSPECIFIED) + ); + int height = mItemsLayout.getMeasuredHeight(); + + if (mode == View.MeasureSpec.EXACTLY) { + height = heightSize; + } else { + height += 2 * mItemsPadding; + + // Check against our minimum width + height = Math.max(height, getSuggestedMinimumHeight()); + + if (mode == View.MeasureSpec.AT_MOST && heightSize < height) { + height = heightSize; + } + } + // forcing recalculating + mItemsLayout.measure( + // MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(400, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(height - 2 * mItemsPadding, View.MeasureSpec.EXACTLY) + ); + + return height; + } + + + //-------------------------------------------------------------------------- + // + // Drawing items + // + //-------------------------------------------------------------------------- + + @Override + protected void drawItems(Canvas canvas) { + canvas.save(); + int w = getMeasuredWidth(); + int h = getMeasuredHeight(); + int iw = getItemDimension(); + + // resetting intermediate bitmap and recreating canvases + mSpinBitmap.eraseColor(0); + Canvas c = new Canvas(mSpinBitmap); + Canvas cSpin = new Canvas(mSpinBitmap); + + int left = (mCurrentItemIdx - mFirstItemIdx) * iw + (iw - getWidth()) / 2; + c.translate(- left + mScrollingOffset, mItemsPadding); + mItemsLayout.draw(c); + +// mSeparatorsBitmap.eraseColor(0); + Canvas cSeparators = new Canvas(mSpinBitmap); + + if (mSelectionDivider != null) { + // draw the top divider + int leftOfLeftDivider = (getWidth() - iw - mSelectionDividerWidth) / 2; + int rightOfLeftDivider = leftOfLeftDivider + mSelectionDividerWidth; + mSelectionDivider.setBounds(leftOfLeftDivider, 0, rightOfLeftDivider, getHeight()); + mSelectionDivider.draw(cSeparators); + + // draw the bottom divider + int leftOfRightDivider = leftOfLeftDivider + iw; + int rightOfRightDivider = rightOfLeftDivider + iw; + mSelectionDivider.setBounds(leftOfRightDivider, 0, rightOfRightDivider, getHeight()); + mSelectionDivider.draw(cSeparators); + } + + cSpin.drawRect(0, 0, w, h, mSelectorWheelPaint); + cSeparators.drawRect(0, 0, w, h, mSeparatorsPaint); + + canvas.drawBitmap(mSpinBitmap, 0, 0, null); + canvas.drawBitmap(mSpinBitmap, 0, 0, null); + canvas.restore(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelRecycler.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelRecycler.java new file mode 100644 index 0000000..72c9533 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelRecycler.java @@ -0,0 +1,139 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.view.View; +import android.widget.LinearLayout; + +import java.util.LinkedList; +import java.util.List; + +/** + * Recycle stored spinnerwheel items to reuse. + */ +public class WheelRecycler { + + + @SuppressWarnings("unused") + private static final String LOG_TAG = WheelRecycler.class.getName(); + + // Cached items + private List items; + + // Cached empty items + private List emptyItems; + + // Wheel view + private AbstractWheel wheel; + + /** + * Constructor + * @param wheel the spinnerwheel view + */ + public WheelRecycler(AbstractWheel wheel) { + this.wheel = wheel; + } + + /** + * Recycles items from specified layout. + * There are saved only items not included to specified range. + * All the cached items are removed from original layout. + * + * @param layout the layout containing items to be cached + * @param firstItem the number of first item in layout + * @param range the range of current spinnerwheel items + * @return the new value of first item number + */ + public int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) { + int index = firstItem; + for (int i = 0; i < layout.getChildCount();) { + if (!range.contains(index)) { + recycleView(layout.getChildAt(i), index); + layout.removeViewAt(i); + if (i == 0) { // first item + firstItem++; + } + } else { + i++; // go to next item + } + index++; + } + return firstItem; + } + + /** + * Gets item view + * @return the cached view + */ + public View getItem() { + return getCachedView(items); + } + + /** + * Gets empty item view + * @return the cached empty view + */ + public View getEmptyItem() { + return getCachedView(emptyItems); + } + + /** + * Clears all views + */ + public void clearAll() { + if (items != null) { + items.clear(); + } + if (emptyItems != null) { + emptyItems.clear(); + } + } + + /** + * Adds view to specified cache. Creates a cache list if it is null. + * @param view the view to be cached + * @param cache the cache list + * @return the cache list + */ + private List addView(View view, List cache) { + if (cache == null) { + cache = new LinkedList<>(); + } + + cache.add(view); + return cache; + } + + /** + * Adds view to cache. Determines view type (item view or empty one) by index. + * @param view the view to be cached + * @param index the index of view + */ + private void recycleView(View view, int index) { + int count = wheel.getViewAdapter().getItemsCount(); + + if ((index < 0 || index >= count) && !wheel.isCyclic()) { + // empty view + emptyItems = addView(view, emptyItems); + } else { + while (index < 0) { + index = count + index; + } + index %= count; + items = addView(view, items); + } + } + + /** + * Gets view from specified cache. + * @param cache the cache + * @return the first view from cache. + */ + private View getCachedView(List cache) { + if (cache != null && cache.size() > 0) { + View view = cache.get(0); + cache.remove(0); + return view; + } + return null; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelScroller.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelScroller.java new file mode 100644 index 0000000..534918c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelScroller.java @@ -0,0 +1,257 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.animation.Interpolator; +import android.widget.Scroller; + +/** + * Scroller class handles scrolling events and updates the spinnerwheel + */ +public abstract class WheelScroller { + /** + * Scrolling listener interface + */ + public interface ScrollingListener { + /** + * Scrolling callback called when scrolling is performed. + * @param distance the distance to scroll + */ + void onScroll(int distance); + + /** + * This callback is invoked when scroller has been touched + */ + void onTouch(); + + /** + * This callback is invoked when touch is up + */ + void onTouchUp(); + + /** + * Starting callback called when scrolling is started + */ + void onStarted(); + + /** + * Finishing callback called after justifying + */ + void onFinished(); + + /** + * Justifying callback called to justify a view when scrolling is ended + */ + void onJustify(); + } + + /** Scrolling duration */ + private static final int SCROLLING_DURATION = 400; + + /** Minimum delta for scrolling */ + public static final int MIN_DELTA_FOR_SCROLLING = 1; + + // Listener + private ScrollingListener listener; + + // Context + private Context context; + + // Scrolling + private GestureDetector gestureDetector; + protected Scroller scroller; + private int lastScrollPosition; + private float lastTouchedPosition; + private boolean isScrollingPerformed; + + /** + * Constructor + * @param context the current context + * @param listener the scrolling listener + */ + public WheelScroller(Context context, ScrollingListener listener) { + gestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + // Do scrolling in onTouchEvent() since onScroll() are not call immediately + // when user touch and move the spinnerwheel + return true; + } + + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + lastScrollPosition = 0; + scrollerFling(lastScrollPosition, (int) velocityX, (int) velocityY); + setNextMessage(MESSAGE_SCROLL); + return true; + } + + // public boolean onDown(MotionEvent motionEvent); + + }); + gestureDetector.setIsLongpressEnabled(false); + + scroller = new Scroller(context); + + this.listener = listener; + this.context = context; + } + + /** + * Set the the specified scrolling interpolator + * @param interpolator the interpolator + */ + public void setInterpolator(Interpolator interpolator) { + scroller.forceFinished(true); + scroller = new Scroller(context, interpolator); + } + + /** + * Scroll the spinnerwheel + * @param distance the scrolling distance + * @param time the scrolling duration + */ + public void scroll(int distance, int time) { + scroller.forceFinished(true); + lastScrollPosition = 0; + scrollerStartScroll(distance, time != 0 ? time : SCROLLING_DURATION); + setNextMessage(MESSAGE_SCROLL); + startScrolling(); + } + + /** + * Stops scrolling + */ + public void stopScrolling() { + scroller.forceFinished(true); + } + + /** + * Handles Touch event + * @param event the motion event + * @return + */ + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + + case MotionEvent.ACTION_DOWN: + lastTouchedPosition = getMotionEventPosition(event); + scroller.forceFinished(true); + clearMessages(); + listener.onTouch(); + break; + + case MotionEvent.ACTION_UP: + if (scroller.isFinished()) + listener.onTouchUp(); + break; + + + case MotionEvent.ACTION_MOVE: + // perform scrolling + int distance = (int)(getMotionEventPosition(event) - lastTouchedPosition); + if (distance != 0) { + startScrolling(); + listener.onScroll(distance); + lastTouchedPosition = getMotionEventPosition(event); + } + break; + } + + if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) { + justify(); + } + + return true; + } + + + // Messages + private static final int MESSAGE_SCROLL = 0; + private static final int MESSAGE_JUSTIFY = 1; + + /** + * Set next message to queue. Clears queue before. + * + * @param message the message to set + */ + private void setNextMessage(int message) { + clearMessages(); + animationHandler.sendEmptyMessage(message); + } + + /** + * Clears messages from queue + */ + private void clearMessages() { + animationHandler.removeMessages(MESSAGE_SCROLL); + animationHandler.removeMessages(MESSAGE_JUSTIFY); + } + + // animation handler + private Handler animationHandler = new Handler() { + public void handleMessage(Message msg) { + scroller.computeScrollOffset(); + int currPosition = getCurrentScrollerPosition(); + int delta = lastScrollPosition - currPosition; + lastScrollPosition = currPosition; + if (delta != 0) { + listener.onScroll(delta); + } + + // scrolling is not finished when it comes to final Y + // so, finish it manually + if (Math.abs(currPosition - getFinalScrollerPosition()) < MIN_DELTA_FOR_SCROLLING) { + // currPosition = getFinalScrollerPosition(); + scroller.forceFinished(true); + } + if (!scroller.isFinished()) { + animationHandler.sendEmptyMessage(msg.what); + } else if (msg.what == MESSAGE_SCROLL) { + justify(); + } else { + finishScrolling(); + } + } + }; + + /** + * Justifies spinnerwheel + */ + private void justify() { + listener.onJustify(); + setNextMessage(MESSAGE_JUSTIFY); + } + + /** + * Starts scrolling + */ + private void startScrolling() { + if (!isScrollingPerformed) { + isScrollingPerformed = true; + listener.onStarted(); + } + } + + /** + * Finishes scrolling + */ + protected void finishScrolling() { + if (isScrollingPerformed) { + listener.onFinished(); + isScrollingPerformed = false; + } + } + + protected abstract int getCurrentScrollerPosition(); + + protected abstract int getFinalScrollerPosition(); + + protected abstract float getMotionEventPosition(MotionEvent event); + + protected abstract void scrollerStartScroll(int distance, int time); + + protected abstract void scrollerFling(int position, int velocityX, int velocityY); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalScroller.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalScroller.java new file mode 100644 index 0000000..c25976f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalScroller.java @@ -0,0 +1,47 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.view.MotionEvent; + +/** + * Scroller class handles scrolling events and updates the + */ +public class WheelVerticalScroller extends WheelScroller { + + /** + * Constructor + * @param context the current context + * @param listener the scrolling listener + */ + public WheelVerticalScroller(Context context, ScrollingListener listener) { + super(context, listener); + } + + @Override + protected int getCurrentScrollerPosition() { + return scroller.getCurrY(); + } + + @Override + protected int getFinalScrollerPosition() { + return scroller.getFinalY(); + } + + @Override + protected float getMotionEventPosition(MotionEvent event) { + // should be overriden + return event.getY(); + } + + @Override + protected void scrollerStartScroll(int distance, int time) { + scroller.startScroll(0, 0, 0, distance, time); + } + + @Override + protected void scrollerFling(int position, int velocityX, int velocityY) { + final int maxPosition = 0x7FFFFFFF; + final int minPosition = -maxPosition; + scroller.fling(0, position, 0, -velocityY, 0, 0, minPosition, maxPosition); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalView.java new file mode 100644 index 0000000..5cac593 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/WheelVerticalView.java @@ -0,0 +1,317 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.LinearLayout; + +import com.mm.android.deviceaddmodule.R; + + +/** + * Spinner wheel vertical view. + */ +public class WheelVerticalView extends AbstractWheelView { + + private static int itemID = -1; + + @SuppressWarnings("unused") + private final String LOG_TAG = WheelVerticalView.class.getName() + " #" + (++itemID); + + /** + * The height of the selection divider. + */ + protected int mSelectionDividerHeight; + + // Cached item height + private int mItemHeight = 0; + + //-------------------------------------------------------------------------- + // + // Constructors + // + //-------------------------------------------------------------------------- + + /** + * Create a new wheel vertical view. + * + * @param context The application environment. + */ + public WheelVerticalView(Context context) { + this(context, null); + } + + /** + * Create a new wheel vertical view. + * + * @param context The application environment. + * @param attrs A collection of attributes. + */ + public WheelVerticalView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.abstractWheelViewStyle); + } + + /** + * Create a new wheel vertical view. + * + * @param context the application environment. + * @param attrs a collection of attributes. + * @param defStyle The default style to apply to this view. + */ + public WheelVerticalView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + + //-------------------------------------------------------------------------- + // + // Initiating assets and setter for selector paint + // + //-------------------------------------------------------------------------- + + @Override + protected void initAttributes(AttributeSet attrs, int defStyle) { + super.initAttributes(attrs, defStyle); + + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MobileCommonWheelVerticalView, defStyle, 0); + mSelectionDividerHeight = a.getDimensionPixelSize(R.styleable.MobileCommonWheelVerticalView_selectionDividerHeight, DEF_SELECTION_DIVIDER_SIZE); + a.recycle(); + } + + @Override + public void setSelectorPaintCoeff(float coeff) { + LinearGradient shader; + + int h = getMeasuredHeight(); + int ih = getItemDimension(); + float p1 = (1 - ih/(float) h)/2; + float p2 = (1 + ih/(float) h)/2; + float z = mItemsDimmedAlpha * (1 - coeff); + float c1f = z + 255 * coeff; + + if (mVisibleItems == 2) { + int c1 = Math.round( c1f ) << 24; + int c2 = Math.round( z ) << 24; + int[] colors = {c2, c1, 0xff000000, 0xff000000, c1, c2}; + float[] positions = { 0, p1, p1, p2, p2, 1}; + shader = new LinearGradient(0, 0, 0, h, colors, positions, Shader.TileMode.CLAMP); + } else { + float p3 = (1 - ih*3/(float) h)/2; + float p4 = (1 + ih*3/(float) h)/2; + + float s = 255 * p3/p1; + float c3f = s * coeff ; // here goes some optimized stuff + float c2f = z + c3f; + + int c1 = Math.round( c1f ) << 24; + int c2 = Math.round( c2f ) << 24; + int c3 = Math.round( c3f ) << 24; + + int[] colors = {0, c3, c2, c1, 0xff000000, 0xff000000, c1, c2, c3, 0}; + float[] positions = {0, p3, p3, p1, p1, p2, p2, p4, p4, 1}; + shader = new LinearGradient(0, 0, 0, h, colors, positions, Shader.TileMode.CLAMP); + } + mSelectorWheelPaint.setShader(shader); + invalidate(); + } + + + //-------------------------------------------------------------------------- + // + // Scroller-specific methods + // + //-------------------------------------------------------------------------- + + @Override + protected WheelScroller createScroller(WheelScroller.ScrollingListener scrollingListener) { + return new WheelVerticalScroller(getContext(), scrollingListener); + } + + @Override + protected float getMotionEventPosition(MotionEvent event) { + return event.getY(); + } + + //-------------------------------------------------------------------------- + // + // Base measurements + // + //-------------------------------------------------------------------------- + + @Override + protected int getBaseDimension() { + return getHeight(); + } + + /** + * Returns height of the spinnerwheel + * @return the item height + */ + @Override + protected int getItemDimension() { + if (mItemHeight != 0) { + return mItemHeight; + } + + if (mItemsLayout != null && mItemsLayout.getChildAt(0) != null) { + mItemHeight = mItemsLayout.getChildAt(0).getMeasuredHeight(); + return mItemHeight; + } + + return getBaseDimension() / mVisibleItems; + } + + //-------------------------------------------------------------------------- + // + // Layout creation and measurement operations + // + //-------------------------------------------------------------------------- + + /** + * Creates item layout if necessary + */ + @Override + protected void createItemsLayout() { + if (mItemsLayout == null) { + mItemsLayout = new LinearLayout(getContext()); + mItemsLayout.setOrientation(LinearLayout.VERTICAL); + } + } + + @Override + protected void doItemsLayout() { + mItemsLayout.layout(0, 0, getMeasuredWidth() - 2 * mItemsPadding, getMeasuredHeight()); + } + + + @Override + protected void measureLayout() { + mItemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + mItemsLayout.measure( + View.MeasureSpec.makeMeasureSpec(getWidth() - 2 * mItemsPadding, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ); + + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + int widthMode = View.MeasureSpec.getMode(widthMeasureSpec); + int heightMode = View.MeasureSpec.getMode(heightMeasureSpec); + int widthSize = View.MeasureSpec.getSize(widthMeasureSpec); + int heightSize = View.MeasureSpec.getSize(heightMeasureSpec); + + rebuildItems(); // rebuilding before measuring + + int width = calculateLayoutWidth(widthSize, widthMode); + + int height; + if (heightMode == View.MeasureSpec.EXACTLY) { + height = heightSize; + } else { + height = Math.max( + getItemDimension() * (mVisibleItems - mItemOffsetPercent / 100), + getSuggestedMinimumHeight() + ); + + if (heightMode == View.MeasureSpec.AT_MOST) { + height = Math.min(height, heightSize); + } + } + setMeasuredDimension(width, height); + } + + /** + * Calculates control width + * @param widthSize the input layout width + * @param mode the layout mode + * @return the calculated control width + */ + private int calculateLayoutWidth(int widthSize, int mode) { + mItemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + mItemsLayout.measure( + View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ); + int width = mItemsLayout.getMeasuredWidth(); + + if (mode == View.MeasureSpec.EXACTLY) { + width = widthSize; + } else { + width += 2 * mItemsPadding; + + // Check against our minimum width + width = Math.max(width, getSuggestedMinimumWidth()); + + if (mode == View.MeasureSpec.AT_MOST && widthSize < width) { + width = widthSize; + } + } + + // forcing recalculating + mItemsLayout.measure( + View.MeasureSpec.makeMeasureSpec(width - 2 * mItemsPadding, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ); + + return width; + } + + + //-------------------------------------------------------------------------- + // + // Drawing items + // + //-------------------------------------------------------------------------- + + @Override + protected void drawItems(Canvas canvas) { + canvas.save(); + int w = getMeasuredWidth(); + int h = getMeasuredHeight(); + int ih = getItemDimension(); + + // resetting intermediate bitmap and recreating canvases + mSpinBitmap.eraseColor(0); + Canvas c = new Canvas(mSpinBitmap); + Canvas cSpin = new Canvas(mSpinBitmap); + + int top = (mCurrentItemIdx - mFirstItemIdx) * ih + (ih - getHeight()) / 2; + c.translate(mItemsPadding, - top + mScrollingOffset); + mItemsLayout.draw(c); + +// mSeparatorsBitmap.eraseColor(0); + Canvas cSeparators = new Canvas(mSpinBitmap); + + if (mSelectionDivider != null) { + // draw the top divider + int topOfTopDivider = (getHeight() - ih - mSelectionDividerHeight) / 2; + int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; + mSelectionDivider.setBounds(0, topOfTopDivider, w, bottomOfTopDivider); + mSelectionDivider.draw(cSeparators); + + // draw the bottom divider + int topOfBottomDivider = topOfTopDivider + ih; + int bottomOfBottomDivider = bottomOfTopDivider + ih; + mSelectionDivider.setBounds(0, topOfBottomDivider, w, bottomOfBottomDivider); + mSelectionDivider.draw(cSeparators); + } + + cSpin.drawRect(0, 0, w, h, mSelectorWheelPaint); + cSeparators.drawRect(0, 0, w, h, mSeparatorsPaint); + + canvas.drawBitmap(mSpinBitmap, 0, 0, null); + canvas.drawBitmap(mSpinBitmap, 0, 0, null); + canvas.restore(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelAdapter.java new file mode 100644 index 0000000..610add7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelAdapter.java @@ -0,0 +1,58 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters; + +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; + +import java.util.LinkedList; +import java.util.List; + +/** + * Abstract Wheel adapter. + */ +public abstract class AbstractWheelAdapter implements WheelViewAdapter { + // Observers + private List datasetObservers; + + @Override + public View getEmptyItem(View convertView, ViewGroup parent) { + return null; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + if (datasetObservers == null) { + datasetObservers = new LinkedList<>(); + } + datasetObservers.add(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + if (datasetObservers != null) { + datasetObservers.remove(observer); + } + } + + /** + * Notifies observers about data changing + */ + protected void notifyDataChangedEvent() { + if (datasetObservers != null) { + for (DataSetObserver observer : datasetObservers) { + observer.onChanged(); + } + } + } + + /** + * Notifies observers about invalidating data + */ + protected void notifyDataInvalidatedEvent() { + if (datasetObservers != null) { + for (DataSetObserver observer : datasetObservers) { + observer.onInvalidated(); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelTextAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelTextAdapter.java new file mode 100644 index 0000000..15ff9d4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/AbstractWheelTextAdapter.java @@ -0,0 +1,270 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters; + +import android.content.Context; +import android.graphics.Typeface; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +/** + * Abstract spinnerwheel adapter provides common functionality for adapters. + */ +public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter { + + /** Text view resource. Used as a default view for adapter. */ + public static final int TEXT_VIEW_ITEM_RESOURCE = -1; + + /** No resource constant. */ + protected static final int NO_RESOURCE = 0; + + /** Default text color */ + public static final int DEFAULT_TEXT_COLOR = 0xFF000000; + + /** Default text color */ + public static final int LABEL_COLOR = 0xFF700070; + + /** Default text size */ + public static final int DEFAULT_TEXT_SIZE = 18; + + /// Custom text typeface + private Typeface textTypeface; + + // Text settings + private int textColor = DEFAULT_TEXT_COLOR; + private int textSize = DEFAULT_TEXT_SIZE; + + // Current context + protected Context context; + // Layout inflater + protected LayoutInflater inflater; + + // Items resources + protected int itemResourceId; + protected int itemTextResourceId; + + // Empty items resources + protected int emptyItemResourceId; + + + /** + * Constructor + * @param context the current context + */ + protected AbstractWheelTextAdapter(Context context) { + this(context, TEXT_VIEW_ITEM_RESOURCE); + } + + /** + * Constructor + * @param context the current context + * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views + */ + protected AbstractWheelTextAdapter(Context context, int itemResource) { + this(context, itemResource, NO_RESOURCE); + } + + /** + * Constructor + * @param context the current context + * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views + * @param itemTextResource the resource ID for a text view in the item layout + */ + protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) { + this.context = context; + itemResourceId = itemResource; + itemTextResourceId = itemTextResource; + + inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + /** + * Gets text color + * @return the text color + */ + public int getTextColor() { + return textColor; + } + + /** + * Sets text color + * @param textColor the text color to set + */ + public void setTextColor(int textColor) { + this.textColor = textColor; + } + + /** + * Sets text typeface + * @param typeface typeface to set + */ + public void setTextTypeface(Typeface typeface) { + this.textTypeface = typeface; + } + + /** + * Gets text size + * @return the text size + */ + public int getTextSize() { + return textSize; + } + + /** + * Sets text size + * @param textSize the text size to set + */ + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + /** + * Gets resource Id for items views + * @return the item resource Id + */ + public int getItemResource() { + return itemResourceId; + } + + /** + * Sets resource Id for items views + * @param itemResourceId the resource Id to set + */ + public void setItemResource(int itemResourceId) { + this.itemResourceId = itemResourceId; + } + + /** + * Gets resource Id for text view in item layout + * @return the item text resource Id + */ + public int getItemTextResource() { + return itemTextResourceId; + } + + /** + * Sets resource Id for text view in item layout + * @param itemTextResourceId the item text resource Id to set + */ + public void setItemTextResource(int itemTextResourceId) { + this.itemTextResourceId = itemTextResourceId; + } + + /** + * Gets resource Id for empty items views + * @return the empty item resource Id + */ + public int getEmptyItemResource() { + return emptyItemResourceId; + } + + /** + * Sets resource Id for empty items views + * @param emptyItemResourceId the empty item resource Id to set + */ + public void setEmptyItemResource(int emptyItemResourceId) { + this.emptyItemResourceId = emptyItemResourceId; + } + + /** + * Returns text for specified item + * @param index the item index + * @return the text of specified items + */ + protected abstract CharSequence getItemText(int index); + + @Override + public View getItem(int index, View convertView, ViewGroup parent) { + if (index >= 0 && index < getItemsCount()) { + if (convertView == null) { + convertView = getView(itemResourceId, parent); + } + if (convertView == null) { + convertView = new View(context); + } + TextView textView = getTextView(convertView, itemTextResourceId); + if (textView != null) { + CharSequence text = getItemText(index); + if (text == null) { + text = ""; + } + textView.setText(text); + configureTextView(textView); + } + return convertView; + } + return null; + } + + @Override + public View getEmptyItem(View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = getView(emptyItemResourceId, parent); + } + if (convertView instanceof TextView) { + configureTextView((TextView)convertView); + } + + return convertView; + } + + /** + * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views. + * @param view the text view to be configured + */ + protected void configureTextView(TextView view) { + if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) { + view.setTextColor(textColor); + view.setGravity(Gravity.CENTER); + view.setTextSize(textSize); + view.setLines(1); + } + if (textTypeface != null) { + view.setTypeface(textTypeface); + } else { + view.setTypeface(Typeface.DEFAULT, Typeface.NORMAL); + } + } + + /** + * Loads a text view from view + * @param view the text view or layout containing it + * @param textResource the text resource Id in layout + * @return the loaded text view + */ + private TextView getTextView(View view, int textResource) { + TextView text = null; + try { + if (textResource == NO_RESOURCE && view instanceof TextView) { + text = (TextView) view; + } else if (textResource != NO_RESOURCE) { + text = view.findViewById(textResource); + } + } catch (ClassCastException e) { + LogUtil.errorLog("AbstractWheelAdapter", "You must supply a resource ID for a TextView"); + throw new IllegalStateException( + "AbstractWheelAdapter requires the resource ID to be a TextView", e); + } + + return text; + } + + /** + * Loads view from resources + * @param resource the resource Id + * @return the loaded view or null if resource is not set + */ + private View getView(int resource, ViewGroup parent) { + switch (resource) { + case NO_RESOURCE: + return null; + case TEXT_VIEW_ITEM_RESOURCE: + return new TextView(context); + default: + return inflater.inflate(resource, parent, false); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/ArrayWheelAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/ArrayWheelAdapter.java new file mode 100644 index 0000000..919cbdc --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/ArrayWheelAdapter.java @@ -0,0 +1,52 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters; + +import android.content.Context; + +/** + * The simple Array spinnerwheel adapter + * + * @param + * the element type + */ +public class ArrayWheelAdapter extends AbstractWheelTextAdapter { + + // items + private T items[]; + + /** + * Constructor + * + * @param context + * the current context + * @param items + * the items + */ + public ArrayWheelAdapter(Context context, T items[]) { + super(context); + + // setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE); + this.items = items; + } + + public ArrayWheelAdapter(Context context, T items[], int itemResource, int itemTextResource){ + super(context, itemResource, itemTextResource); + this.items = items; + } + + @Override + public CharSequence getItemText(int index) { + if (index >= 0 && index < items.length) { + T item = items[index]; + if (item instanceof CharSequence) { + return (CharSequence) item; + } + return item.toString(); + } + return null; + } + + @Override + public int getItemsCount() { + return items.length; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/NumericWheelAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/NumericWheelAdapter.java new file mode 100644 index 0000000..82f7264 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/NumericWheelAdapter.java @@ -0,0 +1,82 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters; + +import android.content.Context; + +/** + * Numeric Wheel adapter. + */ +public class NumericWheelAdapter extends AbstractWheelTextAdapter { + + /** The default min value */ + public static final int DEFAULT_MAX_VALUE = 9; + + /** The default max value */ + private static final int DEFAULT_MIN_VALUE = 0; + + // Values + private int minValue; + private int maxValue; + + // format + private String format; + + /** + * Constructor + * + * @param context + * the current context + */ + public NumericWheelAdapter(Context context) { + this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE); + } + + /** + * Constructor + * + * @param context + * the current context + * @param minValue + * the spinnerwheel min value + * @param maxValue + * the spinnerwheel max value + */ + public NumericWheelAdapter(Context context, int minValue, int maxValue) { + this(context, minValue, maxValue, null); + } + + /** + * Constructor + * + * @param context + * the current context + * @param minValue + * the spinnerwheel min value + * @param maxValue + * the spinnerwheel max value + * @param format + * the format string + */ + public NumericWheelAdapter(Context context, int minValue, int maxValue, + String format) { + super(context); + + this.minValue = minValue; + this.maxValue = maxValue; + this.format = format; + } + + @Override + public CharSequence getItemText(int index) { + if (index >= 0 && index < getItemsCount()) { + int value = minValue + index; + return format != null ? String.format(format, value) : Integer + .toString(value); + } + return null; + } + + @Override + public int getItemsCount() { + return maxValue - minValue + 1; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/WheelViewAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/WheelViewAdapter.java new file mode 100644 index 0000000..46e47cd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/antistatic/spinnerwheel/adapters/WheelViewAdapter.java @@ -0,0 +1,48 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.antistatic.spinnerwheel.adapters; + +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; + +/** + * Wheel items adapter interface + */ +public interface WheelViewAdapter { + /** + * Gets items count + * @return the count of spinnerwheel items + */ + public int getItemsCount(); + + /** + * Get a View that displays the data at the specified position in the data set + * + * @param index the item index + * @param convertView the old view to reuse if possible + * @param parent the parent that this view will eventually be attached to + * @return the spinnerwheel item View + */ + public View getItem(int index, View convertView, ViewGroup parent); + + /** + * Get a View that displays an empty spinnerwheel item placed before the first or after + * the last spinnerwheel item. + * + * @param convertView the old view to reuse if possible + * @param parent the parent that this view will eventually be attached to + * @return the empty item View + */ + public View getEmptyItem(View convertView, ViewGroup parent); + + /** + * Register an observer that is called when changes happen to the data used by this adapter. + * @param observer the observer to be registered + */ + public void registerDataSetObserver(DataSetObserver observer); + + /** + * Unregister an observer that has previously been registered + * @param observer the observer to be unregistered + */ + void unregisterDataSetObserver (DataSetObserver observer); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/CalendarUtils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/CalendarUtils.java new file mode 100644 index 0000000..cc628e2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/CalendarUtils.java @@ -0,0 +1,181 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.TimeUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day.CalendarDay; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.month.SelectedMonth; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +public class CalendarUtils +{ + public static int getDaysInMonth(int month, int year) { + switch (month) { + case Calendar.JANUARY: + case Calendar.MARCH: + case Calendar.MAY: + case Calendar.JULY: + case Calendar.AUGUST: + case Calendar.OCTOBER: + case Calendar.DECEMBER: + return 31; + case Calendar.APRIL: + case Calendar.JUNE: + case Calendar.SEPTEMBER: + case Calendar.NOVEMBER: + return 30; + case Calendar.FEBRUARY: + return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 29 : 28; + default: + throw new IllegalArgumentException("Invalid Month"); + } + } + + // 获取本周周一 + public static CalendarDay getMonday() { + Calendar calendar = Calendar.getInstance(); + int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + if(dayOfWeek == 1) { + dayOfWeek += 7; + } + calendar.add(Calendar.DATE, 2 - dayOfWeek); + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 获取本周周日 + public static CalendarDay getSunday() { + Calendar calendar = Calendar.getInstance(); + int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + if(dayOfWeek == 1) { + dayOfWeek += 7; + } + calendar.add(Calendar.DATE, 2 - dayOfWeek); + calendar.add(Calendar.DAY_OF_WEEK, 6); + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 获取上周周一 + public static CalendarDay getLastWeekMonday() { + Calendar calendar = Calendar.getInstance(); + calendar.setFirstDayOfWeek(Calendar.MONDAY); + calendar.add(Calendar.DATE, -1 * 7); + calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 获取上周周日 + public static CalendarDay getLastWeekSunday() { + Calendar calendar = Calendar.getInstance(); + calendar.setFirstDayOfWeek(Calendar.MONDAY); + calendar.add(Calendar.DATE, -1 * 7); + calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 获取给定日期所在周的周一 + public static CalendarDay getFixedMonday(int year, int month, int day) { + Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, day); + int dayWeek = calendar.get(Calendar.DAY_OF_WEEK); + if(dayWeek == 1) { + calendar.add(Calendar.DAY_OF_MONTH, -1); + } + + calendar.setFirstDayOfWeek(Calendar.MONDAY); + int y = calendar.get(Calendar.DAY_OF_WEEK); + calendar.add(Calendar.DATE, calendar.getFirstDayOfWeek() - y); + + + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 获取给定日期所在周的周日 + public static CalendarDay getFixedSunday(int year, int month, int day) { + Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, day); + int dayWeek = calendar.get(Calendar.DAY_OF_WEEK); + if(dayWeek == 1) { + calendar.add(Calendar.DAY_OF_MONTH, -1); + } + + calendar.setFirstDayOfWeek(Calendar.MONDAY); + int y = calendar.get(Calendar.DAY_OF_WEEK); + calendar.add(Calendar.DATE, calendar.getFirstDayOfWeek() - y); + calendar.add(Calendar.DAY_OF_WEEK, 6); + return new CalendarDay(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + + // 判断给定日期是否是本周 + public static boolean isThisWeek(CalendarDay calendarDay) { + Calendar calendar = Calendar.getInstance(); + if(calendarDay.getYear() != calendar.get(Calendar.YEAR)) { + return false; + } + + int thisWeek = calendar.get(Calendar.WEEK_OF_YEAR); + + calendar.set(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()); + int week = calendar.get(Calendar.WEEK_OF_YEAR); + return thisWeek == week; + } + + // 判断给定日期是否是上周 + public static boolean isLastWeek(CalendarDay calendarDay) { + CalendarDay lastWeekMonday = getLastWeekMonday(); + Calendar lastWeekMondayCal = Calendar.getInstance(); + lastWeekMondayCal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); + lastWeekMondayCal.set(lastWeekMonday.getYear(), lastWeekMonday.getMonth(), lastWeekMonday.getDay()); + + CalendarDay lastWeekSunday = getLastWeekSunday(); + Calendar lastWeekSundayCal = Calendar.getInstance(); + lastWeekSundayCal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); + lastWeekSundayCal.set(lastWeekSunday.getYear(), lastWeekSunday.getMonth(), lastWeekSunday.getDay()); + + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); + calendar.set(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()); + +// return !calendar.before(lastWeekMondayCal) && !calendar.after(lastWeekSundayCal); + return isInTime(calendar.getTime(), lastWeekMondayCal.getTime(), lastWeekSundayCal.getTime(), "yyyy-MM-dd"); + } + + public static String getKeyByCalendarDay(CalendarDay calendarDay) { + return String.valueOf(calendarDay.getYear()) + calendarDay.getMonth() + calendarDay.getDay(); + } + + public static String getKeyByYearMonthDay(int year, int month, int day) { + return String.valueOf(year) + month + day; + } + + public static String getKeyBySelectedMonth(SelectedMonth selectedMonth) { + return String.valueOf(selectedMonth.getYear()) + selectedMonth.getMonth(); + } + + public static String getKeyByYearMonth(int year, int month) { + return String.valueOf(year) + month; + } + + // 获取给定日期所在周的周一 + public static String getKeyByFixedMonday(int year, int month, int day) { + CalendarDay calendarDay = getFixedMonday(year, month, day); + + return getKeyByYearMonthDay(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()); + } + + // 判断是否在某个时间范围之内 + public static boolean isInTime(Date date, Date before, Date after, String pattern) { + try { + SimpleDateFormat sdf = TimeUtils.getDateFormatWithUS(pattern); + String dateStr = sdf.format(date); + date = sdf.parse(dateStr); + String beforeStr = sdf.format(before); + before = sdf.parse(beforeStr); + String afterStr = sdf.format(after); + after = sdf.parse(afterStr); + return date.compareTo(before) >= 0 && date.compareTo(after) <= 0; + }catch (Exception e) { + return false; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/CalendarDay.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/CalendarDay.java new file mode 100644 index 0000000..a49451e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/CalendarDay.java @@ -0,0 +1,171 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day; + +import android.graphics.Color; + +import java.io.Serializable; +import java.util.Calendar; + +public class CalendarDay implements Serializable +{ + private static final long serialVersionUID = -5456695978688356202L; + private Calendar mCalendar; + + private int mDay; + private int mMonth; + private int mYear; + private boolean mIsToday; + private boolean mIsYesterday; + private int mColor; + + public CalendarDay() { + setTime(System.currentTimeMillis()); + } + + public CalendarDay(int year, int month, int day) { + setDay(year, month, day); + } + + private void setTime(long timeInMillis) { + if (mCalendar == null) { + mCalendar = Calendar.getInstance(); + } + mCalendar.setTimeInMillis(timeInMillis); + mMonth = mCalendar.get(Calendar.MONTH); + mYear = mCalendar.get(Calendar.YEAR); + mDay = mCalendar.get(Calendar.DAY_OF_MONTH); + generateValue(); + } + + public void setDay(int year, int month, int day) { + if (mCalendar == null) { + mCalendar = Calendar.getInstance(); + } + mYear = year; + mMonth = month; + mDay = day; + mCalendar.set(year, month, day); + generateValue(); + } + + private void setIsToday() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + int month = calendar.get(Calendar.MONTH); + int year = calendar.get(Calendar.YEAR); + int day = calendar.get(Calendar.DAY_OF_MONTH); + mIsToday = (mMonth == month && mYear == year && mDay == day); + if(mIsToday) { + mColor = Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_THIS); + } + } + + private void setIsYesterday() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + calendar.add(Calendar.DAY_OF_MONTH, -1); + int month = calendar.get(Calendar.MONTH); + int year = calendar.get(Calendar.YEAR); + int day = calendar.get(Calendar.DAY_OF_MONTH); + mIsYesterday = (mMonth == month && mYear == year && mDay == day); + if(mIsYesterday) { + mColor = Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_LAST); + } + } + + private void generateValue(){ + setIsToday(); + setIsYesterday(); + + } + + public int getDay() { + return mDay; + } + + public void setDay(int day) { + this.mDay = day; + } + + public int getMonth() { + return mMonth; + } + + public void setMonth(int month) { + this.mMonth = month; + } + + public int getYear() { + return mYear; + } + + public void setYear(int year) { + this.mYear = year; + } + + public boolean isToday() { + return mIsToday; + } + + public void setIsToday(boolean isToday) { + this.mIsToday = isToday; + } + + public boolean isYesterday() { + return mIsYesterday; + } + + public void setIsYesterday(boolean isYesterday) { + this.mIsYesterday = isYesterday; + } + + public int getColor() { + return mColor; + } + + public void setColor(int color) { + this.mColor = color; + } + + public Calendar getCalendar() { + return mCalendar; + } + + public void setCalendar(Calendar calendar) { + this.mCalendar = calendar; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mYear; + result = 31 * result + mMonth; + result = 31 * result + mDay; + return result; + } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof CalendarDay)) { + return false; + } + CalendarDay calendarDay = (CalendarDay)o; + return calendarDay.getDay() == mDay + && calendarDay.getMonth() == mMonth + && calendarDay.getYear() == mYear; + } + + @Override + public String toString() + { + String stringBuilder = "{ year: " + + mYear + + ", month: " + + mMonth + + ", day: " + + mDay + + " }"; + + return stringBuilder; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/DayPickerView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/DayPickerView.java new file mode 100644 index 0000000..f97675a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/DayPickerView.java @@ -0,0 +1,127 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; + +import com.mm.android.deviceaddmodule.R; + +import java.util.List; +import java.util.Map; + +public class DayPickerView extends RecyclerView +{ + protected Context mContext; + protected SimpleMonthAdapter mAdapter; + protected int mCurrentScrollState = 0; + protected long mPreviousScrollPosition; + protected int mPreviousScrollState = 0; + private TypedArray typedArray; + private OnScrollListener onScrollListener; + + public DayPickerView(Context context) + { + this(context, null); + } + + public DayPickerView(Context context, AttributeSet attrs) + { + this(context, attrs, 0); + } + + public DayPickerView(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + if (!isInEditMode()) + { + typedArray = context.obtainStyledAttributes(attrs, R.styleable.DayPickerView); +// setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + init(context); + } + } + + public void setController() + { + setUpAdapter(); + setAdapter(mAdapter); + } + + + public void init(Context paramContext) { + setLayoutManager(new LinearLayoutManager(paramContext)); + mContext = paramContext; + setUpListView(); + + onScrollListener = new OnScrollListener() + { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + super.onScrolled(recyclerView, dx, dy); + final SimpleMonthView child = (SimpleMonthView) recyclerView.getChildAt(0); + if (child == null) { + return; + } + + mPreviousScrollPosition = dy; + mPreviousScrollState = mCurrentScrollState; + } + }; + + } + + + protected void setUpAdapter() { + if (mAdapter == null) { + mAdapter = new SimpleMonthAdapter(getContext(), typedArray); + } + + mAdapter.notifyDataSetChanged(); + + scrollToPosition(mAdapter.getItemCount() - 1); + } + + protected void setUpListView() { + setVerticalScrollBarEnabled(false); + setOnScrollListener(onScrollListener); + setFadingEdgeLength(0); + setItemViewCacheSize(15); + } + + public Map getSelectedDayList() + { + return mAdapter.getSelectedDayList(); + } + + public void setSelectedDayList(List selectedDayList) + { + if(selectedDayList == null || selectedDayList.size() > SimpleMonthAdapter.NUM_CAN_SELECT) { + return; + } + mAdapter.setSelectedDayList(selectedDayList); + } + + public Map getSelectedWeekList() + { + return mAdapter.getSelectedWeekList(); + } + + public void setSelectedWeekList(List selectedWeekList) + { + if(selectedWeekList == null || selectedWeekList.size() > SimpleMonthAdapter.NUM_CAN_SELECT) { + return; + } + mAdapter.setSelectedWeekList(selectedWeekList); + } + + public void setModeOfDay(boolean isModeOfDay) { + mAdapter.setIsModeOfDay(isModeOfDay); + } + + protected TypedArray getTypedArray() + { + return typedArray; + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SelectedDays.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SelectedDays.java new file mode 100644 index 0000000..80e79bf --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SelectedDays.java @@ -0,0 +1,95 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day; + +import android.graphics.Color; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.CalendarUtils; + +import java.io.Serializable; + +public class SelectedDays implements Serializable +{ + private static final long serialVersionUID = 3942549765282708376L; + private CalendarDay mFirst; + private CalendarDay mLast; + private boolean mIsThisWeek; + private boolean mIsLastWeek; + + public SelectedDays(CalendarDay first, CalendarDay last) { + mFirst = first; + mLast = last; + generateVaule(); + } + + public SelectedDays(CalendarDay calendarDay) { + + this(CalendarUtils.getFixedMonday(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()), + CalendarUtils.getFixedSunday(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay())); + } + + private void generateVaule() { + mIsThisWeek = CalendarUtils.isThisWeek(mFirst); + mIsLastWeek = CalendarUtils.isLastWeek(mLast); + if(mIsThisWeek) { + mFirst.setColor(Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_THIS)); + mLast.setColor(Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_THIS)); + } else if(mIsLastWeek) { + mFirst.setColor(Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_LAST)); + mLast.setColor(Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG_LAST)); + } + } + + public boolean isThisWeek() { + return mIsThisWeek; + } + + public void setThisWeek(boolean thisWeek) { + mIsThisWeek = thisWeek; + } + + public boolean isLastWeek() { + return mIsLastWeek; + } + + public void setLastWeek(boolean lastWeek) { + mIsLastWeek = lastWeek; + } + + public CalendarDay getFirst() + { + return mFirst; + } + + public void setFirst(CalendarDay first) + { + mFirst = first; + } + + public CalendarDay getLast() + { + return mLast; + } + + public void setLast(CalendarDay last) + { + mLast = last; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mFirst.hashCode(); + result = 31 * result + mLast.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof SelectedDays)) { + return false; + } + SelectedDays selectedDays = (SelectedDays)o; + return selectedDays.getFirst().equals(mFirst) + && selectedDays.getLast().equals(mLast); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthAdapter.java new file mode 100644 index 0000000..e4a2d37 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthAdapter.java @@ -0,0 +1,224 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.AbsListView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.CalendarUtils; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class SimpleMonthAdapter extends RecyclerView.Adapter implements SimpleMonthView.OnDayClickListener { + public static final int MONTHS_IN_YEAR = 12; + public static final int NUM_CAN_SELECT = 5; //可选数量 + public static final int RANGE_CAN_SELECT = 90; // 可选日期范围 + + private final TypedArray mTypedArray; + private final Context mContext; + private final Calendar mMinCalendar; + private final Calendar mCurCalendar; + private final Integer mFirstMonth; + private final Integer mLastMonth; + private final Map mSelectedDayList; + private final Map mSelectedWeekList; + private final Set mSelectedColors; + private boolean mIsModeOfDay; + + + public SimpleMonthAdapter(Context context, TypedArray typedArray) { + mTypedArray = typedArray; + mContext = context; + + mMinCalendar = Calendar.getInstance(); + mMinCalendar.add(Calendar.DAY_OF_MONTH, -RANGE_CAN_SELECT); + mCurCalendar = Calendar.getInstance(); + mFirstMonth = mMinCalendar.get(Calendar.MONTH); + mLastMonth = (mCurCalendar.get(Calendar.MONTH)) % MONTHS_IN_YEAR; + + mSelectedDayList = new HashMap<>(NUM_CAN_SELECT); + mSelectedWeekList = new HashMap<>(NUM_CAN_SELECT); + mSelectedColors = new HashSet<>(NUM_CAN_SELECT - 2); + init(); + } + + private void init() { + mIsModeOfDay = mTypedArray.getBoolean(R.styleable.DayPickerView_modeOfDay, true); + + // 三种颜色 + int mSelectedColor1 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg1, Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG1)); + int mSelectedColor2 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg2, Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG2)); + int mSelectedColor3 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg3, Color.parseColor(SimpleMonthView.COLOR_SELECTED_BG3)); + mSelectedColors.add(mSelectedColor1); + mSelectedColors.add(mSelectedColor2); + mSelectedColors.add(mSelectedColor3); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) + { + final SimpleMonthView simpleMonthView = new SimpleMonthView(mContext, mTypedArray); + return new ViewHolder(simpleMonthView, this); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, int position) + { + final SimpleMonthView v = viewHolder.simpleMonthView; + final HashMap drawingParams = new HashMap<>(); + int month; + int year; + + month = (mFirstMonth + (position % MONTHS_IN_YEAR)) % MONTHS_IN_YEAR; + year = position / MONTHS_IN_YEAR + mMinCalendar.get(Calendar.YEAR) + ((mFirstMonth + (position % MONTHS_IN_YEAR)) / MONTHS_IN_YEAR); + + v.reuse(); + + drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year); + drawingParams.put(SimpleMonthView.VIEW_PARAMS_MONTH, month); + drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mMinCalendar.getFirstDayOfWeek()); + v.setMonthParams(drawingParams); + v.setSelectedDayList(mSelectedDayList); + v.setSelectedWeekList(mSelectedWeekList); + v.setSelectedColors(mSelectedColors); + v.setModeOfDay(mIsModeOfDay); + v.setCurrentCalendar(mCurCalendar); + v.setMinCalendar(mMinCalendar); + + v.invalidate(); + } + + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() + { + int itemCount = (((mCurCalendar.get(Calendar.YEAR) - mMinCalendar.get(Calendar.YEAR)) + 1) * MONTHS_IN_YEAR); + + itemCount -= mFirstMonth; + + itemCount -= (MONTHS_IN_YEAR - mLastMonth) - 1; + + return itemCount; + } + + public static class ViewHolder extends RecyclerView.ViewHolder + { + final SimpleMonthView simpleMonthView; + + public ViewHolder(View itemView, SimpleMonthView.OnDayClickListener onDayClickListener) + { + super(itemView); + simpleMonthView = (SimpleMonthView) itemView; + simpleMonthView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + simpleMonthView.setClickable(true); + simpleMonthView.setOnDayClickListener(onDayClickListener); + } + } + + public void onDayClick(SimpleMonthView simpleMonthView, CalendarDay calendarDay) { + if (calendarDay != null) { + setSelectedDay(calendarDay); + } + } + public void onDayClick(SimpleMonthView simpleMonthView, SelectedDays selectedDays) { + if (selectedDays != null) { + setSelectedDay(selectedDays); + } + } + + private void setSelectedDay(CalendarDay calendarDay) { + + if (calendarDay.isYesterday() || calendarDay.isToday()) { + return; + } + + if (mSelectedDayList.containsKey(CalendarUtils.getKeyByCalendarDay(calendarDay))) { + mSelectedDayList.remove(CalendarUtils.getKeyByCalendarDay(calendarDay)); + } else { + if (mSelectedDayList.size() < NUM_CAN_SELECT) { + mSelectedDayList.put(CalendarUtils.getKeyByCalendarDay(calendarDay), calendarDay); + } + } + + notifyDataSetChanged(); + } + + private void setSelectedDay(SelectedDays selectedDays) { + + if(selectedDays.isThisWeek() || selectedDays.isLastWeek()) { + return; + } + + if (mSelectedWeekList.containsKey(CalendarUtils.getKeyByCalendarDay(selectedDays.getFirst()))) { + mSelectedWeekList.remove(CalendarUtils.getKeyByCalendarDay(selectedDays.getFirst())); + } else { + if (mSelectedWeekList.size() < NUM_CAN_SELECT) { + mSelectedWeekList.put(CalendarUtils.getKeyByCalendarDay(selectedDays.getFirst()), selectedDays); + } + } + + notifyDataSetChanged(); + } + + public void setIsModeOfDay(boolean isModeOfDay) { + this.mIsModeOfDay = isModeOfDay; + } + + public Map getSelectedDayList() + { + return mSelectedDayList; + } + + public void setSelectedDayList(List selectedDayList) + { + for(CalendarDay calendarDay : selectedDayList) { + if(calendarDay != null && !mSelectedDayList.containsKey(CalendarUtils.getKeyByCalendarDay(calendarDay)) && mSelectedDayList.size() < NUM_CAN_SELECT) { + + if(!calendarDay.isToday() && !calendarDay.isYesterday()) { + Iterator it = mSelectedColors.iterator(); + if (it.hasNext()) { + calendarDay.setColor(it.next()); + it.remove(); + } + } + mSelectedDayList.put(CalendarUtils.getKeyByCalendarDay(calendarDay), calendarDay); + } + } + } + + public Map getSelectedWeekList() + { + return mSelectedWeekList; + } + + public void setSelectedWeekList(List selectedWeekList) + { + for(SelectedDays selectedDays : selectedWeekList) { + if(selectedDays != null && !mSelectedWeekList.containsKey(CalendarUtils.getKeyByCalendarDay(selectedDays.getFirst())) && mSelectedWeekList.size() < NUM_CAN_SELECT) { + if(!selectedDays.isThisWeek() && !selectedDays.isLastWeek()) { + Iterator it = mSelectedColors.iterator(); + if (it.hasNext()) { + selectedDays.getFirst().setColor(it.next()); + selectedDays.getLast().setColor(selectedDays.getFirst().getColor()); + it.remove(); + } + } + mSelectedWeekList.put(CalendarUtils.getKeyByCalendarDay(selectedDays.getFirst()), selectedDays); + } + } + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthView.java new file mode 100644 index 0000000..13cce2f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/day/SimpleMonthView.java @@ -0,0 +1,491 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Paint.Style; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.text.format.DateUtils; +import android.view.MotionEvent; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.CalendarUtils; + +import java.security.InvalidParameterException; +import java.text.DateFormatSymbols; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +public class SimpleMonthView extends View +{ + public static final String COLOR_NORMAL_DAY = "#ff999999"; + public static final String COLOR_ENABLE_DAY = "#ff999999"; + public static final String COLOR_SELECTED_BG_THIS = "#f18d00"; + public static final String COLOR_SELECTED_BG_LAST = "#7396f7"; + public static final String COLOR_SELECTED_BG1 = "#f76163"; + public static final String COLOR_SELECTED_BG2 = "#2e9b95"; + public static final String COLOR_SELECTED_BG3 = "#4ea7f2"; + + public static final String TYPE_FACE_SANS_SERIF = "Arial Regular"; + + public static final int TEXT_SIZE_DAY = 16; + public static final int TEXT_SIZE_MONTH = 16; + public static final int TEXT_SIZE_NAME = 10; + public static final int HEIGHT_HEADER_MONTH = 50; + public static final int DIMEN_SELECTED_DAY_RADIUS = 16; + public static final int HEIGHT_CALENDAR = 270; + + + public static final String VIEW_PARAMS_HEIGHT = "height"; + public static final String VIEW_PARAMS_MONTH = "month"; + public static final String VIEW_PARAMS_YEAR = "year"; + public static final String VIEW_PARAMS_WEEK_START = "week_start"; + + private static final int SELECTED_CIRCLE_ALPHA = 128; + private static int DEFAULT_HEIGHT = 32; + private static final int DEFAULT_NUM_ROWS = 6; + private static int DAY_SELECTED_CIRCLE_SIZE; + private static int DAY_SEPARATOR_WIDTH = 1; + private static int MINI_DAY_NUMBER_TEXT_SIZE; + private static int MIN_HEIGHT = 10; + private static int MONTH_DAY_LABEL_TEXT_SIZE; + private static int MONTH_HEADER_SIZE; + private static int MONTH_LABEL_TEXT_SIZE; + + private int mPadding = 0; + + private String mDayOfWeekTypeface; + private String mMonthTitleTypeface; + + private Paint mMonthDayLabelPaint; + private Paint mMonthNumPaint; + private Paint mMonthTitlePaint; + private Paint mSelectedCirclePaint; + private Paint mLinePaint; + private int mEnableDayTextColor; + private int mMonthTextColor; + private int mDayTextColor; + private int mDayNumColor; + + private int mSelectedColorThis; + private int mSelectedColorLast; + + + private final StringBuilder mStringBuilder; + + private int mWeekStart = Calendar.SUNDAY;// 一周的第一天 + private int mNumDays = 7; + private int mNumCells = mNumDays; + private int mDayOfWeekStart = 0;// 一周中的第几天 + private int mMonth; + private Boolean mDrawRect; + private Boolean mIsModeOfDay; + private int mRowHeight = DEFAULT_HEIGHT; + private int mWidth; + private int mYear; + + // 可以选择的最小时间 + private Calendar minCalendar; + // 当前时间 + private Calendar currentCalendar; + // 月标题使用的Calendar + private final Calendar mTitleCalendar; + + private int mNumRows = DEFAULT_NUM_ROWS; + + private DateFormatSymbols mDateFormatSymbols = new DateFormatSymbols(); + + private OnDayClickListener mOnDayClickListener; + + private Map selectedDayList; + private Map selectedWeekList; + private Set selectedColors; + + public SimpleMonthView(Context context, TypedArray typedArray) + { + super(context); + + mSelectedColorThis = typedArray.getColor(R.styleable.DayPickerView_colorSelectedBgThis, Color.parseColor(COLOR_SELECTED_BG_THIS)); + mSelectedColorLast = typedArray.getColor(R.styleable.DayPickerView_colorSelectedBgLast, Color.parseColor(COLOR_SELECTED_BG_LAST)); + + + mDrawRect = typedArray.getBoolean(R.styleable.DayPickerView_drawRoundRect, false); + mTitleCalendar = Calendar.getInstance(); + + mDayOfWeekTypeface = TYPE_FACE_SANS_SERIF; + mMonthTitleTypeface = TYPE_FACE_SANS_SERIF; + + mEnableDayTextColor = typedArray.getColor(R.styleable.DayPickerView_colorEnableDay, Color.parseColor(COLOR_ENABLE_DAY)); + + mMonthTextColor = typedArray.getColor(R.styleable.DayPickerView_colorMonthName, Color.parseColor(COLOR_NORMAL_DAY)); + mDayTextColor = typedArray.getColor(R.styleable.DayPickerView_colorDayName, Color.parseColor(COLOR_NORMAL_DAY)); + mDayNumColor = typedArray.getColor(R.styleable.DayPickerView_colorNormalDay, Color.parseColor(COLOR_NORMAL_DAY)); + + mStringBuilder = new StringBuilder(50); + + MINI_DAY_NUMBER_TEXT_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_textSizeDay, UIUtils.sp2px(context, TEXT_SIZE_DAY)); + MONTH_LABEL_TEXT_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_textSizeMonth, UIUtils.sp2px(context, TEXT_SIZE_MONTH)); + MONTH_DAY_LABEL_TEXT_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_textSizeDayName, UIUtils.sp2px(context, TEXT_SIZE_NAME)); + MONTH_HEADER_SIZE = typedArray.getDimensionPixelOffset(R.styleable.DayPickerView_headerMonthHeight, UIUtils.dp2px(context, HEIGHT_HEADER_MONTH)); + DAY_SELECTED_CIRCLE_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_selectedDayRadius, UIUtils.dp2px(context, DIMEN_SELECTED_DAY_RADIUS)); + + mRowHeight = ((typedArray.getDimensionPixelSize(R.styleable.DayPickerView_calendarHeight, UIUtils.dp2px(context, HEIGHT_CALENDAR)) - MONTH_HEADER_SIZE) / 6); + + initView(); + + } + + private int calculateNumRows() { + int offset = findDayOffset(); + int dividend = (offset + mNumCells) / mNumDays; + int remainder = (offset + mNumCells) % mNumDays; + return (dividend + (remainder > 0 ? 1 : 0)); + } + + private void drawMonthDayLabels(Canvas canvas) { + int y = MONTH_HEADER_SIZE - (MONTH_DAY_LABEL_TEXT_SIZE / 2) - 10; + int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); + Calendar dayLabelCalendar = Calendar.getInstance(); + + for (int i = 0; i < mNumDays; i++) { + int calendarDay = (i + mWeekStart) % mNumDays; + int x = (2 * i + 1) * dayWidthHalf + mPadding; + dayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); + canvas.drawText(mDateFormatSymbols.getShortWeekdays()[dayLabelCalendar.get(Calendar.DAY_OF_WEEK)].toUpperCase(Locale.getDefault()), x, y, mMonthDayLabelPaint); + } + + canvas.drawLine(0, y - MONTH_DAY_LABEL_TEXT_SIZE - (MONTH_HEADER_SIZE - y), mWidth , + y - MONTH_DAY_LABEL_TEXT_SIZE - (MONTH_HEADER_SIZE - y), mLinePaint); + canvas.drawLine(0, MONTH_HEADER_SIZE, mWidth , MONTH_HEADER_SIZE, mLinePaint); + } + + private void drawMonthTitle(Canvas canvas) { + int x = (mWidth + 2 * mPadding) / 2; + int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE - 20) / 2 /*+ (MONTH_LABEL_TEXT_SIZE / 3)*/; + StringBuilder stringBuilder = new StringBuilder(getMonthAndYearString().toLowerCase()); + stringBuilder.setCharAt(0, Character.toUpperCase(stringBuilder.charAt(0))); + canvas.drawText(stringBuilder.toString(), x, y, mMonthTitlePaint); + } + + private int findDayOffset() { + return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart) + - mWeekStart; + } + + private String getMonthAndYearString() { + int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_NO_MONTH_DAY; + mStringBuilder.setLength(0); + long millis = mTitleCalendar.getTimeInMillis(); + return DateUtils.formatDateRange(getContext(), millis, millis, flags); + } + + private void onDayClick(CalendarDay calendarDay) { + if (mOnDayClickListener == null) { + return; + } + + if(mIsModeOfDay) { + dayClick(calendarDay); + } else { + weekClick(calendarDay); + } + } + + private void dayClick(CalendarDay calendarDay){ + if (selectedDayList.containsKey(CalendarUtils.getKeyByCalendarDay(calendarDay))) { + CalendarDay c = selectedDayList.get(CalendarUtils.getKeyByCalendarDay(calendarDay)); + if (calendarDay.equals(c)) { + if (!calendarDay.isYesterday() && !calendarDay.isToday()) { + calendarDay.setColor(c.getColor()); + selectedColors.add(calendarDay.getColor()); + } + } + } else { + if (!calendarDay.isYesterday() && !calendarDay.isToday()) { + Iterator it = selectedColors.iterator(); + if (it.hasNext()) { + calendarDay.setColor(it.next()); + it.remove(); + } + } + } + mOnDayClickListener.onDayClick(this, calendarDay); + } + + private void weekClick(CalendarDay calendarDay) { + SelectedDays selectedDays ; + if (selectedWeekList.containsKey(CalendarUtils.getKeyByCalendarDay(CalendarUtils.getFixedMonday(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay())))) { + selectedDays = selectedWeekList.get(CalendarUtils.getKeyByCalendarDay(CalendarUtils.getFixedMonday(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()))); + if (!selectedDays.isThisWeek() && !selectedDays.isLastWeek()) { + selectedColors.add(selectedDays.getFirst().getColor()); + } + } else { + selectedDays = new SelectedDays(calendarDay); + if(!selectedDays.isThisWeek() && !selectedDays.isLastWeek()) { + Iterator it = selectedColors.iterator(); + if (it.hasNext()) { + selectedDays.getFirst().setColor(it.next()); + selectedDays.getLast().setColor(selectedDays.getFirst().getColor()); + it.remove(); + } + } + } + mOnDayClickListener.onDayClick(this, selectedDays); + } + + protected void drawMonthNums(Canvas canvas) { + int y = (mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2 - DAY_SEPARATOR_WIDTH + MONTH_HEADER_SIZE; + int lineY = mRowHeight + MONTH_HEADER_SIZE - DAY_SEPARATOR_WIDTH; + int paddingDay = (mWidth - 2 * mPadding) / (2 * mNumDays); + int dayOffset = findDayOffset(); + int day = 1; + + while (day <= mNumCells) { + int x = paddingDay * (1 + dayOffset * 2) + mPadding; + + Calendar calendar = Calendar.getInstance(); + calendar.set(mYear, mMonth, day); + + if(mIsModeOfDay) { + if (selectedDayList.containsKey(CalendarUtils.getKeyByYearMonthDay(mYear, mMonth, day))) { + setModeOfDaySelectedBgColor(day); + drawSelectedBg(canvas, x, y); + } + } else { + if (selectedWeekList.containsKey(CalendarUtils.getKeyByFixedMonday(mYear, mMonth, day)) + && CalendarUtils.isInTime(calendar.getTime(), minCalendar.getTime(), currentCalendar.getTime(), "yyyy-MM-dd")) { + setModeOfWeekSelectedBgColor(day); + drawSelectedBg(canvas, x, y); + } + } + + + if ((selectedDayList.containsKey(CalendarUtils.getKeyByYearMonthDay(mYear, mMonth, day)) + || selectedWeekList.containsKey(CalendarUtils.getKeyByFixedMonday(mYear, mMonth, day))) + && CalendarUtils.isInTime(calendar.getTime(), minCalendar.getTime(), currentCalendar.getTime(), "yyyy-MM-dd")){ + //选中的白色 + mMonthNumPaint.setColor(Color.WHITE); + } else if(CalendarUtils.isInTime(calendar.getTime(), minCalendar.getTime(), currentCalendar.getTime(), "yyyy-MM-dd")) { + //范围内的正常色 + mMonthNumPaint.setColor(mDayNumColor); + } else { + // 超过范围的日期置灰 + mMonthNumPaint.setColor(mEnableDayTextColor); + } + + canvas.drawText(String.format("%d", day), x, y, mMonthNumPaint); + + dayOffset++; + if (dayOffset == mNumDays) { + if (day != mNumCells){ + //每月最后一天刚好是周六的不绘制线 + canvas.drawLine(0, lineY, mWidth , lineY, mLinePaint); + } + dayOffset = 0; + y += mRowHeight; + lineY += mRowHeight; + } + day++; + } + } + + // 设置日模式下选中数字的背景颜色 + private void setModeOfDaySelectedBgColor(int day) { + CalendarDay c = selectedDayList.get(CalendarUtils.getKeyByYearMonthDay(mYear, mMonth, day)); + if (c.isToday()) { + c.setColor(mSelectedColorThis); + } else if (c.isYesterday()) { + c.setColor(mSelectedColorLast); + } + mSelectedCirclePaint.setColor(c.getColor()); + } + + // 设置周模式下选中数字背景颜色 + private void setModeOfWeekSelectedBgColor(int day) { + SelectedDays s = selectedWeekList.get(CalendarUtils.getKeyByFixedMonday(mYear, mMonth, day)); + if (s.isThisWeek()) { + s.getFirst().setColor(mSelectedColorThis); + s.getLast().setColor(mSelectedColorThis); + } else if (s.isLastWeek()) { + s.getFirst().setColor(mSelectedColorLast); + s.getLast().setColor(mSelectedColorLast); + } + mSelectedCirclePaint.setColor(s.getFirst().getColor()); + } + + // 画数字背景 + private void drawSelectedBg(Canvas canvas, int x, int y) { + if (mDrawRect) { + RectF rectF = new RectF(x - DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) - DAY_SELECTED_CIRCLE_SIZE, x + DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) + DAY_SELECTED_CIRCLE_SIZE); + canvas.drawRoundRect(rectF, 10.0f, 10.0f, mSelectedCirclePaint); + } else { + canvas.drawCircle(x, y - MINI_DAY_NUMBER_TEXT_SIZE / 3, DAY_SELECTED_CIRCLE_SIZE, mSelectedCirclePaint); + } + } + + public CalendarDay getDayFromLocation(float x, float y) { + int padding = mPadding; + if ((x < padding) || (x > mWidth - mPadding)) { + return null; + } + + int yDay = (int) (y - MONTH_HEADER_SIZE) / mRowHeight; + int day = 1 + ((int) ((x - padding) * mNumDays / (mWidth - padding - mPadding)) - findDayOffset()) + yDay * mNumDays; + + if (mMonth > 11 || mMonth < 0 || CalendarUtils.getDaysInMonth(mMonth, mYear) < day || day < 1) + return null; + + return new CalendarDay(mYear, mMonth, day); + } + + protected void initView() { + mMonthTitlePaint = new Paint(); +// mMonthTitlePaint.setFakeBoldText(true); + mMonthTitlePaint.setAntiAlias(true); + mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE); + mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.NORMAL)); + mMonthTitlePaint.setColor(mMonthTextColor); + mMonthTitlePaint.setTextAlign(Align.CENTER); + mMonthTitlePaint.setStyle(Style.FILL); + + mSelectedCirclePaint = new Paint(); + mSelectedCirclePaint.setFakeBoldText(true); + mSelectedCirclePaint.setAntiAlias(true); + mSelectedCirclePaint.setTextAlign(Align.CENTER); + mSelectedCirclePaint.setStyle(Style.FILL); + mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA); + + mMonthDayLabelPaint = new Paint(); + mMonthDayLabelPaint.setAntiAlias(true); + mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE); + mMonthDayLabelPaint.setColor(mDayTextColor); + mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL)); + mMonthDayLabelPaint.setStyle(Style.FILL); + mMonthDayLabelPaint.setTextAlign(Align.CENTER); +// mMonthDayLabelPaint.setFakeBoldText(true); + + mMonthNumPaint = new Paint(); + mMonthNumPaint.setAntiAlias(true); + mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE); + mMonthNumPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL)); + mMonthNumPaint.setStyle(Style.FILL); + mMonthNumPaint.setTextAlign(Align.CENTER); + mMonthNumPaint.setFakeBoldText(false); + + mLinePaint = new Paint(); + mLinePaint.setAntiAlias(true); + mLinePaint.setStyle(Style.FILL); + mLinePaint.setStrokeWidth(UIUtils.dip2px(getContext(), 0.5f)); + mLinePaint.setColor(Color.parseColor("#eeeeee")); + } + + protected void onDraw(Canvas canvas) { + drawMonthTitle(canvas); + drawMonthDayLabels(canvas); + drawMonthNums(canvas); + } + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows + MONTH_HEADER_SIZE); + } + + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mWidth = w; + } + + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + CalendarDay calendarDay = getDayFromLocation(event.getX(), event.getY()); + if (calendarDay != null) { + + Calendar calendar = Calendar.getInstance(); + calendar.set(calendarDay.getYear(), calendarDay.getMonth(), calendarDay.getDay()); + // 超过范围不能点击 + if(!calendar.before(minCalendar) && !calendar.after(currentCalendar)) { + + onDayClick(calendarDay); + } + } + } + return true; + } + + public void reuse() { + mNumRows = DEFAULT_NUM_ROWS; + requestLayout(); + } + + public void setMonthParams(HashMap params) { + if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) { + throw new InvalidParameterException("You must specify month and year for this view"); + } + setTag(params); + + if (params.containsKey(VIEW_PARAMS_HEIGHT)) { + mRowHeight = params.get(VIEW_PARAMS_HEIGHT); + if (mRowHeight < MIN_HEIGHT) { + mRowHeight = MIN_HEIGHT; + } + } + + mMonth = params.get(VIEW_PARAMS_MONTH); + mYear = params.get(VIEW_PARAMS_YEAR); + + mTitleCalendar.set(Calendar.MONTH, mMonth); + mTitleCalendar.set(Calendar.YEAR, mYear); + mTitleCalendar.set(Calendar.DAY_OF_MONTH, 1);// 一个月中的第几天 + mDayOfWeekStart = mTitleCalendar.get(Calendar.DAY_OF_WEEK);// 一周中的第几天 + + if (params.containsKey(VIEW_PARAMS_WEEK_START)) { + mWeekStart = params.get(VIEW_PARAMS_WEEK_START); + } else { + mWeekStart = mTitleCalendar.getFirstDayOfWeek();// 一周的第一天 + } + + mNumCells = CalendarUtils.getDaysInMonth(mMonth, mYear); + mNumRows = calculateNumRows(); + } + + public void setSelectedDayList(Map selectedDayList) { + this.selectedDayList = selectedDayList; + } + + public void setSelectedWeekList(Map selectedWeekList) { + this.selectedWeekList = selectedWeekList; + } + + public void setSelectedColors(Set selectedColors) { + this.selectedColors = selectedColors; + } + + public void setModeOfDay(boolean isModeOfDay) { + this.mIsModeOfDay = isModeOfDay; + } + + public void setCurrentCalendar(Calendar calendar) { + this.currentCalendar = calendar; + } + + public void setMinCalendar(Calendar calendar) { + this.minCalendar = calendar; + } + + public void setOnDayClickListener(OnDayClickListener onDayClickListener) { + mOnDayClickListener = onDayClickListener; + } + + public static abstract interface OnDayClickListener { + void onDayClick(SimpleMonthView simpleMonthView, CalendarDay calendarDay); + void onDayClick(SimpleMonthView simpleMonthView, SelectedDays selectedDays); + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthPickerView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthPickerView.java new file mode 100644 index 0000000..4116e2b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthPickerView.java @@ -0,0 +1,111 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.month; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day.SimpleMonthAdapter; + +import java.util.List; +import java.util.Map; + +public class MonthPickerView extends RecyclerView +{ + protected Context mContext; + protected MonthSelectAdapter mAdapter; + protected int mCurrentScrollState = 0; + protected long mPreviousScrollPosition; + protected int mPreviousScrollState = 0; + private TypedArray typedArray; + private OnScrollListener onScrollListener; + + public MonthPickerView(Context context) + { + this(context, null); + } + + public MonthPickerView(Context context, AttributeSet attrs) + { + this(context, attrs, 0); + } + + public MonthPickerView(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + if (!isInEditMode()) + { + typedArray = context.obtainStyledAttributes(attrs, R.styleable.DayPickerView); +// setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + init(context); + } + } + + public void setController() + { + setUpAdapter(); + setAdapter(mAdapter); + } + + + public void init(Context paramContext) { + setLayoutManager(new LinearLayoutManager(paramContext)); + mContext = paramContext; + setUpListView(); + + onScrollListener = new OnScrollListener() + { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + super.onScrolled(recyclerView, dx, dy); + final MonthSelectView child = (MonthSelectView) recyclerView.getChildAt(0); + if (child == null) { + return; + } + + mPreviousScrollPosition = dy; + mPreviousScrollState = mCurrentScrollState; + } + }; + + } + + + protected void setUpAdapter() { + if (mAdapter == null) { + mAdapter = new MonthSelectAdapter(getContext(), typedArray); + } + + mAdapter.notifyDataSetChanged(); + + scrollToPosition(mAdapter.getItemCount() - 1); + } + + protected void setUpListView() { + setVerticalScrollBarEnabled(false); + setOnScrollListener(onScrollListener); + setFadingEdgeLength(0); + setItemViewCacheSize(15); + } + + public Map getSelectedMonthList() + { + return mAdapter.getSelectedMonthList(); + } + + public void setSelectedMonthList(List selectedMonthList) + { + if(selectedMonthList == null || selectedMonthList.size() > SimpleMonthAdapter.NUM_CAN_SELECT) { + return; + } + mAdapter.setSelectedMonthList(selectedMonthList); + } + + protected TypedArray getTypedArray() + { + return typedArray; + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectAdapter.java new file mode 100644 index 0000000..02b0877 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectAdapter.java @@ -0,0 +1,162 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.month; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.AbsListView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.CalendarUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.day.SimpleMonthView; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class MonthSelectAdapter extends RecyclerView.Adapter implements MonthSelectView.OnDayClickListener { + public static final int NUM_CAN_SELECT = 5; //可选数量 + public static final int RANGE_CAN_SELECT = 36; // 可选月范围 + + private final TypedArray mTypedArray; + private final Context mContext; + private final Calendar mMinCalendar; + private final Calendar mCurCalendar; + + private final Map mSelectedMonthList; + private final Set mSelectedColors; + + public MonthSelectAdapter(Context context, TypedArray typedArray) { + mTypedArray = typedArray; + mContext = context; + + mMinCalendar = Calendar.getInstance(); + mMinCalendar.add(Calendar.MONTH, - RANGE_CAN_SELECT); + mCurCalendar = Calendar.getInstance(); + + mSelectedMonthList = new HashMap<>(NUM_CAN_SELECT); + mSelectedColors = new HashSet<>(NUM_CAN_SELECT - 2); + init(); + } + + private void init() { + // 三种颜色 + int mSelectedColor1 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg1, Color.parseColor(MonthSelectView.COLOR_SELECTED_BG1)); + int mSelectedColor2 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg2, Color.parseColor(MonthSelectView.COLOR_SELECTED_BG2)); + int mSelectedColor3 = mTypedArray.getColor(R.styleable.DayPickerView_colorSelectedBg3, Color.parseColor(MonthSelectView.COLOR_SELECTED_BG3)); + mSelectedColors.add(mSelectedColor1); + mSelectedColors.add(mSelectedColor2); + mSelectedColors.add(mSelectedColor3); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) + { + final MonthSelectView simpleMonthView = new MonthSelectView(mContext, mTypedArray); + return new ViewHolder(simpleMonthView, this); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, int position) + { + final MonthSelectView v = viewHolder.simpleMonthView; + final HashMap drawingParams = new HashMap<>(); + + int year = mMinCalendar.get(Calendar.YEAR) + position; + + v.reuse(); + + drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year); + drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mMinCalendar.getFirstDayOfWeek()); + v.setMonthParams(drawingParams); + v.setSelectedMonthList(mSelectedMonthList); + v.setSelectedColors(mSelectedColors); + v.setCurrentCalendar(mCurCalendar); + v.setMinCalendar(mMinCalendar); + + v.invalidate(); + } + + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() + { + int itemCount = (mCurCalendar.get(Calendar.YEAR) - mMinCalendar.get(Calendar.YEAR)) + 1; + + return itemCount; + } + + public static class ViewHolder extends RecyclerView.ViewHolder + { + final MonthSelectView simpleMonthView; + + public ViewHolder(View itemView, MonthSelectView.OnDayClickListener onDayClickListener) + { + super(itemView); + simpleMonthView = (MonthSelectView) itemView; + simpleMonthView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + simpleMonthView.setClickable(true); + simpleMonthView.setOnDayClickListener(onDayClickListener); + } + } + + public void onDayClick(MonthSelectView simpleMonthView, SelectedMonth selectedMonth) { + if (selectedMonth != null) { + setSelectedMonth(selectedMonth); + } + } + + + private void setSelectedMonth(SelectedMonth selectedMonth) { + + if (selectedMonth.isThisMonth() || selectedMonth.isLastMonth()) { + return; + } + + if (mSelectedMonthList.containsKey(CalendarUtils.getKeyBySelectedMonth(selectedMonth))) { + mSelectedMonthList.remove(CalendarUtils.getKeyBySelectedMonth(selectedMonth)); + } else { + if (mSelectedMonthList.size() < NUM_CAN_SELECT) { + mSelectedMonthList.put(CalendarUtils.getKeyBySelectedMonth(selectedMonth), selectedMonth); + } + } + + notifyDataSetChanged(); + } + + + + public Map getSelectedMonthList() + { + return mSelectedMonthList; + } + + public void setSelectedMonthList(List selectedMonthList) + { + for(SelectedMonth selectedMonth : selectedMonthList) { + if(selectedMonth != null && !mSelectedMonthList.containsKey(CalendarUtils.getKeyBySelectedMonth(selectedMonth)) && mSelectedMonthList.size() < NUM_CAN_SELECT) { + + if(!selectedMonth.isThisMonth() && !selectedMonth.isLastMonth()) { + Iterator it = mSelectedColors.iterator(); + if (it.hasNext()) { + selectedMonth.setColor(it.next()); + it.remove(); + } + } + mSelectedMonthList.put(CalendarUtils.getKeyBySelectedMonth(selectedMonth), selectedMonth); + } + } + } + + +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectView.java new file mode 100644 index 0000000..bf54184 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/MonthSelectView.java @@ -0,0 +1,384 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.month; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Paint.Style; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.view.MotionEvent; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.CalendarUtils; + +import java.security.InvalidParameterException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class MonthSelectView extends View { + public static final String COLOR_NORMAL_DAY = "#ff999999"; + public static final String COLOR_ENABLE_DAY = "#ff999999"; + public static final String COLOR_SELECTED_BG_THIS = "#f18d00"; + public static final String COLOR_SELECTED_BG_LAST = "#7396f7"; + public static final String COLOR_SELECTED_BG1 = "#f76163"; + public static final String COLOR_SELECTED_BG2 = "#2e9b95"; + public static final String COLOR_SELECTED_BG3 = "#4ea7f2"; + + public static final String TYPE_FACE_SANS_SERIF = "Arial Regular"; + + public static final int TEXT_SIZE_DAY = 16; + public static final int TEXT_SIZE_MONTH = 16; + public static final int TEXT_SIZE_NAME = 10; + public static final int HEIGHT_HEADER_MONTH = 50; + public static final int DIMEN_SELECTED_DAY_RADIUS = 22; + public static final int HEIGHT_CALENDAR = 270; + + + public static final String VIEW_PARAMS_HEIGHT = "height"; + public static final String VIEW_PARAMS_YEAR = "year"; + + private static final int SELECTED_CIRCLE_ALPHA = 128; + private static int DEFAULT_HEIGHT = 32; + private static final int DEFAULT_NUM_ROWS = 4; + private static int DAY_SELECTED_CIRCLE_SIZE; + private static int DAY_SEPARATOR_WIDTH = 1; + private static int MINI_DAY_NUMBER_TEXT_SIZE; + private static int MIN_HEIGHT = 10; + private static int MONTH_HEADER_SIZE; + private static int MONTH_LABEL_TEXT_SIZE; + + private int mPadding = 0; + + private String mDayOfWeekTypeface; + private String mMonthTitleTypeface; + + private Paint mMonthNumPaint; + private Paint mMonthTitlePaint; + private Paint mSelectedCirclePaint; + private Paint mLinePaint; + private int mEnableDayTextColor; + private int mMonthTextColor; + private int mDayTextColor; + private int mDayNumColor; + + private int mSelectedColorThis; + private int mSelectedColorLast; + + + private final StringBuilder mStringBuilder; + + private int mNumDays = 3; + private int mNumCells = mNumDays; + private Boolean mDrawRect; + private int mRowHeight = DEFAULT_HEIGHT; + private int mWidth; + private int mYear; + + // 可以选择的最小时间 + private Calendar minCalendar; + // 当前时间 + private Calendar currentCalendar; + // 月标题使用的Calendar + private final Calendar mTitleCalendar; + + private int mNumRows = DEFAULT_NUM_ROWS; + + private OnDayClickListener mOnDayClickListener; + + private Map selectedMonthList; + private Set selectedColors; + + public MonthSelectView(Context context, TypedArray typedArray) { + super(context); + + mSelectedColorThis = typedArray.getColor(R.styleable.DayPickerView_colorSelectedBgThis, Color.parseColor(COLOR_SELECTED_BG_THIS)); + mSelectedColorLast = typedArray.getColor(R.styleable.DayPickerView_colorSelectedBgLast, Color.parseColor(COLOR_SELECTED_BG_LAST)); + + + mDrawRect = typedArray.getBoolean(R.styleable.DayPickerView_drawRoundRect, false); + mTitleCalendar = Calendar.getInstance(); + + mDayOfWeekTypeface = TYPE_FACE_SANS_SERIF; + mMonthTitleTypeface = TYPE_FACE_SANS_SERIF; + + mEnableDayTextColor = typedArray.getColor(R.styleable.DayPickerView_colorEnableDay, Color.parseColor(COLOR_ENABLE_DAY)); + + mMonthTextColor = typedArray.getColor(R.styleable.DayPickerView_colorMonthName, Color.parseColor(COLOR_NORMAL_DAY)); + mDayTextColor = typedArray.getColor(R.styleable.DayPickerView_colorDayName, Color.parseColor(COLOR_NORMAL_DAY)); + mDayNumColor = typedArray.getColor(R.styleable.DayPickerView_colorNormalDay, Color.parseColor(COLOR_NORMAL_DAY)); + + mStringBuilder = new StringBuilder(50); + + MINI_DAY_NUMBER_TEXT_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_textSizeDay, UIUtils.sp2px(context, TEXT_SIZE_DAY)); + MONTH_LABEL_TEXT_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_textSizeMonth, UIUtils.sp2px(context, TEXT_SIZE_MONTH)); + MONTH_HEADER_SIZE = typedArray.getDimensionPixelOffset(R.styleable.DayPickerView_headerMonthHeight, UIUtils.dp2px(context, HEIGHT_HEADER_MONTH)); + DAY_SELECTED_CIRCLE_SIZE = typedArray.getDimensionPixelSize(R.styleable.DayPickerView_selectedDayRadius, UIUtils.dp2px(context, DIMEN_SELECTED_DAY_RADIUS)); + + mRowHeight = ((typedArray.getDimensionPixelSize(R.styleable.DayPickerView_calendarHeight, UIUtils.dp2px(context, HEIGHT_CALENDAR)) - MONTH_HEADER_SIZE) / 6); + + initView(); + + } + + private void drawMonthTitle(Canvas canvas) { + int x = (mWidth + 2 * mPadding) / 2; + int y = MONTH_HEADER_SIZE / 2 + (MONTH_LABEL_TEXT_SIZE / 3); + canvas.drawText(getYearString(), x, y, mMonthTitlePaint); + canvas.drawLine(0, MONTH_HEADER_SIZE, mWidth , MONTH_HEADER_SIZE, mLinePaint); + } + + + private String getYearString() { + int year = mTitleCalendar.get(Calendar.YEAR); + return getContext().getResources().getString(R.string.device_manager_report_month_select_year, year); + } + + private void onDayClick(SelectedMonth selectedMonth) { + if (mOnDayClickListener == null) { + return; + } + + dayClick(selectedMonth); + + } + + private void dayClick(SelectedMonth selectedMonth) { + if (selectedMonthList.containsKey(CalendarUtils.getKeyBySelectedMonth(selectedMonth))) { + SelectedMonth c = selectedMonthList.get(CalendarUtils.getKeyBySelectedMonth(selectedMonth)); + if (selectedMonth.equals(c)) { + if (!selectedMonth.isLastMonth() && !selectedMonth.isThisMonth()) { + selectedMonth.setColor(c.getColor()); + selectedColors.add(selectedMonth.getColor()); + } + } + } else { + if (!selectedMonth.isLastMonth() && !selectedMonth.isThisMonth()) { + Iterator it = selectedColors.iterator(); + if (it.hasNext()) { + selectedMonth.setColor(it.next()); + it.remove(); + } + } + } + mOnDayClickListener.onDayClick(this, selectedMonth); + } + + + protected void drawMonthNums(Canvas canvas) { + int y = (mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2 - DAY_SEPARATOR_WIDTH + MONTH_HEADER_SIZE; + int lineY = mRowHeight + MONTH_HEADER_SIZE - DAY_SEPARATOR_WIDTH; + int paddingDay = (mWidth - 2 * mPadding) / (2 * mNumDays); + int dayOffset = 0; + int month = 0; + + //取12月的文字长度(这里偷懒不再遍历最长的文字,直接取12月份的) + float textWidth = mMonthNumPaint.measureText(getContext().getResources().getString(R.string.device_manager_report_month_select_month, 12)) - 10; + + while (month < mNumCells) { + int x = paddingDay * (1 + dayOffset * 2) + mPadding; + + if (selectedMonthList.containsKey(CalendarUtils.getKeyByYearMonth(mYear, month))) { + setModeOfDaySelectedBgColor(month); + drawSelectedBg(canvas, x, y, textWidth); + } + + + Calendar calendar = Calendar.getInstance(); + calendar.set(mYear, month, 1); + + if (selectedMonthList.containsKey(CalendarUtils.getKeyByYearMonth(mYear, month))){ + //选中的白色 + mMonthNumPaint.setColor(Color.WHITE); + } else if (CalendarUtils.isInTime(calendar.getTime(), minCalendar.getTime(), currentCalendar.getTime(), "yyyy-MM")) { + //范围内的正常色 + mMonthNumPaint.setColor(mDayNumColor); + } else { + // 超过范围的日期置灰 + mMonthNumPaint.setColor(mEnableDayTextColor); + } + + canvas.drawText(getContext().getResources().getString(R.string.device_manager_report_month_select_month, month + 1), x, y, mMonthNumPaint); + + dayOffset++; + if (dayOffset == mNumDays) { + canvas.drawLine(0, lineY, mWidth , lineY, mLinePaint); + dayOffset = 0; + y += mRowHeight; + lineY += mRowHeight; + } + month++; + } + } + + // 设置选中数字的背景颜色 + private void setModeOfDaySelectedBgColor(int month) { + SelectedMonth c = selectedMonthList.get(CalendarUtils.getKeyByYearMonth(mYear, month)); + if (c.isThisMonth()) { + c.setColor(mSelectedColorThis); + } else if (c.isLastMonth()) { + c.setColor(mSelectedColorLast); + } + mSelectedCirclePaint.setColor(c.getColor()); + } + + + // 画数字背景 + private void drawSelectedBg(Canvas canvas, int x, int y, float textWidth) { + if (mDrawRect) { + RectF rectF = new RectF(x - DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) - DAY_SELECTED_CIRCLE_SIZE, x + DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) + DAY_SELECTED_CIRCLE_SIZE); + canvas.drawRoundRect(rectF, 10.0f, 10.0f, mSelectedCirclePaint); + } else { + int centerX = x; //文字中心X + int centerY = y - MINI_DAY_NUMBER_TEXT_SIZE / 3; //文字中心Y + int offset = 5; //由于设置了抗锯齿,防止部分手机上出现拼接出现间隙。重叠绘制一小部分 + + RectF center = new RectF(centerX - textWidth/2, centerY - DAY_SELECTED_CIRCLE_SIZE, + centerX + textWidth/2, centerY + DAY_SELECTED_CIRCLE_SIZE); + canvas.drawRect(center, mSelectedCirclePaint); + + //左半边圆弧 + RectF ovalLeft = new RectF(centerX + offset - textWidth/2 - DAY_SELECTED_CIRCLE_SIZE, centerY - DAY_SELECTED_CIRCLE_SIZE, + centerX + offset - textWidth/2 + DAY_SELECTED_CIRCLE_SIZE, centerY + DAY_SELECTED_CIRCLE_SIZE); + canvas.drawArc(ovalLeft, 90, 180, true, mSelectedCirclePaint); + + //右半边圆弧 + RectF ovalRight = new RectF(centerX - offset + textWidth/2 - DAY_SELECTED_CIRCLE_SIZE , centerY - DAY_SELECTED_CIRCLE_SIZE, + centerX - offset + textWidth/2 + DAY_SELECTED_CIRCLE_SIZE, centerY + DAY_SELECTED_CIRCLE_SIZE); + canvas.drawArc(ovalRight, -90, 180, true, mSelectedCirclePaint); + } + } + + public SelectedMonth getDayFromLocation(float x, float y) { + int padding = mPadding; + if ((x < padding) || (x > mWidth - mPadding)) { + return null; + } + + int yDay = (int) (y - MONTH_HEADER_SIZE) / mRowHeight; + int month = ((int) ((x - padding) * mNumDays / (mWidth - padding - mPadding))) + yDay * mNumDays; + + return new SelectedMonth(mYear, month); + } + + protected void initView() { + mMonthTitlePaint = new Paint(); +// mMonthTitlePaint.setFakeBoldText(true); + mMonthTitlePaint.setAntiAlias(true); + mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE); + mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.NORMAL)); + mMonthTitlePaint.setColor(mMonthTextColor); + mMonthTitlePaint.setTextAlign(Align.CENTER); + mMonthTitlePaint.setStyle(Style.FILL); + + mSelectedCirclePaint = new Paint(); + mSelectedCirclePaint.setFakeBoldText(true); + mSelectedCirclePaint.setAntiAlias(true); + mSelectedCirclePaint.setTextAlign(Align.CENTER); + mSelectedCirclePaint.setStyle(Style.FILL); + mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA); + + mMonthNumPaint = new Paint(); + mMonthNumPaint.setAntiAlias(true); + mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE); + mMonthNumPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL)); + mMonthNumPaint.setStyle(Style.FILL); + mMonthNumPaint.setTextAlign(Align.CENTER); + mMonthNumPaint.setFakeBoldText(false); + + mLinePaint = new Paint(); + mLinePaint.setAntiAlias(true); + mLinePaint.setStyle(Style.FILL); + mLinePaint.setStrokeWidth(UIUtils.dip2px(getContext(), 0.5f)); + mLinePaint.setColor(Color.parseColor("#eeeeee")); + } + + protected void onDraw(Canvas canvas) { + drawMonthTitle(canvas); + drawMonthNums(canvas); + } + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows + MONTH_HEADER_SIZE); + } + + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mWidth = w; + } + + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + SelectedMonth selectedMonth = getDayFromLocation(event.getX(), event.getY()); + if (selectedMonth != null) { + + Calendar calendar = Calendar.getInstance(); + calendar.set(selectedMonth.getYear(), selectedMonth.getMonth(), 1); + // 超过范围不能点击 + if (!calendar.before(minCalendar) && !calendar.after(currentCalendar)) { + + onDayClick(selectedMonth); + } + } + } + return true; + } + + public void reuse() { + mNumRows = DEFAULT_NUM_ROWS; + requestLayout(); + } + + public void setMonthParams(HashMap params) { + if (!params.containsKey(VIEW_PARAMS_YEAR)) { + throw new InvalidParameterException("You must specify year for this view"); + } + setTag(params); + + if (params.containsKey(VIEW_PARAMS_HEIGHT)) { + mRowHeight = params.get(VIEW_PARAMS_HEIGHT); + if (mRowHeight < MIN_HEIGHT) { + mRowHeight = MIN_HEIGHT; + } + } + + mYear = params.get(VIEW_PARAMS_YEAR); + + mTitleCalendar.set(Calendar.YEAR, mYear); + + mNumCells = 12; + mNumRows = 4; + } + + public void setSelectedMonthList(Map selectedMonthList) { + this.selectedMonthList = selectedMonthList; + } + + + public void setSelectedColors(Set selectedColors) { + this.selectedColors = selectedColors; + } + + + public void setCurrentCalendar(Calendar calendar) { + this.currentCalendar = calendar; + } + + public void setMinCalendar(Calendar calendar) { + this.minCalendar = calendar; + } + + public void setOnDayClickListener(OnDayClickListener onDayClickListener) { + mOnDayClickListener = onDayClickListener; + } + + public static abstract interface OnDayClickListener { + void onDayClick(MonthSelectView simpleMonthView, SelectedMonth selectedMonth); + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/SelectedMonth.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/SelectedMonth.java new file mode 100644 index 0000000..b7217b9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/calendar/month/SelectedMonth.java @@ -0,0 +1,153 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.calendar.month; + +import android.graphics.Color; + +import java.io.Serializable; +import java.util.Calendar; + +public class SelectedMonth implements Serializable +{ + private static final long serialVersionUID = -5456695978688356205L; + private Calendar mCalendar; + + private int mMonth; + private int mYear; + private boolean mIsThisMonth; + private boolean mIsLastMonth; + private int mColor; + + public SelectedMonth() { + setTime(System.currentTimeMillis()); + } + + public SelectedMonth(int year, int month) { + setDay(year, month); + } + + private void setTime(long timeInMillis) { + if (mCalendar == null) { + mCalendar = Calendar.getInstance(); + } + mCalendar.setTimeInMillis(timeInMillis); + mMonth = mCalendar.get(Calendar.MONTH); + mYear = mCalendar.get(Calendar.YEAR); + generateValue(); + } + + public void setDay(int year, int month) { + mYear = year; + mMonth = month; + if (mCalendar == null) { + mCalendar = Calendar.getInstance(); + } + mCalendar.set(year, month, 1); + generateValue(); + } + + private void setIsThisMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + int month = calendar.get(Calendar.MONTH); + int year = calendar.get(Calendar.YEAR); + mIsThisMonth = (mMonth == month && mYear == year); + if(mIsThisMonth) { + mColor = Color.parseColor(MonthSelectView.COLOR_SELECTED_BG_THIS); + } + } + + private void setIsLastMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + calendar.add(Calendar.MONTH, -1); + int month = calendar.get(Calendar.MONTH); + int year = calendar.get(Calendar.YEAR); + mIsLastMonth = (mMonth == month && mYear == year); + if(mIsLastMonth) { + mColor = Color.parseColor(MonthSelectView.COLOR_SELECTED_BG_LAST); + } + } + + private void generateValue(){ + setIsThisMonth(); + setIsLastMonth(); + } + + public int getMonth() { + return mMonth; + } + + public void setMonth(int month) { + this.mMonth = month; + } + + public int getYear() { + return mYear; + } + + public void setYear(int year) { + this.mYear = year; + } + + public boolean isThisMonth() { + return mIsThisMonth; + } + + public void setIsThisMonth(boolean isThisMonth) { + this.mIsThisMonth = isThisMonth; + } + + public boolean isLastMonth() { + return mIsLastMonth; + } + + public void setIsLastMonth(boolean isLastMonth) { + this.mIsLastMonth = isLastMonth; + } + + public int getColor() { + return mColor; + } + + public void setColor(int color) { + this.mColor = color; + } + + public Calendar getCalendar() { + return mCalendar; + } + + public void setCalendar(Calendar calendar) { + this.mCalendar = calendar; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mYear; + result = 31 * result + mMonth; + return result; + } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof SelectedMonth)) { + return false; + } + SelectedMonth calendarDay = (SelectedMonth)o; + return calendarDay.getMonth() == mMonth + && calendarDay.getYear() == mYear; + } + + @Override + public String toString() + { + String stringBuilder = "{ year: " + + mYear + + ", month: " + + mMonth + + " }"; + + return stringBuilder; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/ChartHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/ChartHelper.java new file mode 100644 index 0000000..958fa18 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/ChartHelper.java @@ -0,0 +1,169 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.DayHighLightValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.DefaultValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.MonthHighLightValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.ReportValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.WeekHighLightValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.YearHighLightValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts.LineChart; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Lines; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.Axis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.HighLight; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.XAxis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.YAxis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.ArrayList; +import java.util.List; + +public class ChartHelper { + private static final int dayXCount = 24; + private static final int weekXCount = 7; + private static final int monthXCount = 31; + private static final int yearXCount = 12; + + private LineChart _lineChart; + private int linesNumber=0; + + private String duration; + + private List lineEntities; + + public ChartHelper(LineChart _lineChart) { + this._lineChart = _lineChart; + } + + public void displayChart() { + + _lineChart.setCanX_drag(true);// x 方向可以拖拽 + _lineChart.setCanY_drag(false);// y 方向不可拖拽 + _lineChart.setCanX_zoom(true);// x 方向可以缩放 + _lineChart.setCanY_zoom(false);// y 方向不可用缩放 + _lineChart.setZoom_alone(false);// 设置在 x,y方向上是否要独立缩放 + + setAxis(_lineChart); + setNumberData(); + setHighLight(_lineChart); + } + + private void setHighLight(LineChart lineChart) { + // 高亮 + HighLight highLight = lineChart.get_HighLight(); + highLight.setEnable(!(linesNumber > 1));// 启用高亮显示 默认为启用状态 + highLight.setDrawHint(false); + switch (duration) { + case "day": + highLight.setxValueAdapter(new DayHighLightValueAdapter()); + break; + case "week": + highLight.setxValueAdapter(new WeekHighLightValueAdapter()); + break; + case "month": + highLight.setxValueAdapter(new MonthHighLightValueAdapter()); + break; + case "year": + highLight.setxValueAdapter(new YearHighLightValueAdapter()); + break; + } + } + + private void setAxis(LineChart lineChart) { + duration = getDuration(); + + if (duration == null) { + return; + } + +// // x,y轴上的单位 + XAxis xAxis = lineChart.get_XAxis(); + xAxis.set_labelCountAdvice(4); + xAxis.set_ValueAdapter(new DefaultValueAdapter(0)); + xAxis.setLabelTextSize(Utils.sp2px(12)); + + YAxis yAxis = lineChart.get_YAxis(); + yAxis.set_labelCountAdvice(6); + yAxis.setCalWay(Axis.CalWay.perfect); + yAxis.set_ValueAdapter(new ReportValueAdapter()); + yAxis.setLabelTextSize(Utils.sp2px(12)); + + + switch (duration) { + case "day": + xAxis.setCalWay(Axis.CalWay.lc_day); + break; + case "week": + xAxis.setCalWay(Axis.CalWay.lc_week); + break; + case "month": + xAxis.setCalWay(Axis.CalWay.lc_month); + break; + case "year": + xAxis.setCalWay(Axis.CalWay.lc_year); + break; + } + + _lineChart.set_paddingLeft(0); + _lineChart.set_paddingBottom(0); + } + + private void setNumberData() { + linesNumber = 0; + Lines lines = new Lines(); + lines.setXCustomMaxMin(false); + + for(int i = 0; i < lineEntities.size(); i++) { + LineEntity lineEntity = lineEntities.get(i); + + List listEntriesNow = new ArrayList<>(); + if (lineEntity.isVisible()) { + int count = dayXCount; + switch (duration) { + case "day": + count = dayXCount; + break; + case "week": + count = weekXCount; + break; + case "month": + count = monthXCount; + break; + case "year": + count = yearXCount; + break; + } + + long[] data = lineEntity.getData(); + for(int j = 0; j < count; j++) { + if (data.length > j) { + listEntriesNow.add(new Entry(j, data[j])); + } + } + + Line line = new Line(); + line.setLineColor(lineEntity.getColor()); + line.setEntries(listEntriesNow); + lines.addLine(line); + linesNumber++; + setHighLight(_lineChart); + } + } + + _lineChart.setLines(lines); + + } + + public String getDuration() { + return duration; + } + + public void setDuration(String duration) { + this.duration = duration; + } + + public void setLineEntities(List lineEntities) { + this.lineEntities = lineEntities; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/LineEntity.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/LineEntity.java new file mode 100644 index 0000000..be09525 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/LineEntity.java @@ -0,0 +1,37 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart; + +public class LineEntity { + private long[] data; + private int color; + private boolean visible; + + public LineEntity(long[] data, int color, boolean visible) { + this.data = data; + this.color = color; + this.visible = visible; + } + + public long[] getData() { + return data; + } + + public void setData(long[] data) { + this.data = data; + } + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DayHighLightValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DayHighLightValueAdapter.java new file mode 100644 index 0000000..40be1a7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DayHighLightValueAdapter.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +/** + * 按天显示的报表,气泡X轴显示适配器 + */ + +public class DayHighLightValueAdapter implements IValueAdapter { + private DecimalFormat _formatter; + + public DayHighLightValueAdapter() { + } + + @Override + public String value2String(double value) { + return String.format("%02d:00", (int)value); + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultHighLightValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultHighLightValueAdapter.java new file mode 100644 index 0000000..4975311 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultHighLightValueAdapter.java @@ -0,0 +1,15 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + + +public class DefaultHighLightValueAdapter implements IValueAdapter { + + public DefaultHighLightValueAdapter() { + + } + + @Override + public String value2String(double value) { + return (int)value + ""; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultValueAdapter.java new file mode 100644 index 0000000..c7ce1f8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/DefaultValueAdapter.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +public class DefaultValueAdapter implements IValueAdapter { + + + private DecimalFormat _formatter; + protected int _digits = 0; + + public DefaultValueAdapter(int digits) { + _digits = digits; + + StringBuffer b = new StringBuffer(); + for (int i = 0; i < _digits; i++) { + if (i == 0) + b.append("."); + b.append("0"); + } + + _formatter = new DecimalFormat("###,###,###,##0" + b.toString()); + } + + @Override + public String value2String(double value) { + return _formatter.format(value); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/IValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/IValueAdapter.java new file mode 100644 index 0000000..71e92e9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/IValueAdapter.java @@ -0,0 +1,5 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +public interface IValueAdapter { + String value2String(double value); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/MonthHighLightValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/MonthHighLightValueAdapter.java new file mode 100644 index 0000000..d8bdf23 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/MonthHighLightValueAdapter.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +/** + * 按月显示的报表,气泡X轴显示适配器 + */ + +public class MonthHighLightValueAdapter implements IValueAdapter { + private DecimalFormat _formatter; + + public MonthHighLightValueAdapter() { + } + + @Override + public String value2String(double value) { + return (int)value + "日"; + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/ReportValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/ReportValueAdapter.java new file mode 100644 index 0000000..362a39f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/ReportValueAdapter.java @@ -0,0 +1,30 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +/** + * 报表Y轴单位文案适配器 + * 大于1000的按照1.0k显示 + */ + +public class ReportValueAdapter implements IValueAdapter { + private DecimalFormat _formatter; + + public ReportValueAdapter() { + _formatter = new DecimalFormat("###,###,###,###.0" + "k"); + } + + @Override + public String value2String(double value) { + //这里文案的长度会用来计算,负值需要处理 + value = Math.abs(value); + if (value >= 1000){ + return _formatter.format(value / 1000); + }else if (value < 10){ + return new DecimalFormat("0.#").format(value); + }else { + return new DecimalFormat("###").format(value); + } + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/WeekHighLightValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/WeekHighLightValueAdapter.java new file mode 100644 index 0000000..a7b2552 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/WeekHighLightValueAdapter.java @@ -0,0 +1,44 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +/** + * 按周显示的报表,气泡X轴显示适配器 + */ + +public class WeekHighLightValueAdapter implements IValueAdapter { + private DecimalFormat _formatter; + + public WeekHighLightValueAdapter() { + } + + @Override + public String value2String(double value) { + String str = ""; + switch ((int)value){ + case 1: + str = "周一"; + break; + case 2: + str = "周二"; + break; + case 3: + str = "周三"; + break; + case 4: + str = "周四"; + break; + case 5: + str = "周五"; + break; + case 6: + str = "周六"; + break; + case 7: + str = "周日"; + break; + } + return str; + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/YearHighLightValueAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/YearHighLightValueAdapter.java new file mode 100644 index 0000000..e7152bd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/adapter/YearHighLightValueAdapter.java @@ -0,0 +1,20 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter; + +import java.text.DecimalFormat; + +/** + * 按年显示的报表,气泡X轴显示适配器 + */ + +public class YearHighLightValueAdapter implements IValueAdapter { + private DecimalFormat _formatter; + + public YearHighLightValueAdapter() { + } + + @Override + public String value2String(double value) { + return String.format("%02d月", (int)value); + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/animate/LAnimator.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/animate/LAnimator.java new file mode 100644 index 0000000..fd492fc --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/animate/LAnimator.java @@ -0,0 +1,79 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.animate; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts.LineChart; + + +public class LAnimator { + + float _hitValueY = 1; + float _hitValueX = 1; + + LineChart _LineChart; + + public LAnimator(LineChart lineChart) { + this._LineChart = lineChart; + } + + + public void animateX(long duration) { + ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); + animator.setDuration(1000); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + _hitValueX = (float) animation.getAnimatedValue(); + + _LineChart.postInvalidate(); + } + }); + animator.start(); + } + + public void animateY(long duration) { + ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); + animator.setDuration(1000); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + _hitValueY = (float) animation.getAnimatedValue(); + + _LineChart.postInvalidate(); + } + }); + animator.start(); + } + + public void animateXY(long duration) { + ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); + animator.setDuration(1000); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + _hitValueX = (float) animation.getAnimatedValue(); + _hitValueY = _hitValueX; + + _LineChart.postInvalidate(); + } + }); + animator.start(); + } + + public float get_hitValueY() { + return _hitValueY; + } + + public void set_hitValueY(float _hitValueY) { + this._hitValueY = _hitValueY; + } + + public float get_hitValueX() { + return _hitValueX; + } + + public void set_hitValueX(float _hitValueX) { + this._hitValueX = _hitValueX; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/Chart.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/Chart.java new file mode 100644 index 0000000..0c77787 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/Chart.java @@ -0,0 +1,44 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + + +public abstract class Chart extends View { + + public Chart(Context context) { + this(context, null, 0); + } + + public Chart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public Chart(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + + protected void init(Context context, AttributeSet attrs) { + // 采用硬件加速 + setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int size = 100; + int width = resolveSize(size, widthMeasureSpec); + int height = resolveSize(size, heightMeasureSpec); + + setMeasuredDimension(width, height); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/LineChart.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/LineChart.java new file mode 100644 index 0000000..20b6d66 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/charts/LineChart.java @@ -0,0 +1,805 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.IValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.animate.LAnimator; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Lines; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.listener.IDragListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.Axis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.HighLight; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.XAxis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.YAxis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.GodRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.HighLightRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.LineRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.NoDataRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.XAxisRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render.YAxisRender; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.touch.GodTouchListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.touch.TouchListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.RectD; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleD_XY; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.List; + + +public class LineChart extends Chart { + + MappingManager _MappingManager; + + Lines _lines; + + //////////////////////////// listener /////////////////////////// + IDragListener _dragListener; + + ////////////////////////// function ////////////////////////// + boolean isHighLightEnabled = true; + boolean isTouchEnabled = true; + boolean isDragable = true; + boolean isScaleable = true; + ChartMode _ChartMode; + + ///////////////////////////////// parts //////////////////////////////// + XAxis _XAxis; + YAxis _YAxis; + HighLight _HighLight; + + ////////////////////////////////// render ///////////////////////////// + NoDataRender _NoDataRender; + XAxisRender _XAxisRender; + YAxisRender _YAxisRender; + LineRender _LineRender; + HighLightRender _HighLightRender; + GodRender _GodRender; + + + ////////////////////////////// touch ///////////////////////////// + TouchListener _TouchListener; + GodTouchListener _GodTouchListener; + + //////////////////////////// 区域 /////////////////////////// + RectF _MainPlotRect;// 主要的绘图区域 + + float _paddingLeft = 40; + float _paddingRight = 5; +// float _paddingTop = 17; + float _paddingTop = 37; +// float _paddingBottom = 15; + float _paddingBottom = 25; + + RectF _GodRect;// + + ////////////////////////////// animator //////////////////////////// + LAnimator _LAnimator; + + + public LineChart(Context context) { + super(context); + } + + public LineChart(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LineChart(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void init(Context context, AttributeSet attributeSet) { + super.init(context, attributeSet); + + TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.LineChart); + boolean isGodMode = typedArray.getBoolean(R.styleable.LineChart_god_mode, false); + _ChartMode = isGodMode ? ChartMode.God : ChartMode.Normal; + typedArray.recycle(); + + // animator + _LAnimator = new LAnimator(this); + + // init v + _MainPlotRect = new RectF(); + _MappingManager = new MappingManager(_MainPlotRect); + _GodRect = new RectF(); + + // models + _XAxis = new XAxis(); + _YAxis = new YAxis(); + _HighLight = new HighLight(); + + // render + _NoDataRender = new NoDataRender(_MainPlotRect, _MappingManager); + _XAxisRender = new XAxisRender(_MainPlotRect, _MappingManager, _XAxis); + _YAxisRender = new YAxisRender(_MainPlotRect, _MappingManager, _YAxis); + _LineRender = new LineRender(_MainPlotRect, _MappingManager, _lines, this); + _HighLightRender = new HighLightRender(context,_MainPlotRect, _MappingManager, _lines, _HighLight); + _GodRender = new GodRender(_MainPlotRect, _MappingManager, _GodRect); + + // touch listener + _TouchListener = new TouchListener(this); + _GodTouchListener = new GodTouchListener(this); + + // other + _paddingLeft = Utils.dp2px(_paddingLeft); + _paddingRight = Utils.dp2px(_paddingRight); + _paddingTop = Utils.dp2px(_paddingTop); + _paddingBottom = Utils.dp2px(_paddingBottom); + } + + + @Override + public void computeScroll() { + super.computeScroll(); + + if (_ChartMode == ChartMode.Normal) { + _TouchListener.computeScroll(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + + if (_lines == null) { + return false; + } + if (!isTouchEnabled) { + return false; + } + + if (_ChartMode == ChartMode.Normal) { + return _TouchListener.onTouch(this, event); + } else if (_ChartMode == ChartMode.God) { + return _GodTouchListener.onTouch(this, event); + } + + return false; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // 1. render no data + if (_lines == null || _lines.getLines() == null || _lines.getLines().size() == 0) { +// _NoDataRender.render(canvas); + + + _XAxis.calValues(getVisiableMinX(), getVisiableMaxX(), null); + _YAxis.calValues(getVisiableMinY(), getVisiableMaxY(), null); + + _YAxisRender.renderGridline(canvas); + + // render labels + _XAxisRender.renderLabels(canvas); + _YAxisRender.renderLabels(canvas); + + // render unit + _XAxisRender.renderUnit(canvas); + _YAxisRender.renderUnit(canvas); + + + return; + } + + // 计算轴线上的数值 + Line line = _lines.getLines().get(0); + _XAxis.calValues(getVisiableMinX(), getVisiableMaxX(), line); + _YAxis.calValues(getVisiableMinY(), getVisiableMaxY(), line); + + + // render grid line +// _XAxisRender.renderGridline(canvas); + _YAxisRender.renderGridline(canvas); + + // render line + _LineRender.render(canvas); + + // render god + if (_ChartMode == ChartMode.God) { + _GodRender.render(canvas); + } + + + // render high light,放到刻度虚线后面画,防止被Gridline遮挡 + _HighLightRender.render(canvas); + + + // render warn line + _XAxisRender.renderWarnLine(canvas); + _YAxisRender.renderWarnLine(canvas); + + // render Axis +// _XAxisRender.renderAxisLine(canvas); +// _YAxisRender.renderAxisLine(canvas); + + // render labels + _XAxisRender.renderLabels(canvas); + _YAxisRender.renderLabels(canvas); + + // render unit + _XAxisRender.renderUnit(canvas); + _YAxisRender.renderUnit(canvas); + + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + _LineRender.onChartSizeChanged(w, h); + notifyDataChanged(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + _lines = null; + } + + /** + * 通知数据改变 + */ + public void notifyDataChanged() { + + limitMainPlotArea(); + + if (_lines == null) { + return; + } + _lines.calMinMax(); + + prepareMap(); + + // 2. onDataChanged + _LineRender.onDataChanged(_lines); + _HighLightRender.onDataChanged(_lines); + } + + /** + * 限制 主绘图区域的边界 + */ + private void limitMainPlotArea() { + + _MainPlotRect.setEmpty(); + _MainPlotRect.right += _MainPlotRect.left + getWidth(); + _MainPlotRect.bottom += _MainPlotRect.top + getHeight(); + + // 0. padding + offsetPadding(); + // 1. 计算label,unit的宽高 + offsetArea(); + + if (_ChartMode == ChartMode.God) { + _GodRect.set(_MainPlotRect); + _GodRect.right = _GodRect.right / 3; + } + } + + private void offsetPadding() { + + // 考虑图例 + if (_lines != null) { + int h = 0; + for (Line line : _lines.getLines()) { + if (line.getLegendHeight() > h) { + h = line.getLegendHeight(); + } + } + + if (h > 0) { + _paddingTop = h; + } + } + + _MainPlotRect.left += _paddingLeft; + _MainPlotRect.top += _paddingTop; + _MainPlotRect.right -= _paddingRight; + _MainPlotRect.bottom -= _paddingBottom; + } + + private void offsetArea() { + + _YAxisRender.paint_label(); + _YAxisRender.paint_unit(); + Paint paintLabel = _YAxisRender.get_PaintLabel(); + Paint paintUnit = _YAxisRender.get_PaintUnit(); + + /******************************* 取一堆label中的head middle tail 中的最大值 ***********************************/ + float labelDimen = _YAxis.getLabelDimen(); + + if (_lines != null && _lines.getLines().size() > 0) { + Line line = _lines.getLines().get(0); + + if (line.getEntries().size() > 0) { + List entryList = line.getEntries(); + + Entry head = entryList.get(0); + Entry tail = entryList.get(entryList.size() - 1); + Entry middle = entryList.get(( entryList.size() - 1) / 2); + + IValueAdapter yAdapter = _YAxis.get_ValueAdapter(); + String s1 = yAdapter.value2String(head.getY()); + float w1 = Utils.textWidth(paintLabel, s1); + if (labelDimen < w1) { + labelDimen = w1; + } + + String s2 = yAdapter.value2String(middle.getY()); + float w2 = Utils.textWidth(paintLabel, s2); + if (labelDimen < w2) { + labelDimen = w2; + } + + String s3 = yAdapter.value2String(tail.getY()); + float w3 = Utils.textWidth(paintLabel, s3); + if (labelDimen < w3) { + labelDimen = w3; + } + } + + } + + // 考虑y label和unit + _MainPlotRect.left += _YAxis.offsetLeft(labelDimen, Utils.textHeight(paintUnit)); + // 考虑x label和unit + _MainPlotRect.bottom -= _XAxis.offsetBottom(Utils.textHeight(paintLabel), Utils.textHeight(paintUnit)); + } + + + /** + * 准备映射关系 + */ + private void prepareMap() { + double xMin = _lines.getmXMin(); + double xMax = _lines.getmXMax(); + double yMin = _lines.getmYMin(); + double yMax = _lines.getmYMax(); + + if (yMin == 0 && yMax == 0){ + yMax = 10; + yMin = 0; + } + + if (_lines.getLines().size() == 0){ + yMax = 10; + yMin = 0; + + Axis.CalWay calWay = get_XAxis().getCalWay(); + if (calWay == Axis.CalWay.lc_day){ + xMin = - 23.d/30; + xMax = 23.d*31/30; + }else if (calWay == Axis.CalWay.lc_week){ + xMin = - 6.d/30; + xMax = 6.d*31/30; + }else if (calWay == Axis.CalWay.lc_month){ + xMin = - 30.d/30; + xMax = 30.d*31/30; + }else if (calWay == Axis.CalWay.lc_year){ + xMin = - 11.d/30; + xMax = 11.d*31/30; + } + + } + + _MappingManager.prepareRelation(xMin, xMax, yMin, yMax); + } + + /** + * 设置数据源 + * + * @param lines + */ + public void setLines(Lines lines) { + _lines = lines; + + notifyDataChanged(); + postInvalidate(); + } + + public Lines getlines() { + return _lines; + } + + /** + * 清空数据 + */ + public void clearData() { + _lines = null; + invalidate(); + } + + + private void A______________________________________________() { + + } + + /** + * Y方向进行动画 + */ + @UiThread + public void animateY() { + _LAnimator.animateY(1000); + } + + /** + * Y方向进行动画 + */ + @UiThread + public void animateY(long duration) { + _LAnimator.animateY(duration); + } + + /** + * X方向进行动画 + */ + @UiThread + public void animateX() { + _LAnimator.animateX(1000); + } + + /** + * X方向进行动画 + */ + @UiThread + public void animateX(long duration) { + _LAnimator.animateX(duration); + } + + /** + * X,Y方向进行动画 + */ + @UiThread + public void animateXY() { + _LAnimator.animateXY(1000); + } + + /** + * X,Y方向进行动画 + */ + @UiThread + public void animateXY(long duration) { + _LAnimator.animateXY(duration); + } + + public LAnimator get_LAnimator() { + return _LAnimator; + } + + public void set_LAnimator(LAnimator _LAnimator) { + this._LAnimator = _LAnimator; + } + + + private void B_________________________________________________() { + + } + + private void a______________________________________________() { + + } + + public boolean isCanX_drag() { + return _TouchListener.isCanX_drag(); + } + + /** + * 设置x方向是否可拖动 + * + * @param canX_drag + */ + public void setCanX_drag(boolean canX_drag) { + _TouchListener.setCanX_drag(canX_drag); + } + + public boolean isCanY_drag() { + return _TouchListener.isCanY_drag(); + } + + /** + * 设置y方向是否可拖动 + * + * @param canY_drag + */ + public void setCanY_drag(boolean canY_drag) { + _TouchListener.setCanY_drag(canY_drag); + } + + public boolean isZoom_alone() { + return _TouchListener.isZoom_alone(); + } + + /** + * 设置x,y方向是否可以独立缩放 + * + * @param zoom_independent + */ + public void setZoom_alone(boolean zoom_independent) { + _TouchListener.setZoom_alone(zoom_independent); + } + + public boolean isCanX_zoom() { + return _TouchListener.isCanX_zoom(); + } + + /** + * 设置x方向是否可以缩放 + * + * @param canX_zoom + */ + public void setCanX_zoom(boolean canX_zoom) { + _TouchListener.setCanX_zoom(canX_zoom); + } + + public boolean isCanY_zoom() { + return _TouchListener.isCanY_zoom(); + } + + /** + * 设置y方向是否可以缩放 + * + * @param canY_zoom + */ + public void setCanY_zoom(boolean canY_zoom) { + _TouchListener.setCanY_zoom(canY_zoom); + } + + public boolean isDragable() { + return isDragable; + } + + public void setDragable(boolean dragable) { + isDragable = dragable; + } + + public boolean isScaleable() { + return isScaleable; + } + + public void setScaleable(boolean scaleable) { + isScaleable = scaleable; + } + + public IDragListener get_dragListener() { + return _dragListener; + } + + public void set_dragListener(IDragListener _dragListener) { + this._dragListener = _dragListener; + } + + private void b______________________________________________() { + + } + + public float get_paddingLeft() { + return _paddingLeft; + } + + public void set_paddingLeft(float _paddingLeft) { + this._paddingLeft = _paddingLeft; + } + + public float get_paddingRight() { + return _paddingRight; + } + + public void set_paddingRight(float _paddingRight) { + this._paddingRight = _paddingRight; + } + + public float get_paddingTop() { + return _paddingTop; + } + + public void set_paddingTop(float _paddingTop) { + this._paddingTop = _paddingTop; + } + + public float get_paddingBottom() { + return _paddingBottom; + } + + public void set_paddingBottom(float _paddingBottom) { + this._paddingBottom = _paddingBottom; + } + + private void c______________________________________________() { + + } + + public double getVisiableMinX() { + float px = _MainPlotRect.left; + SingleD_XY xy = _MappingManager.getValueByPx(px, 0); + return xy.getX(); + } + + public double getVisiableMaxX() { + float px = _MainPlotRect.right; + SingleD_XY xy = _MappingManager.getValueByPx(px, 0); + return xy.getX(); + } + + public double getVisiableMinY() { + float py = _MainPlotRect.bottom; + SingleD_XY xy = _MappingManager.getValueByPx(0, py); + return xy.getY(); + } + + public double getVisiableMaxY() { + float py = _MainPlotRect.top; + SingleD_XY xy = _MappingManager.getValueByPx(0, py); + return xy.getY(); + } + + public RectD get_currentViewPort() { + return _MappingManager.get_currentViewPort(); + } + + public void set_currentViewPort(RectD currentViewPort) { + _MappingManager.set_currentViewPort(currentViewPort); + } + + /** + * 设置y轴的范围 + * + * @param yMin + * @param yMax + */ + public void setYMax_Min(double yMin, double yMax) { + if (_lines != null) { + _lines.setYCustomMaxMin(true); + _lines.setmYMin(yMin); + _lines.setmYMax(yMax); + postInvalidate(); + } else { + LogUtil.errorLog("setAxisMaxMin:", " 请在lines设置后,调用此方法!"); + } + } + + /** + * 设置轴线的范围 + * + * @param xMin + * @param xMax + */ + public void setXAix_MaxMin(double xMin, double xMax) { + if (_lines != null) { + _lines.setXCustomMaxMin(true); + _lines.setmXMin(xMin); + _lines.setmXMax(xMax); + postInvalidate(); + } else { + LogUtil.errorLog("setAxisMaxMin:"," 请在lines设置后,调用此方法!"); + } + } + + private void d______________________________________________() { + + } + + /** + * 获取映射管家 + * + * @return + */ + public MappingManager get_MappingManager() { + return _MappingManager; + } + + + //////////////////////////////// 便捷的方法 ////////////////////////////////// + + public void highLight_PixXY(float px, float py) { + SingleD_XY xy = _MappingManager.getValueByPx(px, py); + highLight_ValueXY(xy.getX(), xy.getY()); + } + + public void highLight_ValueXY(double x, double y) { + _HighLightRender.highLight_ValueXY(x, y); + invalidate(); + } + + public void highLightLeft() { + _HighLightRender.highLightLeft(); + invalidate(); + } + + public void highLightRight() { + _HighLightRender.highLightRight(); + invalidate(); + } + + public HighLight get_HighLight() { + return _HighLight; + } + + public void set_HighLight(HighLight _HighLight) { + this._HighLight = _HighLight; + } + + public XAxis get_XAxis() { + return _XAxis; + } + + public YAxis get_YAxis() { + return _YAxis; + } + + public RectF get_GodRect() { + return _GodRect; + } + + public void set_GodRect(RectF _GodRect) { + this._GodRect = _GodRect; + } + + public RectF get_MainPlotRect() { + return _MainPlotRect; + } + + public void set_MainPlotRect(RectF _MainPlotRect) { + this._MainPlotRect = _MainPlotRect; + } + + public ChartMode get_ChartMode() { + return _ChartMode; + } + + public LineChart set_ChartMode(ChartMode _ChartMode) { + this._ChartMode = _ChartMode; + return this; + } + + LineChart _ob_linechart; + + public void registObserver(LineChart lineChartOb) { + this._ob_linechart = lineChartOb; + + notifyDataChanged_FromOb(lineChartOb); + } + + public void notifyDataChanged_FromOb(LineChart lineChartOb) { + + // x,y轴上的单位 + XAxis xAxis = lineChartOb.get_XAxis(); + this.get_XAxis().set_unit(xAxis.get_unit()); + + YAxis yAxis = lineChartOb.get_YAxis(); + this.get_YAxis().set_unit(yAxis.get_unit()); + + this.setLines(lineChartOb.getlines()); + } + + public void notifyOB_ViewportChanged(RectD _currentViewPort) { + _ob_linechart.set_CurrentViewPort(_currentViewPort); + _ob_linechart.invalidate(); + } + + public LineChart set_CurrentViewPort(RectD _currentViewPort) { + _MappingManager.set_currentViewPort(_currentViewPort); + return this; + } + + + public enum ChartMode { + Normal, God + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Entry.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Entry.java new file mode 100644 index 0000000..5a8ac90 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Entry.java @@ -0,0 +1,47 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data; + +public class Entry { + + double x; + double y; + + boolean isNull_Y = false; + + public Entry(double x, double y) { + this.x = x; + this.y = y; + } + + + public double getX() { + return x; + } + + public Entry setX(double x) { + this.x = x; + return this; + } + + public double getY() { + return y; + } + + public Entry setY(double y) { + this.y = y; + return this; + } + + public boolean isNull_Y() { + return isNull_Y; + } + + public Entry setNull_Y() { + isNull_Y = true; + return this; + } + + @Override + public String toString() { + return "entry x:" + x + " y:" + y; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Line.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Line.java new file mode 100644 index 0000000..84ed88f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Line.java @@ -0,0 +1,385 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data; + +import android.graphics.Color; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.ArrayList; +import java.util.List; + + +public class Line { + + private List entries = new ArrayList<>(); + + + private double mYMax = Double.MIN_VALUE; + private double mYMin = Double.MAX_VALUE; + private double mXMax = Double.MIN_VALUE; + private double mXMin = Double.MAX_VALUE; + + private int lineColor = Color.BLACK; + private int lineWidth = (int) Utils.dp2px(1); //px + private int circleColor = Color.RED; + private int circleR = 2; + + private boolean isFilled = false; + private int lineAlpha = 50; + + private boolean isEnable = true; + private boolean isDrawCircle = true; + private boolean isDrawLegend = false; + private int legendWidth = 50; + private int legendHeight = 17; + private int legendTextSize = 8; + private String name = "line"; + + private CallBack_OnEntryClick onEntryClick; + + public Line() { + this(null); + } + + public Line(List entries) { + + circleR = (int) Utils.dp2px(circleR); + legendWidth = (int) Utils.dp2px(legendWidth); + legendTextSize = (int) Utils.dp2px(legendTextSize); + legendHeight = (int) Utils.dp2px(legendHeight); + + if (entries != null) { + setEntries(entries); + } + } + + private void calMinMax(List entries) { + + mYMax = -Double.MAX_VALUE; + mYMin = Double.MAX_VALUE; + mXMax = -Double.MAX_VALUE; + mXMin = Double.MAX_VALUE; + + for (Entry entry : entries) { + + if (entry.getX() < mXMin) { + mXMin = entry.getX(); + } + if (entry.getX() > mXMax) { + mXMax = entry.getX(); + } + + if (entry.getY() < mYMin) { + mYMin = entry.getY(); + } + if (entry.getY() > mYMax) { + mYMax = entry.getY(); + } + } + } + + /** + * 在数组的前面添加数据 + * + * @param entry + */ + public void addEntryInHead(Entry entry) { + if (entries == null) { + entries = new ArrayList<>(); + } + entries.add(0, entry); + + // 计算最大最小 + if (entry.getX() < mXMin) { + mXMin = entry.getX(); + } + if (entry.getX() > mXMax) { + mXMax = entry.getX(); + } + + if (entry.getY() < mYMin) { + mYMin = entry.getY(); + } + if (entry.getY() > mYMax) { + mYMax = entry.getY(); + } + } + + public void addEntry(Entry entry) { + if (entries == null) { + entries = new ArrayList<>(); + } + entries.add(entry); + + // 计算最大最小 + if (entry.getX() < mXMin) { + mXMin = entry.getX(); + } + if (entry.getX() > mXMax) { + mXMax = entry.getX(); + } + + if (entry.getY() < mYMin) { + mYMin = entry.getY(); + } + if (entry.getY() > mYMax) { + mYMax = entry.getY(); + } + } + + public List getEntries() { + return entries; + } + + public void setEntries(List entries) { + // check + if (entries == null) { + throw new IllegalArgumentException("entries must be no null"); + } + + this.entries = entries; + + calMinMax(entries); + } + + + /** + * 根据提供的 x数值,找出list中离它最近的数,返回其下标。 + * -------------- + * 考虑到性能的原因,采用二分查找法。(速度很快,不错!) + * + * @param entries + * @param hitValue + * @param rounding + * @return + */ + public static int getEntryIndex(List entries, double hitValue, Rounding rounding) { + + if (entries == null || entries.isEmpty()) + return -1; + + int low = 0; + int high = entries.size() - 1; + int closet = low; + + while (low < high) { + int m = (low + high) / 2; + + double fm = entries.get(m).getX();// middle + double fr = entries.get(m + 1).getX();// right + + if (hitValue >= fm && hitValue <= fr) { + + // 中_右 + double d1 = Math.abs(hitValue - fm); + double d2 = Math.abs(hitValue - fr); + + if (d1 <= d2) { + closet = m; + } else { + closet = m + 1; + } + + low = high = closet; + break; + + } else if (hitValue < fm) { + + if (m >= 1) { + double fl = entries.get(m - 1).getX();// left + + if (hitValue >= fl && hitValue <= fm) { + // 中_左 + double d0 = Math.abs(hitValue - fl); + double d1 = Math.abs(hitValue - fm); + + if (d0 <= d1) { + closet = m - 1; + } else { + closet = m; + } + + low = high = closet; + break; + } + } + + high = m - 1; + closet = high; + } else if (hitValue > fr) { + low = m + 1; + closet = low; + } + } + + // trick + high++; + low--; + closet = Math.min(Math.max(closet, 0), entries.size() - 1); + + int result = low; + if (rounding == Rounding.UP) { + result = Math.min(high, entries.size() - 1);//多一个 + } else if (rounding == Rounding.DOWN) { + result = Math.max(low, 0);//少一个 + } else if (rounding == Rounding.CLOSEST) { + result = closet; + } + return result; + } + + + public double getmYMax() { + return mYMax; + } + + public void setmYMax(double mYMax) { + this.mYMax = mYMax; + } + + public double getmYMin() { + return mYMin; + } + + public void setmYMin(double mYMin) { + this.mYMin = mYMin; + } + + public double getmXMax() { + return mXMax; + } + + public void setmXMax(double mXMax) { + this.mXMax = mXMax; + } + + public double getmXMin() { + return mXMin; + } + + public void setmXMin(double mXMin) { + this.mXMin = mXMin; + } + + public int getLineColor() { + return lineColor; + } + + public void setLineColor(int lineColor) { + this.lineColor = lineColor; + } + + public int getLineWidth() { + return lineWidth; + } + + public void setLineWidth(int lineWidth) { + this.lineWidth = lineWidth; + } + + public boolean isEnable() { + return isEnable; + } + + public void setEnable(boolean enable) { + isEnable = enable; + } + + public boolean isDrawCircle() { + return isDrawCircle; + } + + public void setDrawCircle(boolean drawCircle) { + isDrawCircle = drawCircle; + } + + public int getLegendHeight() { + return legendHeight; + } + + public void setLegendHeight(int legendHeight) { + this.legendHeight = legendHeight; + } + + public int getLegendTextSize() { + return legendTextSize; + } + + public void setLegendTextSize(int legendTextSize) { + this.legendTextSize = legendTextSize; + } + + public int getLegendWidth() { + return legendWidth; + } + + public void setLegendWidth(int legendWidth) { + this.legendWidth = legendWidth; + } + + public boolean isDrawLegend() { + return isDrawLegend; + } + + public void setDrawLegend(boolean drawLegend) { + isDrawLegend = drawLegend; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getCircleR() { + return circleR; + } + + public void setCircleR(int circleR) { + this.circleR = circleR; + } + + public int getCircleColor() { + return circleColor; + } + + public void setCircleColor(int circleColor) { + this.circleColor = circleColor; + } + + public CallBack_OnEntryClick getOnEntryClick() { + return onEntryClick; + } + + public void setOnEntryClick(CallBack_OnEntryClick onEntryClick) { + this.onEntryClick = onEntryClick; + } + + public boolean isFilled() { + return isFilled; + } + + public void setFilled(boolean filled) { + isFilled = filled; + } + + public int getLineAlpha() { + return lineAlpha; + } + + public void setLineAlpha(int lineAlpha) { + this.lineAlpha = lineAlpha; + } + + public enum Rounding { + UP, + DOWN, + CLOSEST, + } + + public interface CallBack_OnEntryClick { + void onEntry(Line line, Entry entry); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Lines.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Lines.java new file mode 100644 index 0000000..023386b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/data/Lines.java @@ -0,0 +1,152 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data; + +import java.util.ArrayList; +import java.util.List; + + +public class Lines { + + private List lines = new ArrayList<>(); + + /************************ x,y的范围 **********************/ + private double mYMax; + private double mYMin; + private double mXMax; + private double mXMin; + + /** + * 是否使用 设置的最小最大值 + */ + private boolean isYCustomMaxMin = false; + /** + * 是否使用 设置的最小最大值 + */ + private boolean isXCustomMaxMin = false; + + public Lines() { + } + + public Lines(List lines) { + setLines(lines); + } + + public List getLines() { + return lines; + } + + public void setLines(List lines) { + this.lines = lines; + calMinMax(lines); + } + + public void addLine(Line line) { + lines.add(line); + calMinMax(lines); + } + + private void calMinMax(List lines) { + + if (!isXCustomMaxMin) { + mXMax = Double.MIN_VALUE; + mXMin = Double.MAX_VALUE; + } + + if (!isYCustomMaxMin) { +// mYMax = Double.MIN_VALUE; + mYMax = 0; + mYMin = Double.MAX_VALUE; + } + + for (Line line : lines) { + + if (!isXCustomMaxMin) { + if (line.getmXMin() < mXMin) { + mXMin = - line.getmXMax()/30; + + } + if (line.getmXMax() > mXMax) { + mXMax = line.getmXMax()*31/30; + } + } + + if (!isYCustomMaxMin) { + if (line.getmYMin() < mYMin) { + mYMin = line.getmYMin(); + + } + if (line.getmYMax() > mYMax) { + mYMax = line.getmYMax(); + } + } + } + + // 考虑到只有一个点的问题 + if (mXMax == mXMin) { + double half = Math.abs(mXMax) / 2; + mXMax += half; + mXMin -= half; + } + + if (mYMax == mYMin) { + double half = Math.abs(mYMax) / 2; + mYMax += half; + mYMin -= half; + } + } + + public void calMinMax() { + + if (lines != null) { + calMinMax(lines); + } + } + + + public double getmYMax() { + return mYMax; + } + + public void setmYMax(double mYMax) { + this.mYMax = mYMax; + } + + public double getmYMin() { + return mYMin; + } + + public void setmYMin(double mYMin) { + this.mYMin = mYMin; + } + + public double getmXMax() { + return mXMax; + } + + public void setmXMax(double mXMax) { + this.mXMax = mXMax; + } + + public double getmXMin() { + return mXMin; + } + + public void setmXMin(double mXMin) { + this.mXMin = mXMin; + } + + public boolean isYCustomMaxMin() { + return isYCustomMaxMin; + } + + public void setYCustomMaxMin(boolean customMaxMin) { + isYCustomMaxMin = customMaxMin; + } + + public boolean isXCustomMaxMin() { + return isXCustomMaxMin; + } + + public void setXCustomMaxMin(boolean XCustomMaxMin) { + isXCustomMaxMin = XCustomMaxMin; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/listener/IDragListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/listener/IDragListener.java new file mode 100644 index 0000000..b44e8c5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/listener/IDragListener.java @@ -0,0 +1,9 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.listener; + +public interface IDragListener { + /** + * @param xMin 当前图谱中可见的x轴上的最小值 + * @param xMax 当前图谱中可见的x轴上的最大值 + */ + void onDrag(double xMin, double xMax); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/manager/MappingManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/manager/MappingManager.java new file mode 100644 index 0000000..68ef3c8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/manager/MappingManager.java @@ -0,0 +1,305 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager; + +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.RectD; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleD_XY; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; + + +/** + * 数据源与绘出来的图之间的映射关系 + * ------------------- + * 人与照片直接的映射关系 + *

    + */ + +public class MappingManager { + + /** + * 区域视图 + */ + RectF _contentRect; + + /** + * 数据视图 + */ + RectD _maxViewPort; + RectD _currentViewPort; + + + /** + * 数据视图的约束 + */ + float fatFactor = 1f;//肥胖因子 + RectD _constrainViewPort; + + int maxScaleX = 5;//最大放大倍数 + + public MappingManager(RectF rectMain) { + _contentRect = rectMain; + _maxViewPort = new RectD(); + _currentViewPort = new RectD(); + _constrainViewPort = new RectD(); + } + + public void prepareRelation(double xMin, double xMax, double yMin, double yMax) { + + _maxViewPort.left = xMin; + _maxViewPort.right = xMax; + _maxViewPort.bottom = yMin; + _maxViewPort.top = yMax; + + _currentViewPort.setRectD(_maxViewPort); + + setFatFactor(fatFactor); + } + + /** + * 根据像素位置变换成数值 + * + * @param x + * @param y + * @return + */ + public SingleD_XY getValueByPx(float x, float y) { + SingleD_XY value = SingleD_XY.getInstance(); + value.setX(p2v_x(x)).setY(p2v_y(y)); + return value; + } + + public SingleF_XY getPxByEntry(Entry entry) { + return getPxByValue(entry.getX(), entry.getY()); + } + + /** + * 根据数值变换成像素 + * + * @param x + * @param y + * @return + */ + public SingleF_XY getPxByValue(double x, double y) { + + SingleF_XY value = SingleF_XY.getInstance(); + value.setX(v2p_x(x)).setY(v2p_y(y)); + return value; + } + + /** + * x方向 + * --------------- + * 数值转换成像素 + * + * @param xValue + * @return + */ + public float v2p_x(double xValue) { + double px = _contentRect.left + _contentRect.width() * (xValue - _currentViewPort.left) / _currentViewPort.width(); + return (float) px; + } + + /** + * y方向 + * ---------------- + * 数值转换成像素 + * + * @param yValue + * @return + */ + public float v2p_y(double yValue) { + double py = _contentRect.top + _contentRect.height() - _contentRect.height() * (yValue - _currentViewPort.bottom) / _currentViewPort.height(); + return (float) py; + } + + /** + * x方向 + * --------------- + * 像素转换成数值 + * + * @param xPix + * @return + */ + public double p2v_x(float xPix) { + double value = xPix - _contentRect.left; + value = value / _contentRect.width() * _currentViewPort.width(); + value = value + _currentViewPort.left; + return value; + } + + /** + * y方向 + * -------------- + * 像素转换成数值 + * + * @param yPix + * @return + */ + public double p2v_y(float yPix) { + double value = yPix - (_contentRect.top + _contentRect.height()); + value = value / -_contentRect.height() * _currentViewPort.height(); + value = value + _currentViewPort.bottom; + return value; + } + + + public void zoom(float scaleX, float scaleY, float cx, float cy) { + + double newWidth = scaleX * _currentViewPort.width(); + double newHeight = scaleY * _currentViewPort.height(); + + double hitValueX = p2v_x(cx); + double left = hitValueX - newWidth * (cx - _contentRect.left) / _contentRect.width(); + + double hitValueY = p2v_y(cy); + double bottom = hitValueY - newHeight * (_contentRect.bottom - cy) / _contentRect.height(); + + if ((_maxViewPort.right - _maxViewPort.left) / newWidth> maxScaleX){ + //超过最大放大倍数 + return; + } + + _currentViewPort.left = left; + _currentViewPort.bottom = bottom; + _currentViewPort.right = _currentViewPort.left + newWidth; + _currentViewPort.top = _currentViewPort.bottom + newHeight; + + constrainViewPort(_currentViewPort); + } + + public void zoom(float level, double oldStartW, double oldStartH, float cx, float cy, boolean canX, boolean canY) { + + double newWidth = canX ? oldStartW * level : oldStartW; + double newHeight = canY ? oldStartH * level : oldStartH; + + double hitValueX = p2v_x(cx); + double left = hitValueX - newWidth * (cx - _contentRect.left) / _contentRect.width(); + + double hitValueY = p2v_y(cy); + double bottom = hitValueY - newHeight * (_contentRect.bottom - cy) / _contentRect.height(); + + if ((_maxViewPort.right - _maxViewPort.left) / newWidth> maxScaleX){ + //超过最大放大倍数 + return; + } + + _currentViewPort.left = left; + _currentViewPort.bottom = bottom; + _currentViewPort.right = _currentViewPort.left + newWidth; + _currentViewPort.top = _currentViewPort.bottom + newHeight; + + constrainViewPort(_currentViewPort); + } + + /** + * 根据移动的像素偏离---》计算出数据视图的偏离 + * + * @param dx + * @param dy + */ + public void translate(float dx, float dy) { + + double w = _currentViewPort.width(); + double h = _currentViewPort.height(); + + double ddx = w * dx / _contentRect.width(); + double ddy = h * dy / _contentRect.height(); + + _currentViewPort.left += -ddx; + _currentViewPort.bottom += ddy; + + // 约束 currentViewPort 的位置 + constrainViewPort(_currentViewPort, w, h); + + _currentViewPort.right = _currentViewPort.left + w; + _currentViewPort.top = _currentViewPort.bottom + h; + } + + /** + * 约束当前的viewport + * --------------------- + * 针对平移的方式 + */ + private void constrainViewPort(RectD currentViewPort, double currentWidth, double currentHeight) { + + currentViewPort.left = Math.max(_constrainViewPort.left, Math.min(_constrainViewPort.right - currentWidth, currentViewPort.left)); + currentViewPort.bottom = Math.max(_constrainViewPort.bottom, Math.min(_constrainViewPort.top - currentHeight, currentViewPort.bottom)); + } + + /** + * 约束当前的viewport + * --------------------- + * 针对缩放的方式 + * + * @param currentViewPort + */ + private void constrainViewPort(RectD currentViewPort) { + + currentViewPort.left = Math.max(_constrainViewPort.left, currentViewPort.left); + currentViewPort.right = Math.min(_constrainViewPort.right, currentViewPort.right); + + currentViewPort.bottom = Math.max(_constrainViewPort.bottom, currentViewPort.bottom); + currentViewPort.top = Math.min(_constrainViewPort.top, currentViewPort.top); + } + + public RectD get_constrainViewPort() { + return _constrainViewPort; + } + + public void set_constrainViewPort(RectD _constrainViewPort) { + this._constrainViewPort = _constrainViewPort; + } + + public RectD get_maxViewPort() { + return _maxViewPort; + } + + public void set_maxViewPort(RectD _maxViewPort) { + this._maxViewPort = _maxViewPort; + } + + public RectD get_currentViewPort() { + return _currentViewPort; + } + + public void set_currentViewPort(RectD _currentViewPort) { + this._currentViewPort = _currentViewPort; + } + + public float getFatFactor() { + return fatFactor; + } + + /** + * 设置约束视图的肥胖因子 + * ------------------- + * 和最大的数据视图做比较: + * 1. 约束视图 是 最大视图的 1.1 倍,那么这个肥胖因子就是 1.1 + * + * @param fatFactor + */ + public void setFatFactor(float fatFactor) { + + if (fatFactor < 1) { + throw new RuntimeException("肥胖因子必须大于1!"); + } + + this.fatFactor = fatFactor; + + double w = _maxViewPort.width(); + double h = _maxViewPort.height(); + + fatFactor = fatFactor - 1; + + _constrainViewPort.left = _maxViewPort.left - w * fatFactor; + _constrainViewPort.right = _maxViewPort.right + w * fatFactor; + _constrainViewPort.top = _maxViewPort.top + h * fatFactor; + _constrainViewPort.bottom = _maxViewPort.bottom - h * fatFactor; + } + + public void setMaxScaleX(int maxScaleX) { + this.maxScaleX = maxScaleX; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/Axis.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/Axis.java new file mode 100644 index 0000000..eac33b4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/Axis.java @@ -0,0 +1,399 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model; + +import android.graphics.Color; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.DefaultValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.IValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.List; + +/** + * 轴线相关 + * ----------------------- + * 区域事先约定,优于计算! + *

    + */ + +public abstract class Axis { + + public static final float D_AXIS_WIDTH = 2;// d 代表default +// public static final float D_LEG_WIDTH = 5; + public static final float D_LEG_WIDTH = 0; + public static final float D_LABEL_TXT = 7; + public static final float D_UNIT_TXT = 12; + + public static final int D_LABEL_COUNT = 0;// 建议label的数量,决定从外部传 + + + ////////////////////////// label 相关 ///////////////////////// + double[] labelValues = new double[]{}; + int labelCount = 6; + int _labelCountAdvice = D_LABEL_COUNT; + float labelDimen; + int labelColor = Color.BLACK; + float labelTextSize; + + + + String duration; + CalWay calWay = CalWay.perfect; + + /////////////////////////////// unit 相关 //////////////////////////// + boolean _enableUnit = true; + String _unit = ""; + float unitDimen; + float unitTxtSize; + int unitColor = Color.RED; + + ///////////////////////////////// 轴线相关 ////////////////////////////////// + int axisColor = Color.BLACK; + float axisWidth; + float leg;// 轴线上的小腿(多出来的小不点:叫他小腿吧) + + ///////////////////////////////// 预警线相关 //////////////////////////////// + List listWarnLins; + + + boolean enable = true;// axis is enable? + IValueAdapter _ValueAdapter; + + public Axis() { + + axisWidth = Utils.dp2px(D_AXIS_WIDTH); + labelTextSize = Utils.dp2px(D_LABEL_TXT); + leg = Utils.dp2px(D_LEG_WIDTH); + unitTxtSize = Utils.dp2px(D_UNIT_TXT); + + // value adapter + _ValueAdapter = new DefaultValueAdapter(2); + } + + /** + * 计算与存储:可见区域内的每一步的数值 + * ----------------------------- + * 注意:可见区域! + */ + public void calValues(double min, double max, Line line) { + + double range; + range = max - min; + + if (Math.abs(max - min) == 0) { + return; + } + + if (calWay == CalWay.perfect) { + // 漂亮:展现的更合理 + + double rawInterval = range / (_labelCountAdvice - 1); + // 1.以最大数值为量程 + double interval = Utils.roundNumber2One(rawInterval);//314->300 + // 2. 量程>5,则以10为单位 + double intervalMagnitude = Math.pow(10, (int) Math.log10(interval));//100 + int intervalSigDigit = (int) (interval / intervalMagnitude); + if (intervalSigDigit > 5) { + interval = Math.floor(10 * intervalMagnitude);// 以10位单位 // + } + + double first = Math.floor(min / interval) * interval;//有几个interval + double last = Math.ceil(max / interval) * interval; + + double f; + int n = 0; + if (interval != 0.0) { + for (f = first; f <= last; f += interval) { + ++n; + } + } + labelCount = n; + + if (labelValues.length < labelCount) { + labelValues = new double[labelCount]; + } + + f = first; + for (int i = 0; i < n; f += interval, ++i) { + + if (f == 0.0) // Fix for negative zero case (Where value == -0.0, and 0.0 == -0.0) + f = 0.0; + + labelValues[i] = (float) f; + } + + + } else if (calWay == CalWay.justAvg) { + // 平均:达到共产主义 + labelCount = _labelCountAdvice; + + if (labelValues.length < labelCount) { + labelValues = new double[labelCount]; + } + + double v = min; + double interval = range / (labelCount - 1); + + labelValues[0] = min; + for (int i = 1; i < labelCount - 1; i++) { + v = v + interval; + labelValues[i] = v; + } + labelValues[labelCount - 1] = max; + } else if (calWay == CalWay.every) { + // 每个:将可视范围内,这条线上的每个数据在x轴上的label都绘制出来 + + if (line != null && line.getEntries().size() != 0) { + int minIndex = Line.getEntryIndex(line.getEntries(), min, Line.Rounding.DOWN); + int maxIndex = Line.getEntryIndex(line.getEntries(), max, Line.Rounding.UP); + + labelCount = (maxIndex - minIndex) + 1; + if (labelValues.length < labelCount) { + labelValues = new double[labelCount]; + } + + int count = 0; + for (int i = minIndex; i <= maxIndex; i++) { + if (this instanceof XAxis) { + labelValues[count++] = line.getEntries().get(i).getX(); + } else { + labelValues[count++] = line.getEntries().get(i).getY(); + } + } + } + + } else if (calWay == CalWay.lc_day) { + labelValues = new double[]{0, 4, 8,12,16,20,24}; + duration = "DAY"; + }else if (calWay == CalWay.lc_week) { + labelValues = new double[]{0, 3, 6}; + duration = "WEEK"; + }else if (calWay == CalWay.lc_month) { + labelValues = new double[]{0, 5, 10, 15, 20, 25, 30}; + duration = "MONTH"; + } else if (calWay == CalWay.lc_year) { + labelValues = new double[]{0, 1, 5, 9}; + duration = "YEAR"; + } + } + + /** + * 轴线左边 label和indicator的距离 + * + * @return + */ + public float offsetLeft(float labelWidth, float unitHeight) { + labelDimen = labelWidth; + unitDimen = unitHeight; + + float sum = labelDimen; + if (_enableUnit) { + sum += unitDimen; + } + sum += leg; + return sum; + } + + /** + * 轴线底部 label和indicator的距离 + * + * @return + */ + public float offsetBottom(float labelHeight, float unitHeight) { + labelDimen = labelHeight; + unitDimen = unitHeight; + + float sum; + sum = labelDimen; + if (_enableUnit) { + sum += unitDimen; + } + sum += leg; + return sum; + } + + + public float getLabelDimen() { + return labelDimen; + } + + public void setLabelDimen(float labelDimen) { + this.labelDimen = labelDimen; + } + + public float getUnitDimen() { + return unitDimen; + } + + public void setUnitDimen(float unitDimen) { + this.unitDimen = unitDimen; + } + + + /////////////////////////////// get set ////////////////////////////////////// + + + public IValueAdapter get_ValueAdapter() { + return _ValueAdapter; + } + + public void set_ValueAdapter(IValueAdapter _ValueAdapter) { + this._ValueAdapter = _ValueAdapter; + } + + public boolean is_enableUnit() { + return _enableUnit; + } + + public void set_enableUnit(boolean _enableUnit) { + this._enableUnit = _enableUnit; + } + + public int get_labelCountAdvice() { + return _labelCountAdvice; + } + + public void set_labelCountAdvice(int _labelCountAdvice) { + this._labelCountAdvice = _labelCountAdvice; + } + + public String get_unit() { + return _unit; + } + + public void set_unit(String _unit) { + this._unit = _unit; + } + + public float getUnitTxtSize() { + return unitTxtSize; + } + + public void setUnitTxtSize(float unitTxtSize) { + this.unitTxtSize = unitTxtSize; + } + + public int getUnitColor() { + return unitColor; + } + + public void setUnitColor(int unitColor) { + this.unitColor = unitColor; + } + + public int getAxisColor() { + return axisColor; + } + + public void setAxisColor(int axisColor) { + this.axisColor = axisColor; + } + + public float getAxisWidth() { + return axisWidth; + } + + public void setAxisWidth(float axisWidth) { + this.axisWidth = axisWidth; + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public float getLeg() { + return leg; + } + + public void setLeg(float leg) { + this.leg = leg; + } + + public float getLabelTextSize() { + return labelTextSize; + } + + public void setLabelTextSize(float labelTextSize) { + this.labelTextSize = labelTextSize; + } + + public int getLabelColor() { + return labelColor; + } + + public void setLabelColor(int labelColor) { + this.labelColor = labelColor; + } + + public int getLabelCount() { + return labelCount; + } + + public void setLabelCount(int labelCount) { + this.labelCount = labelCount; + } + + public double[] getLabelValues() { + return labelValues; + } + + public void setLabelValues(double[] labelValues) { + this.labelValues = labelValues; + } + + public List getListWarnLins() { + return listWarnLins; + } + + public void setListWarnLins(List listWarnLins) { + this.listWarnLins = listWarnLins; + } + + public CalWay getCalWay() { + return calWay; + } + + public String getDuration() { + return duration; + } + + public void setDuration(String duration) { + this.duration = duration; + } + /** + * 轴线上一堆label的计算方式 + * + * @param calWay + */ + public void setCalWay(CalWay calWay) { + this.calWay = calWay; + } + + /** + * 轴线上的一堆数据的计算方式 + */ + public enum CalWay { + /** + * 漂亮:展现的更合理 + */ + perfect, + /** + * 平均: + */ + justAvg, + /** + * 每个:将可视范围内,这条线上的每个数据在x轴上的label都绘制出来 + */ + every, + + lc_day, + lc_week, + lc_month, + lc_year, + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/HighLight.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/HighLight.java new file mode 100644 index 0000000..5ab9e49 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/HighLight.java @@ -0,0 +1,117 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model; + +import android.graphics.Color; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.DefaultHighLightValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.IValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class HighLight { + + public static final float D_HIGHLIGHT_WIDTH = 1; //dp + public static final float D_HINT_TEXT_SIZE = 15; + + //////////////////////// high light //////////////////////// + int highLightColor ; + float highLightWidth; + + //////////////////////// hint //////////////////////// + int hintColor = Color.BLACK; + float hintTextSize; + + boolean enable = false; + boolean isDrawHighLine = true; + boolean isDrawHint = true; + + protected IValueAdapter xValueAdapter;// 高亮时,x应该如何显示? + protected IValueAdapter yValueAdapter;// 高亮时,y应该如何显示? + + + public HighLight() { + + highLightWidth = Utils.dp2px(D_HIGHLIGHT_WIDTH); + hintTextSize = Utils.dp2px(D_HINT_TEXT_SIZE); + + xValueAdapter = new DefaultHighLightValueAdapter(); + yValueAdapter = new DefaultHighLightValueAdapter(); + } + + public HighLight(IValueAdapter xValueAdapter, IValueAdapter yValueAdapter) { + this.xValueAdapter = xValueAdapter; + this.yValueAdapter = yValueAdapter; + } + + public int getHighLightColor() { + return highLightColor; + } + + public void setHighLightColor(int highLightColor) { + this.highLightColor = highLightColor; + } + + public float getHighLightWidth() { + return highLightWidth; + } + + public void setHighLightWidth(float highLightWidth) { + this.highLightWidth = highLightWidth; + } + + public int getHintColor() { + return hintColor; + } + + public void setHintColor(int hintColor) { + this.hintColor = hintColor; + } + + public float getHintTextSize() { + return hintTextSize; + } + + public void setHintTextSize(float hintTextSize) { + this.hintTextSize = hintTextSize; + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public boolean isDrawHighLine() { + return isDrawHighLine; + } + + public void setDrawHighLine(boolean drawHighLine) { + isDrawHighLine = drawHighLine; + } + + public boolean isDrawHint() { + return isDrawHint; + } + + public void setDrawHint(boolean drawHint) { + isDrawHint = drawHint; + } + + public IValueAdapter getxValueAdapter() { + return xValueAdapter; + } + + public HighLight setxValueAdapter(IValueAdapter xValueAdapter) { + this.xValueAdapter = xValueAdapter; + return this; + } + + public IValueAdapter getyValueAdapter() { + return yValueAdapter; + } + + public HighLight setyValueAdapter(IValueAdapter yValueAdapter) { + this.yValueAdapter = yValueAdapter; + return this; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/WarnLine.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/WarnLine.java new file mode 100644 index 0000000..edca13b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/WarnLine.java @@ -0,0 +1,74 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model; + +import android.graphics.Color; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class WarnLine { + + public static final float D_WARN_WIDTH = 2; + public static final float D_WARN_TXT_SIZE = 15; + + int warnColor = Color.RED; + float warnLineWidth; + float txtSize ; + + boolean enable = true; + double value;//预警数值 + + + public WarnLine(double value) { + this.value = value; + + warnLineWidth = Utils.dp2px(D_WARN_WIDTH); + txtSize = Utils.dp2px(D_WARN_TXT_SIZE); + } + + public WarnLine(double value, int warnColor) { + this.value = value; + this.warnColor = warnColor; + + warnLineWidth = Utils.dp2px(D_WARN_WIDTH); + txtSize = Utils.dp2px(D_WARN_TXT_SIZE); + } + + public int getWarnColor() { + return warnColor; + } + + public void setWarnColor(int warnColor) { + this.warnColor = warnColor; + } + + public float getWarnLineWidth() { + return warnLineWidth; + } + + public void setWarnLineWidth(float warnLineWidth) { + this.warnLineWidth = warnLineWidth; + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } + + public float getTxtSize() { + return txtSize; + } + + public void setTxtSize(float txtSize) { + this.txtSize = txtSize; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/XAxis.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/XAxis.java new file mode 100644 index 0000000..866484e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/XAxis.java @@ -0,0 +1,17 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class XAxis extends Axis { + + public static final float AREA_UNIT = 14;// unit 区域的高 + public static final float AREA_LABEL = 14;// label 区域的高 + + + public XAxis() { + super(); + + labelDimen = Utils.dp2px(AREA_LABEL); + unitDimen = Utils.dp2px(AREA_UNIT); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/YAxis.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/YAxis.java new file mode 100644 index 0000000..3f69c36 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/model/YAxis.java @@ -0,0 +1,18 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class YAxis extends Axis { + + public static final float AREA_UNIT = 14;// unit 区域的高 + public static final float AREA_LABEL = 14;// label 区域的高 + + + public YAxis() { + super(); + + labelDimen = Utils.dp2px(AREA_LABEL); + unitDimen = Utils.dp2px(AREA_UNIT); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/AxisRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/AxisRender.java new file mode 100644 index 0000000..82a1b19 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/AxisRender.java @@ -0,0 +1,174 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.Axis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public abstract class AxisRender extends BaseRender { + + Axis _Axis; + + Paint _PaintAxis; + Paint _PaintGridline; + Paint _PaintLittle; + Paint _PaintLabel; + Paint _PaintUnit; + Paint _PaintWarnText; + Paint _PaintWarnPath; + + Path _PathGrid; + Path _PathWarn; + + public AxisRender(RectF rectMain, MappingManager _MappingManager, Axis axis) { + super(rectMain, _MappingManager); + + this._Axis = axis; + + _PaintAxis = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintLabel = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintLittle = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintGridline = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintUnit = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintWarnText = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintWarnPath = new Paint(Paint.ANTI_ALIAS_FLAG); + + // 虚线效果 + _PaintGridline.setStyle(Paint.Style.STROKE); +// _PaintGridline.setPathEffect(new DashPathEffect(new float[]{3, 2}, 0)); + + _PaintWarnPath.setStyle(Paint.Style.STROKE); + _PaintWarnPath.setPathEffect(new DashPathEffect(new float[]{3, 2}, 0)); + + _PathGrid = new Path(); + _PathWarn = new Path(); + } + + public void renderAxisLine(Canvas canvas) { + _PaintAxis.setColor(_Axis.getAxisColor()); + _PaintAxis.setStrokeWidth(_Axis.getAxisWidth()); + } + + public void renderGridline(Canvas canvas) { + _PaintGridline.setColor(Color.parseColor("#eeeeee")); + _PaintGridline.setStrokeWidth(Utils.dp2px(0.5f)); + } + + public void renderLabels(Canvas canvas) { + // label + paint_label(); + // little + paint_little(); + } + + public void renderUnit(Canvas canvas) { + paint_unit(); + } + + public void renderWarnLine(Canvas canvas) { + + + } + + + private void i1_______________________________________________() { + + } + + public void paint_label() { + _PaintLabel.setColor(_Axis.getLabelColor()); + _PaintLabel.setTextSize(_Axis.getLabelTextSize()); + } + + public void paint_little() { + _PaintLittle.setColor(_Axis.getAxisColor()); + _PaintLittle.setStrokeWidth(_Axis.getAxisWidth()); + } + + public void paint_unit() { + _PaintUnit.setColor(_Axis.getUnitColor()); + _PaintUnit.setTextSize(_Axis.getUnitTxtSize()); + } + + private void i2_______________________________________________() { + + } + + public Paint get_PaintAxis() { + return _PaintAxis; + } + + public void set_PaintAxis(Paint _PaintAxis) { + this._PaintAxis = _PaintAxis; + } + + public Paint get_PaintGridline() { + return _PaintGridline; + } + + public void set_PaintGridline(Paint _PaintGridline) { + this._PaintGridline = _PaintGridline; + } + + public Paint get_PaintLittle() { + return _PaintLittle; + } + + public void set_PaintLittle(Paint _PaintLittle) { + this._PaintLittle = _PaintLittle; + } + + public Paint get_PaintLabel() { + return _PaintLabel; + } + + public void set_PaintLabel(Paint _PaintLabel) { + this._PaintLabel = _PaintLabel; + } + + public Paint get_PaintUnit() { + return _PaintUnit; + } + + public void set_PaintUnit(Paint _PaintUnit) { + this._PaintUnit = _PaintUnit; + } + + public Paint get_PaintWarnText() { + return _PaintWarnText; + } + + public void set_PaintWarnText(Paint _PaintWarnText) { + this._PaintWarnText = _PaintWarnText; + } + + public Paint get_PaintWarnPath() { + return _PaintWarnPath; + } + + public void set_PaintWarnPath(Paint _PaintWarnPath) { + this._PaintWarnPath = _PaintWarnPath; + } + + public Path get_PathGrid() { + return _PathGrid; + } + + public void set_PathGrid(Path _PathGrid) { + this._PathGrid = _PathGrid; + } + + public Path get_PathWarn() { + return _PathWarn; + } + + public void set_PathWarn(Path _PathWarn) { + this._PathWarn = _PathWarn; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/BaseRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/BaseRender.java new file mode 100644 index 0000000..b33bacb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/BaseRender.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; + + +public abstract class BaseRender { + RectF _rectMain; + MappingManager _MappingManager; + + public BaseRender(RectF _rectMain, MappingManager _MappingManager) { + this._rectMain = _rectMain; + this._MappingManager = _MappingManager; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/GodRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/GodRender.java new file mode 100644 index 0000000..f149174 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/GodRender.java @@ -0,0 +1,34 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + + +public class GodRender extends BaseRender { + + Paint _PaintRect; + RectF _GodRect = new RectF(_rectMain); + + public GodRender(RectF _rectMain, MappingManager _MappingManager, RectF godRect) { + super(_rectMain, _MappingManager); + + this._GodRect = godRect; + + _PaintRect = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintRect.setColor(Color.RED); + _PaintRect.setStrokeWidth(Utils.dp2px(5)); + _PaintRect.setStyle(Paint.Style.STROKE); + } + + + public void render(Canvas canvas) { + canvas.drawRect(_GodRect, _PaintRect); + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/HighLightRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/HighLightRender.java new file mode 100644 index 0000000..7bf35fa --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/HighLightRender.java @@ -0,0 +1,417 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Lines; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.HighLight; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class HighLightRender extends BaseRender { + + private final static double UN_CHOOSE = Double.MIN_VALUE; + + Lines _lines; + HighLight _highLight; + + Paint paintHighLight; + Paint paintCircle; + Paint paintHint; + Context context; + + private enum DIRECTION{TOP, LEFT, BOTTOM, RIGHT} + + boolean TAG = false; + public HighLightRender(Context context, RectF rectMain, MappingManager _MappingManager, Lines lines, HighLight highLight) { + super(rectMain, _MappingManager); + + this._lines = lines; + this._highLight = highLight; + this.context = context; + + paintHighLight = new Paint(Paint.ANTI_ALIAS_FLAG); + paintHint = new Paint(Paint.ANTI_ALIAS_FLAG); + paintCircle = new Paint(Paint.ANTI_ALIAS_FLAG); + } + + + double highValueX = UN_CHOOSE; + double hightValueY = UN_CHOOSE; + + int record_LineIndex = -1;// 记录哪条线 + int record_EntryIndex = -1;// 记录哪条entry + boolean isClick = false; + + public void highLight_ValueXY(double x, double y) { + highValueX = x; + hightValueY = y; + isClick = true; + } + + public void highLightLeft() { + record_EntryIndex--; + } + + public void highLightRight() { + record_EntryIndex++; + } + + + public void render(Canvas canvas) { + + if (!_highLight.isEnable()) { + return; + } + + if (_lines == null) { + return; + } + + if (_lines.getLines().size() == 0) { + return; + } + + if (highValueX == UN_CHOOSE || hightValueY == UN_CHOOSE) { + return; + } + +// if (TAG) { +// canvas.save(); +// canvas.drawText("", 0, 0, new Paint()); +// canvas.restore(); +// TAG = false; +// } else { + canvas.save(); +// canvas.clipRect(_rectMain); // 限制绘制区域 + + RectF rectF = new RectF(_rectMain); + rectF.top = _rectMain.top - 100; + rectF.bottom = _rectMain.bottom + 100; + canvas.clipRect(rectF); // 限制绘制区域 + + drawHighLight_Hint(canvas); + + canvas.restore(); + +// } + + } + + + private void drawHighLight_Hint(Canvas canvas) { + + double closeX = Double.MAX_VALUE; + double closeY = Double.MAX_VALUE; + Entry hitEntry = null; + + + if (isClick) { + // 点击光标进来的 + int tempIndexEntry = -1; + int tempLineIndex = -1; + + for (int i = 0; i < _lines.getLines().size(); i++) { + Line line = _lines.getLines().get(i); + + if (!line.isEnable()) { + continue; + } + int indexEntry = Line.getEntryIndex(line.getEntries(), highValueX, Line.Rounding.CLOSEST); + + if (indexEntry < 0 || indexEntry >= line.getEntries().size()) { + continue; + } + + Entry entry = line.getEntries().get(indexEntry); + + // 到点击的距离 + double dx = Math.abs(entry.getX() - highValueX); + double dy = Math.abs(entry.getY() - hightValueY); + + // 先考虑 x + if (dx <= closeX) { + closeX = dx; + // 再考虑 y + if (dy <= closeY) { + closeY = dy; + hitEntry = entry; + tempIndexEntry = indexEntry; + tempLineIndex = i; + } + } + } + + if (record_EntryIndex == tempIndexEntry && record_LineIndex == tempLineIndex){ + //点击的是同一个点,重置掉 + record_LineIndex = -1; + record_EntryIndex = -1; + isClick = false; + return; + }else { + record_EntryIndex = tempIndexEntry; + record_LineIndex = tempLineIndex; + } + + } else { + // 左右移动进来的 + try { + Line line = _lines.getLines().get(record_LineIndex); + if (line.isEnable()) { + hitEntry = line.getEntries().get(record_EntryIndex); + } + } catch (Exception e) { + hitEntry = null; + } + } + + + if (hitEntry == null) { + return; + } + + // 考虑断掉的点 + if (hitEntry.isNull_Y()) { + return; + } + + highValueX = hitEntry.getX();// real indexX + + SingleF_XY xy = _MappingManager.getPxByEntry(hitEntry); + + + // draw high line + if (_highLight.isDrawHighLine()) { + //获取当前line的颜色,作为highLine的颜色 + int lineSize = _lines.getLines().size(); + Line line = lineSize > 0 && record_LineIndex < lineSize ? _lines.getLines().get(record_LineIndex) : null; + + int highLineColor = _highLight.getHighLightColor(); + if (highLineColor == 0 && line != null) + { + highLineColor = line.getLineColor(); + } + + //DRAW ROUND RING PIC + //mid white ring + float hightLightwidth = _highLight.getHighLightWidth(); + paintCircle.setStrokeWidth( (int) Utils.dp2px(0.8f) ); //the radius of inner ball is 3dp. white ring width is 2dp + paintCircle.setColor(Color.WHITE); + paintCircle.setStyle(Paint.Style.STROKE); + canvas.drawCircle(xy.getX(), xy.getY(), (int)Utils.dp2px(2+0.8f), paintCircle); + + //outside color ring + paintCircle.setStrokeWidth((int)Utils.dp2px(1)); //color ring width is 2dp + paintCircle.setColor(highLineColor); + paintCircle.setStyle(Paint.Style.STROKE); + canvas.drawCircle(xy.getX(), xy.getY(), (int)Utils.dp2px(2+0.8f+1), paintCircle); + + + //DRAW HIGH VERTICAL LINE + paintHighLight.setStrokeWidth(_highLight.getHighLightWidth()); + + //气泡颜色暂时默认都设置成灰色,隐藏横竖定位线 +// paintHighLight.setColor(highLineColor); + +// canvas.drawLine(_rectMain.left, xy.getY(), _rectMain.right, xy.getY(), paintHighLight); //绘制highLight横线 +// canvas.drawLine(xy.getX(), _rectMain.top, xy.getX(), _rectMain.bottom, paintHighLight); + + + //DRAW LC HINT + + + //绘制气泡 + + Paint paint = new Paint(); + paint.setColor(Color.WHITE); + paint.setTextSize(Utils.sp2px(14)); + paint.setAntiAlias(true); + String xStr = _highLight.getxValueAdapter().value2String(hitEntry.getX()+1); //文字内容 + String yStr = _highLight.getyValueAdapter().value2String(hitEntry.getY()) + "人"; + + //文字长度 + float textLen = Math.max(paint.measureText(xStr), paint.measureText(yStr)); + Paint.FontMetrics fm = paint.getFontMetrics(); + float textHeight1 = Utils.textHeight(paint); + paint.setTextSize(Utils.sp2px(12)); + float textHeight2 = Utils.textHeight(paint); + + float triangleWidth = Utils.dp2px(8); //三角宽高 + float trianglePadding = 0; //三角距离数据原点的间距 + float rectWidth = Math.min(Utils.dp2px(100), textLen + Utils.dp2px(5)*2); //矩形宽度 + float rectHeight = Utils.dp2px(4) * 3 + textHeight1 + textHeight2; //矩形高度 + + + //判断气泡画在哪个方向,必须先判断Y轴方向 + DIRECTION direction = DIRECTION.LEFT; + if (xy.getY() - rectHeight/2 < 0){ + direction = DIRECTION.BOTTOM; + }else if (xy.getY() + rectHeight/2 > _rectMain.bottom){ + direction = DIRECTION.TOP; + }else if (xy.getX() - triangleWidth - trianglePadding - rectWidth > _rectMain.left){ + direction = DIRECTION.LEFT; + }else { + direction = DIRECTION.RIGHT; + } + + //画三角 + Path path = new Path(); + float triangleX; //三角指向圆圈的角的X + float triangleY; //三角指向圆圈的角的Y + float rectRight = 0; //矩形右边 + float rectLeft = 0; //矩形左边 + float rectTop = 0; //矩形上边 + float rectBottom = 0; //矩形下边 + float text1X = 0; + float text1Y = 0; + float text2X = 0; + float text2Y = 0; + + switch(direction){ + case TOP : + //三角 + triangleX = xy.getX(); + triangleY = xy.getY() - triangleWidth - trianglePadding; + path.moveTo(triangleX, triangleY); + path.lineTo(triangleX - triangleWidth/2, triangleY - triangleWidth); + path.lineTo(triangleX + triangleWidth/2, triangleY - triangleWidth); + path.close(); + + //矩形 + rectLeft = triangleX - rectWidth/2; + rectRight = triangleX + rectWidth/2; + rectTop = triangleY - triangleWidth - rectHeight; + rectBottom = triangleY - triangleWidth; + + //文字 + text1X = rectLeft + Utils.dp2px(5); + text1Y = rectTop + rectHeight/2 - 14; + text2X = rectLeft + Utils.dp2px(5); + text2Y = rectTop + rectHeight/2 - 6; + + break; + case BOTTOM : + triangleX = xy.getX(); + triangleY = xy.getY() + triangleWidth + trianglePadding; + path.moveTo(triangleX, triangleY); + path.lineTo(triangleX + triangleWidth/2, triangleY + triangleWidth); + path.lineTo(triangleX - triangleWidth/2, triangleY + triangleWidth); + path.close(); + + //矩形 + rectLeft = triangleX - rectWidth/2; + rectRight = triangleX + rectWidth/2; + rectTop = triangleY + triangleWidth; + rectBottom = triangleY + triangleWidth + rectHeight; + + //文字 + text1X = rectLeft + Utils.dp2px(5); + text1Y = rectTop + rectHeight/2 - 14; + text2X = rectLeft + Utils.dp2px(5); + text2Y = rectTop + rectHeight/2 - 6; + break; + case LEFT : + triangleX = xy.getX() - triangleWidth - trianglePadding; + triangleY = xy.getY(); + path.moveTo(triangleX, triangleY); + path.lineTo(triangleX - triangleWidth, triangleY + triangleWidth/2); + path.lineTo(triangleX - triangleWidth, triangleY - triangleWidth/2); + path.close(); + + //矩形 + rectLeft = triangleX - triangleWidth - rectWidth; + rectRight = triangleX - triangleWidth; + rectTop = triangleY - rectHeight/2; + rectBottom = triangleY + rectHeight/2; + + //文字 + text1X = rectLeft + Utils.dp2px(5); + text1Y = triangleY - 14; + text2X = rectLeft + Utils.dp2px(5); + text2Y = triangleY - 6; + break; + case RIGHT : + triangleX = xy.getX() + triangleWidth + trianglePadding; + triangleY = xy.getY(); + path.moveTo(triangleX, triangleY); + path.lineTo(triangleX + triangleWidth, triangleY + triangleWidth/2); + path.lineTo(triangleX + triangleWidth, triangleY - triangleWidth/2); + path.close(); + + //矩形 + rectLeft = triangleX + triangleWidth; + rectRight = triangleX + triangleWidth + rectWidth; + rectTop = triangleY - rectHeight/2; + rectBottom = triangleY + rectHeight/2; + + //文字 + text1X = rectLeft + Utils.dp2px(5); + text1Y = triangleY - 14; + text2X = rectLeft + Utils.dp2px(5); + text2Y = triangleY - 6; + break; + default: + break; + } + + + //气泡全部设置成灰色,外发光 + paintHighLight.setARGB(229,73,73,73); +// paintHighLight.setShadowLayer(20, 2, 2, Color.argb(229,98,98,98)); +// paintHighLight.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID)); + + canvas.drawRect(rectLeft, rectTop, rectRight, rectBottom, paintHighLight); + canvas.drawPath(path, paintHighLight); + + canvas.drawText(xStr, text1X, text1Y, paint); + canvas.drawText(yStr, text2X, text2Y + textHeight1, paint); +// paintHighLight.clearShadowLayer(); +// paintHighLight.setMaskFilter(null); + } + + + + + // draw hint + if (_highLight.isDrawHint()) { + paintHint.setColor(_highLight.getHintColor()); + paintHint.setTextSize(_highLight.getHintTextSize()); + + String xStr = _highLight.getxValueAdapter().value2String(hitEntry.getX()); + String yStr = _highLight.getyValueAdapter().value2String(hitEntry.getY()); + float txtHeight = Utils.textHeight(paintHint); + float txtWidth = Math.max(Utils.textWidth(paintHint, xStr), Utils.textWidth(paintHint, yStr)); + + float x = _rectMain.right - txtWidth - 10; + float y = _rectMain.top + Utils.dp2px(20); + + canvas.drawText(xStr, x, y, paintHint); + canvas.drawText(yStr, x, y + txtHeight, paintHint); + } + + // callback + if (isClick) { + isClick = false; + + Line line = _lines.getLines().get(record_LineIndex); + hitEntry = line.getEntries().get(record_EntryIndex); + + Line.CallBack_OnEntryClick cb = line.getOnEntryClick(); + if (cb != null) { + cb.onEntry(line, hitEntry); + } + } + + } + + public void onDataChanged(Lines lines) { + _lines = lines; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/LineRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/LineRender.java new file mode 100644 index 0000000..dfa357c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/LineRender.java @@ -0,0 +1,236 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.RectF; +import android.graphics.Shader; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.animate.LAnimator; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts.LineChart; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Lines; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; + +import java.util.List; + + +public class LineRender extends BaseRender { + + LineChart lineChart; + Lines _lines; + + Paint _PaintLine; + Paint _PaintCircle; + Paint _PaintLegend; + + Path _PathLine; + + LAnimator _LAnimator; + + Bitmap _drawBitmap; + Canvas softwareCanvas = new Canvas(); + + public LineRender(RectF rectMain, MappingManager _MappingManager, Lines _lines, LineChart lineChart) { + super(rectMain, _MappingManager); + this._lines = _lines; + this.lineChart = lineChart; + this._LAnimator = lineChart.get_LAnimator(); + + _PaintLine = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG); + _PaintLegend = new Paint(Paint.ANTI_ALIAS_FLAG); + + _PathLine = new Path(); + } + + + public void onChartSizeChanged(int w, int h) { + if (w > 0 && h > 0) { + _drawBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + softwareCanvas.setBitmap(_drawBitmap); + } + } + + + public void render(Canvas canvasSrc) { + + if (_lines == null) { + return; + } + + Canvas canvas = null; + + // layout editor 状态下 _drawBitmap 是没有的 + if (null != _drawBitmap) { + canvas = softwareCanvas; + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + } else { + canvas = canvasSrc; + } + + + canvas.save(); +// canvas.clipRect(_rectMain); // 限制绘制区域 + + RectF rectF = new RectF(_rectMain); + rectF.top = _rectMain.top - 20; + rectF.bottom = _rectMain.bottom + 20; + canvas.clipRect(rectF); // 限制绘制区域 + + // 绘制折线 和 折线上的圆点 + for (Line line : _lines.getLines()) { + if (!line.isEnable()) { + continue; + } + drawLine_Circle(canvas, line); + } + + canvas.restore(); + + // 绘制每条线的 legend +// for (int i = 0; i < _lines.getLines().size(); i++) { +// Line line = _lines.getLines().get(i); +// if (!line.isEnable()) { +// continue; +// } +// drawLegend(canvas, line, i); +// } + + if (_drawBitmap != null) { + canvasSrc.drawBitmap(_drawBitmap, 0, 0, null); + } + } + + private void drawLine_Circle(Canvas canvas, Line line) { + +// HighLight highLight = new HighLight(); +// highLight.setHighLightColor(line.getLineColor()); + + _PaintLine.setStrokeWidth(line.getLineWidth()); + _PaintLine.setColor(line.getLineColor()); + _PaintLine.setStyle(Paint.Style.STROKE); + + _PaintCircle.setStrokeWidth(line.getLineWidth()); + _PaintCircle.setColor(line.getLineColor()); + + List list = line.getEntries(); + + // check + if (list == null || list.size() == 0) { + return; + } + + // 考虑只有一个点的情况 + if (list.size() == 1) { + Entry hit = list.get(0); + SingleF_XY xy = _MappingManager.getPxByEntry(hit); + canvas.drawCircle(xy.getX(), xy.getY(), line.getCircleR(), _PaintCircle); + return; + } + + double xMin_Visiable = lineChart.getVisiableMinX(); + double xMax_Visiable = xMin_Visiable + (lineChart.getVisiableMaxX() - xMin_Visiable) * _LAnimator.get_hitValueX();// 考虑动画 + + int minIndex = Line.getEntryIndex(list, xMin_Visiable, Line.Rounding.DOWN); + int maxIndex = Line.getEntryIndex(list, xMax_Visiable, Line.Rounding.UP); + + if (Math.abs(maxIndex - minIndex) == 0) { + return; + } + + if ((maxIndex - minIndex) > 1500) { + _PaintLine.setAntiAlias(false);// 考虑性能 + } else { + _PaintLine.setAntiAlias(true); + } + + _PathLine.reset(); + + int breakI = -1; + + for (int i = minIndex; i <= maxIndex; i++) { + Entry entry = list.get(i); + + // 考虑这个点是否断掉 + if (entry.isNull_Y()) { + breakI = i; + continue; + } + + float sx = _MappingManager.v2p_x(entry.getX()); + float sy = getAnimateY(_MappingManager.v2p_y(entry.getY())); + + if (i == minIndex || i == breakI + 1) { + _PathLine.moveTo(sx, sy); + } else { + _PathLine.lineTo(sx, sy); + } + + if (line.isDrawCircle()) { + SingleF_XY xy = _MappingManager.getPxByEntry(entry); + canvas.drawCircle(xy.getX(), getAnimateY(xy.getY()), line.getCircleR(), _PaintCircle); + + // 把最后点一个绘制出来 + if (i == maxIndex - 1) { + Entry last = list.get(maxIndex); + xy = _MappingManager.getPxByEntry(last); + ///////////////////////////////////////////// 考虑动画效果 ////////////////////////////////////////// + canvas.drawCircle(xy.getX(), getAnimateY(xy.getY()), line.getCircleR(), _PaintCircle); + } + } + } + + canvas.drawPath(_PathLine, _PaintLine); + + // 有断掉的点,就不考虑填充了 + if (breakI != -1) { + return; + } + + // 考虑填充 + if (line.isFilled()) { + Entry start = list.get(minIndex); + Entry end = list.get(maxIndex); + float sx = _MappingManager.v2p_x(start.getX()); + float sy = getAnimateY(_MappingManager.v2p_y(start.getY())); + float ex = _MappingManager.v2p_x(end.getX()); + float ey = getAnimateY(_MappingManager.v2p_y(end.getY())); + + float maxY = Math.max(sy, ey); + + _PathLine.lineTo(ex, lineChart.get_MainPlotRect().bottom); + _PathLine.lineTo(sx, lineChart.get_MainPlotRect().bottom); + + _PathLine.close(); + + _PaintLine.setStyle(Paint.Style.FILL); + _PaintLine.setAlpha(50); + + Shader shader = new LinearGradient(0, maxY, 0, 0, line.getLineColor(), line.getLineColor() / 50, Shader.TileMode.CLAMP); + _PaintLine.setShader(shader); + + canvas.drawPath(_PathLine, _PaintLine); + _PaintLine.setStyle(Paint.Style.STROKE); + _PaintLine.setShader(null); + } + } + + + RectF _RectFBuffer = new RectF(); + + + public void onDataChanged(Lines lines) { + _lines = lines; + } + + private float getAnimateY(float src) { + return lineChart.get_MainPlotRect().bottom - (lineChart.get_MainPlotRect().bottom - src) * _LAnimator.get_hitValueY(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/NoDataRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/NoDataRender.java new file mode 100644 index 0000000..223fdc3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/NoDataRender.java @@ -0,0 +1,37 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +public class NoDataRender extends BaseRender { + + Paint _Paint; + String txt = "无数据"; + int txtColor = Color.RED; + int txtSize = 30; + + public NoDataRender(RectF _FrameManager, MappingManager _MappingManager) { + super(_FrameManager, _MappingManager); + + _Paint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + + public void render(Canvas canvas) { + + _Paint.setColor(txtColor); + _Paint.setTextSize(txtSize); + + float x = _rectMain.centerX(); + float y = _rectMain.centerY(); + + float halfW = Utils.textWidth(_Paint, txt) / 2f; + float halfH = Utils.textHeightAsc(_Paint) / 2f; + + canvas.drawText(txt, x - halfW, y + halfH, _Paint); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/XAxisRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/XAxisRender.java new file mode 100644 index 0000000..3ab1c49 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/XAxisRender.java @@ -0,0 +1,245 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.IValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.Axis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.WarnLine; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.List; + +public class XAxisRender extends AxisRender { + + public XAxisRender(RectF _FrameManager, MappingManager _MappingManager, Axis axis) { + super(_FrameManager, _MappingManager, axis); + } + + @Override + public void renderAxisLine(Canvas canvas) { + super.renderAxisLine(canvas); + + float startX = _rectMain.left; + float startY = _rectMain.bottom; + float stopX = _rectMain.right; + float stopY = _rectMain.bottom; + + canvas.drawLine(startX, startY, stopX, stopY, _PaintAxis); + } + + + @Override + public void renderGridline(Canvas canvas) { + super.renderGridline(canvas); + + canvas.save(); + canvas.clipRect(_rectMain);// 限制绘制区域 + + double[] values = _Axis.getLabelValues(); + int labelCount = _Axis.getLabelCount(); + float x = 0; + + float top = _rectMain.top; + float bottom = _rectMain.bottom; + + _PathGrid.reset(); + + for (int i = 0; i < labelCount; i++) { + if (values.length < (i + 1)) { + break; + } + + double value = values[i]; + + SingleF_XY xy = _MappingManager.getPxByValue(value, 0); + x = xy.getX(); + + _PathGrid.moveTo(x, bottom); + _PathGrid.lineTo(x, top); + } + + // grid line + canvas.drawPath(_PathGrid, _PaintGridline); + + canvas.restore(); + } + + @Override + public void renderLabels(Canvas canvas) { + super.renderLabels(canvas); + + String duration = _Axis.getDuration(); + double[] values = _Axis.getLabelValues(); + int labelCount = _Axis.getLabelCount(); + + IValueAdapter adapter = _Axis.get_ValueAdapter(); + float indicator = _Axis.getLeg(); + + float x = 0; + + float bottom = _rectMain.bottom; + + for (int i = 0; i < labelCount; i++) { + if (values.length < (i + 1)) { + break; + } + + double value = values[i]; + String label = ""; +// = adapter.value2String(value); + + if (duration .equals( "DAY")) { + if (value == 0) { + label = "01:00"; + } else if (value == 4) { + label = "05:00"; + } else if (value == 8) { + label = "09:00"; + } else if (value == 12) { + label = "13:00"; + } else if (value == 16) { + label = "17:00"; + } else if (value == 20) { + label = "21:00"; + } else if (value == 23) { + label = "24:00"; + } + else { + label = adapter.value2String(value); + } + + } else if (duration .equals( "WEEK")) { + if (value == 0) { + label = "周一"; + } else if (value == 3) { + label = "周四"; + } else if (value == 6) { + label = "周日"; + } else { + label = adapter.value2String(value); + } + + } else if (duration .equals( "MONTH")) { + if (value == 0) { + label = "01"; + } else if (value == 5) { + label = "06"; + } else if (value == 10) { + label = "11"; + }else if (value == 15) { + label = "16"; + }else if (value == 20) { + label = "21"; + }else if (value == 25) { + label = "26"; + }else if (value == 30) { + label = "31"; + } else { + label = adapter.value2String(value); + } + } else if (duration .equals( "YEAR")) { + if (value == 0) { + label = ""; + } else if(value == 1) { + label = "二月"; + } else if (value == 5) { + label = "六月"; + } else if (value == 9) { + label = "十月"; + } else { + label = adapter.value2String(value); + } + } + + + + + SingleF_XY xy = _MappingManager.getPxByValue(value, 0); + x = xy.getX(); + + // check + if (x < _rectMain.left || x > _rectMain.right) { + continue; + } + + if (label == null) { + continue; + } + + // indicator + canvas.drawLine(x, bottom, x, bottom + indicator, _PaintLittle); + + // label + float labelX = x - Utils.textWidth(_PaintLabel, label) / 2; + float labelY = bottom + _Axis.getLeg() + _Axis.getLabelDimen() + 5; + canvas.drawText(label, labelX, labelY, _PaintLabel); + } + } + + + @Override + public void renderUnit(Canvas canvas) { + super.renderUnit(canvas); + + String unit = _Axis.get_unit(); + Paint paintUnit = _PaintUnit; + + float bottom = _rectMain.bottom; + float labelX = _rectMain.centerX() - Utils.textWidth(paintUnit, unit) / 2; + float labelY = bottom + _Axis.getLeg() + _Axis.getLabelDimen() + _Axis.getUnitDimen(); + + canvas.drawText(unit, labelX, labelY, _PaintUnit); + } + + + @Override + public void renderWarnLine(Canvas canvas) { + super.renderWarnLine(canvas); + + List warnLines = _Axis.getListWarnLins(); + if (warnLines == null) { + return; + } + + canvas.save(); + canvas.clipRect(_rectMain); + + for (WarnLine warnLine : warnLines) { + if (warnLine.isEnable()) { + double value = warnLine.getValue(); + + SingleF_XY xy = _MappingManager.getPxByValue(value, 0); + float x = xy.getX(); + + if (x < _rectMain.left || x > _rectMain.right) { + continue; + } + + _PaintWarnText.setColor(warnLine.getWarnColor()); + _PaintWarnText.setStrokeWidth(warnLine.getWarnLineWidth()); + _PaintWarnText.setTextSize(warnLine.getTxtSize()); + + _PaintWarnPath.setColor(warnLine.getWarnColor()); + _PaintWarnPath.setStrokeWidth(warnLine.getWarnLineWidth()); + + _PathWarn.reset(); + _PathWarn.moveTo(x, _rectMain.bottom); + _PathWarn.lineTo(x, _rectMain.top); + + canvas.drawPath(_PathWarn, _PaintWarnPath); + + float txtHeight = Utils.textHeight(_PaintWarnText); + float txtWidth = Utils.textWidth(_PaintWarnText, "" + value); + + canvas.drawText(value + "", x - txtWidth * 1.5f, _rectMain.bottom - txtHeight * 1.5f, _PaintWarnText); + } + } + + canvas.restore(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/YAxisRender.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/YAxisRender.java new file mode 100644 index 0000000..2a7a70d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/render/YAxisRender.java @@ -0,0 +1,188 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; + +import android.graphics.Canvas; +import android.graphics.RectF; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.adapter.IValueAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.Axis; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.WarnLine; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; + +import java.util.List; + +public class YAxisRender extends AxisRender { + + + public YAxisRender(RectF _FrameManager, MappingManager _MappingManager, Axis axis) { + super(_FrameManager, _MappingManager, axis); + } + + @Override + public void renderAxisLine(Canvas canvas) { + super.renderAxisLine(canvas); + + float startX = _rectMain.left; + float startY = _rectMain.bottom; + float stopX = _rectMain.left; + float stopY = _rectMain.top; + + canvas.drawLine(startX, startY, stopX, stopY, _PaintAxis); + } + + @Override + public void renderGridline(Canvas canvas) { + super.renderGridline(canvas); + + canvas.save(); + canvas.clipRect(_rectMain);// 限制绘制区域 + + double[] values = _Axis.getLabelValues(); + int labelCount = _Axis.getLabelCount(); + + float y = 0; + + float left = _rectMain.left; + float right = _rectMain.right; + + _PathGrid.reset(); + + float pNumTxtWidthMax = 0f; + for (int i = 0; i < labelCount; i++) { + if (values.length < (i + 1)) { + break; + } + double value = values[i]; + + SingleF_XY xy = _MappingManager.getPxByValue(0, value); + y = xy.getY(); + + + //xzy + float pNumTxtWidthNow = Utils.textWidth(_PaintGridline, _Axis.get_ValueAdapter().value2String(value)); + if (pNumTxtWidthNow > pNumTxtWidthMax) { + pNumTxtWidthMax = pNumTxtWidthNow; + } +// _PathGrid.moveTo(left, y); + _PathGrid.moveTo(left + pNumTxtWidthMax*1.5f , y); //left = 124 + //xzy + + + _PathGrid.lineTo(right, y); + } + + // grid line + canvas.drawPath(_PathGrid, _PaintGridline); + + canvas.restore(); + } + + + @Override + public void renderLabels(Canvas canvas) { + super.renderLabels(canvas); + + IValueAdapter adapter = _Axis.get_ValueAdapter(); + + double[] values = _Axis.getLabelValues(); + int labelCount = _Axis.getLabelCount(); + float indicator = _Axis.getLeg(); + float y = 0; + + float left = _rectMain.left; + + int txtHeight = Utils.textHeightAsc(_PaintLabel); + + for (int i = 0; i < labelCount; i++) { + if (values.length < (i + 1)) { + break; + } + double value = values[i]; + String label = adapter.value2String(value); + + SingleF_XY xy = _MappingManager.getPxByValue(0, value); + y = xy.getY(); + + if (y < _rectMain.top || y > _rectMain.bottom) { + continue; + } + + if (label == null) { + continue; + } + + // indicator + canvas.drawLine(left, y, left - indicator, y, _PaintLittle); + + float labelX; + if (false){ + // label左对齐 + labelX = left - _Axis.getLabelDimen() - _Axis.getLeg() * 1.5f ; + }else { + //label右对齐 + labelX = left - _Axis.getLeg() * 1.5f - Utils.textWidth(_PaintLabel, label) ; + } + + float labelY = y + txtHeight / 2; + canvas.drawText(label, labelX, labelY, _PaintLabel); + } + + } + + @Override + public void renderUnit(Canvas canvas) { + super.renderUnit(canvas); + + float px = _Axis.getUnitDimen(); + float py = _rectMain.centerY() + _Axis.getUnitDimen() / 2; + canvas.save(); + canvas.rotate(-90, px, py); + canvas.drawText(_Axis.get_unit(), px, py, _PaintUnit); + canvas.restore(); + } + + @Override + public void renderWarnLine(Canvas canvas) { + super.renderWarnLine(canvas); + + List warnLines = _Axis.getListWarnLins(); + if (warnLines == null) { + return; + } + + canvas.save(); + canvas.clipRect(_rectMain); + + for (WarnLine warnLine : warnLines) { + if (warnLine.isEnable()) { + double value = warnLine.getValue(); + + SingleF_XY xy = _MappingManager.getPxByValue(0, value); + float y = xy.getY(); + + if (y < _rectMain.top || y > _rectMain.bottom) { + continue; + } + + _PaintWarnText.setColor(warnLine.getWarnColor()); + _PaintWarnText.setStrokeWidth(warnLine.getWarnLineWidth()); + _PaintWarnText.setTextSize(warnLine.getTxtSize()); + + _PaintWarnPath.setColor(warnLine.getWarnColor()); + _PaintWarnPath.setStrokeWidth(warnLine.getWarnLineWidth()); + + _PathWarn.reset(); + _PathWarn.moveTo(_rectMain.left, y); + _PathWarn.lineTo(_rectMain.right, y); + + canvas.drawPath(_PathWarn, _PaintWarnPath); + + float txtHeight = Utils.textHeight(_PaintWarnText); + canvas.drawText(value + "", _rectMain.left + 10, y - txtHeight, _PaintWarnText); + } + } + + canvas.restore(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/GodTouchListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/GodTouchListener.java new file mode 100644 index 0000000..4b75c18 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/GodTouchListener.java @@ -0,0 +1,199 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.touch; + +import android.graphics.RectF; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.view.ViewParent; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts.LineChart; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.RectD; + +public class GodTouchListener implements View.OnTouchListener { + + GestureDetector _GestureDetector; + ScaleGestureDetector _ScaleGestureDetector; + LineChart _LineChart; + + public GodTouchListener(LineChart lineChart) { + _LineChart = lineChart; + _GestureDetector = new GestureDetector(lineChart.getContext(), new GestureListener()); + _ScaleGestureDetector = new ScaleGestureDetector(lineChart.getContext(), new ScaleListener()); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + + ViewParent parent = v.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + + boolean hit = _GestureDetector.onTouchEvent(event); + hit |= _ScaleGestureDetector.onTouchEvent(event); + if (hit) { + _LineChart.invalidate(); + return true; + } + + return false; + } + + + class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + + float _lastSpanX, _lastSpanY; + + public ScaleListener() { + super(); + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + + float spanX = detector.getCurrentSpanX(); + float kx = spanX / _lastSpanX; + + float spanY = detector.getCurrentSpanY(); + float ky = spanY / _lastSpanY; + + RectF godRect = _LineChart.get_GodRect(); + RectF mainRect = _LineChart.get_MainPlotRect(); + + godRect.right = godRect.left + godRect.width() * kx; + godRect.bottom = godRect.top + godRect.height() * ky; + + constrainRect(godRect, mainRect); + + nofityViewPortChanged(godRect); + + _lastSpanX = spanX; + _lastSpanY = spanY; + + return true; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + + _lastSpanX = detector.getCurrentSpanX(); + _lastSpanY = detector.getCurrentSpanY(); + + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + super.onScaleEnd(detector); + } + } + + + RectD _rectD_ob = new RectD(); + + class GestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDoubleTap(MotionEvent e) { + return super.onDoubleTap(e); + } + + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + return super.onFling(e1, e2, velocityX, velocityY); + } + + @Override + public void onLongPress(MotionEvent e) { + super.onLongPress(e); + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + RectF godRect = _LineChart.get_GodRect(); + RectF mainRect = _LineChart.get_MainPlotRect(); + + + float w = godRect.width(); + float h = godRect.height(); + godRect.left += -distanceX; + godRect.right = godRect.left + w; + godRect.top += -distanceY; + godRect.bottom = godRect.top + h; + + constrainRect(godRect, mainRect); + + nofityViewPortChanged(godRect); + + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + return super.onSingleTapConfirmed(e); + } + } + + + private void nofityViewPortChanged(RectF godRect) { + + // 计算出godRect对应的viewport + MappingManager mappingManager = _LineChart.get_MappingManager(); + double left = mappingManager.p2v_x(godRect.left); + double right = mappingManager.p2v_x(godRect.right); + double bottom = mappingManager.p2v_y(godRect.bottom); + double top = mappingManager.p2v_y(godRect.top); + + _rectD_ob.left = left; + _rectD_ob.top = top; + _rectD_ob.right = right; + _rectD_ob.bottom = bottom; + _LineChart.notifyOB_ViewportChanged(_rectD_ob); + } + + + private void constrainRect(RectF godRect, RectF maxRect) { + float w = godRect.width(); + float h = godRect.height(); + + // 1. 保持比例 + if (godRect.left < maxRect.left) { + godRect.left = maxRect.left; + godRect.right = godRect.left + w; + } + if (godRect.top < maxRect.top) { + godRect.top = maxRect.top; + godRect.bottom = godRect.top + h; + } + if (godRect.right > maxRect.right) { + godRect.right = maxRect.right; + godRect.left = godRect.right - w; + } + if (godRect.bottom > maxRect.bottom) { + godRect.bottom = maxRect.bottom; + godRect.top = godRect.bottom - h; + } + + // 2. 限定值的范围 + if (godRect.left < maxRect.left) { + godRect.left = maxRect.left; + } + if (godRect.top < maxRect.top) { + godRect.top = maxRect.top; + } + if (godRect.right > maxRect.right) { + godRect.right = maxRect.right; + } + if (godRect.bottom > maxRect.bottom) { + godRect.bottom = maxRect.bottom; + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/TouchListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/TouchListener.java new file mode 100644 index 0000000..cdb316a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/TouchListener.java @@ -0,0 +1,482 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.touch; + +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewParent; +import android.widget.Scroller; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.charts.LineChart; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.listener.IDragListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; +import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.RectD; + +public class TouchListener implements View.OnTouchListener { + + ViewParent viewParent; + + GestureDetector _GestureDetector; + Zoomer _Zoomer; + Scroller _Scroller; + + LineChart _LineChart; + MappingManager _MappingManager; + + VelocityTracker _VelocityTracker; + TouchMode _TouchMode = TouchMode.NONE; + + /////////////////////////////////// 平滑的缩放 /////////////////////////////////// + double _zoom_w, _zoom_h; + float _zoom_cx, _zoom_cy; + + public TouchListener(LineChart lineChart) { + this._LineChart = lineChart; + + _GestureDetector = new GestureDetector(_LineChart.getContext(), new GestureListener()); + _MappingManager = lineChart.get_MappingManager(); + + _Zoomer = new Zoomer(); + _Scroller = new Scroller(lineChart.getContext()); + } + + + float _lastX, _lastY; + float _disX = 1, _disY = 1, _disXY = 1, _cX, _cY; + + @Override + public boolean onTouch(View v, MotionEvent event) { + + viewParent = v.getParent(); + + // 速度跟踪 + if (_VelocityTracker == null) { + _VelocityTracker = VelocityTracker.obtain(); + } + _VelocityTracker.addMovement(event); + + boolean hit = _GestureDetector.onTouchEvent(event); + if (hit) { + _LineChart.invalidate(); + return true; + } + + float x = event.getX(); + float y = event.getY(); + + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + stopAll(); + iNeedTouch(true); + _lastX = x; + _lastY = y; + break; + case MotionEvent.ACTION_POINTER_DOWN: + if (event.getPointerCount() >= 2) { + _disX = getXDist(event); + _disY = getYDist(event); + _disXY = getABSDist(event); + float tmpX = event.getX(0) + event.getX(1); + float tmpY = event.getY(0) + event.getY(1); + _cX = (tmpX / 2f); + _cY = (tmpY / 2f); + + _TouchMode = TouchMode.PINCH_ZOOM; + } + break; + case MotionEvent.ACTION_MOVE: + float dx = x - _lastX; + float dy = y - _lastY; + if (_TouchMode == TouchMode.DRAG) { + _VelocityTracker.computeCurrentVelocity(1000); + float vx = _VelocityTracker.getXVelocity();// 得到当前手指在这一点移动的速度 + float vy = _VelocityTracker.getYVelocity();// 速度分为了x和y轴两个方向的速度 + int direction = judgeDir(vx, vy); + doDrag(dx, dy, direction); + } else if (_TouchMode == TouchMode.PINCH_ZOOM) { + doPinch(event); + } else if (_TouchMode == TouchMode.NONE) { + _TouchMode = TouchMode.DRAG; + } + + _lastX = x; + _lastY = y; + break; + case MotionEvent.ACTION_POINTER_UP: + _TouchMode = TouchMode.NONE; + break; + case MotionEvent.ACTION_UP: + if (_TouchMode == TouchMode.DRAG) { + _TouchMode = TouchMode.FLING; + + _VelocityTracker.computeCurrentVelocity(1000, 5000); + int vx = (int) _VelocityTracker.getXVelocity(); + int vy = (int) _VelocityTracker.getYVelocity(); + if (vx > 20 || vy > 20) { + doFling(event.getX(), event.getY(), vx, vy); + } + + IDragListener listener = _LineChart.get_dragListener(); + if (listener != null) { + listener.onDrag(_LineChart.getVisiableMinX(), _LineChart.getVisiableMaxX()); + } + } + _TouchMode = TouchMode.NONE; + break; + case MotionEvent.ACTION_CANCEL: + if (_VelocityTracker != null) { + _VelocityTracker.recycle(); + _VelocityTracker = null; + } + + _TouchMode = TouchMode.NONE; + break; + } + + return true; + } + + float _lastScrollX, _lastScrollY; + + public void computeScroll() { + // 考虑滚动 + if (_Scroller.computeScrollOffset()) { + + int currX = _Scroller.getCurrX(); + int currY = _Scroller.getCurrY(); + + float dx = currX - _lastScrollX; + float dy = currY - _lastScrollY; + + doDrag(dx, dy, -1); + + _lastScrollX = currX; + _lastScrollY = currY; + } + + // 考虑缩放 + if (_Zoomer.computeZoom()) { + + float currentLevel = _Zoomer.getCurrentZoom(); + zoom(currentLevel, _zoom_w, _zoom_h, _zoom_cx, _zoom_cy); + } + } + + + boolean hitStart = false; + int hitCount = 0; + + /** + * lchart 需要触摸事件 + */ + private void iNeedTouch(boolean need) { + + if (need) { + viewParent.requestDisallowInterceptTouchEvent(true); + hitStart = false; + } else { + hitCount++; + + if (!hitStart) { + hitCount = 0; + hitStart = true; + } else { + + if (hitCount > 3) { + hitStart = false; + viewParent.requestDisallowInterceptTouchEvent(false); + } else { + viewParent.requestDisallowInterceptTouchEvent(true); + } + } + } + + } + + + private void stopAll() { + _Scroller.forceFinished(true); + _Zoomer.stop(); + } + + + private int judgeDir(float vx, float vy) { + + float x = Math.abs(vx); + float y = Math.abs(vy); + + if (x > y) { + // 方向是水平 + return 1; + } else { + // 方向是垂直 + return 2; + } + } + + /** + * 双手缩放 + * + * @param event + */ + private void doPinch(MotionEvent event) { + + if (!_LineChart.isScaleable()) { + return; + } + + iNeedTouch(true); + + float absDist = getABSDist(event); + float scale = _disXY / absDist; + + if (zoom_alone) { + // 考虑独立缩放 + float xDis = getXDist(event); + float yDis = getYDist(event); + + if (xDis > yDis) { + zoom(scale, 1, _cX, _cY); + } else { + zoom(1, scale, _cX, _cY); + } + } else { + zoom(scale, scale, _cX, _cY); + } + + _disXY = absDist; + } + + boolean canX_drag = true; + boolean canY_drag = true; + + /** + * 拖拽 + * + * @param dx + * @param dy + */ + private void doDrag(float dx, float dy, int direction) { + + if (!_LineChart.isDragable()) { + return; + } + + if (direction != -1) { + + RectD current = _MappingManager.get_currentViewPort(); + RectD maxx = _MappingManager.get_constrainViewPort(); + + boolean need = false; + + if (direction == 1) { + // hor + need = current.right < maxx.right; + need &= current.left > maxx.left; + + } else { + // ver + need = current.bottom > maxx.bottom; + need &= current.top < maxx.top; + } + + iNeedTouch(need); + } + + if (!canX_drag) { + dx = 0; + } + if (!canY_drag) { + dy = 0; + } + + _MappingManager.translate(dx, dy); + _LineChart.postInvalidate(); + } + + + /** + * 抛掷 + */ + private void doFling(float x, float y, int velocityX, int velocityY) { + + if (!_LineChart.isDragable()) { + return; + } + + _Scroller.forceFinished(true); + + _lastScrollX = x; + _lastScrollY = y; + + _Scroller.fling( + (int) x, (int) y, + velocityX, velocityY, + Integer.MIN_VALUE, Integer.MAX_VALUE, + Integer.MIN_VALUE, Integer.MAX_VALUE); + + _LineChart.invalidate(); + } + + + boolean canX_zoom = true; + boolean canY_zoom = true; + boolean zoom_alone = false; + + /** + * 应用于指定的缩放 + * + * @param scaleX + * @param scaleY + * @param cx + * @param cy + */ + private void zoom(float scaleX, float scaleY, float cx, float cy) { + + if (!_LineChart.isScaleable()) { + return; + } + + if (!canX_zoom) { + scaleX = 1; + } + if (!canY_zoom) { + scaleY = 1; + } + + _MappingManager.zoom(scaleX, scaleY, cx, cy); + _LineChart.postInvalidate(); + } + + + /** + * 应用于平滑的缩放 + * + * @param level + * @param startW + * @param startH + * @param cx + * @param cy + */ + private void zoom(float level, double startW, double startH, float cx, float cy) { + + if (!_LineChart.isScaleable()) { + return; + } + + _MappingManager.zoom(level, startW, startH, cx, cy, canX_zoom, canY_zoom); + _LineChart.postInvalidate(); + } + + private static float getABSDist(MotionEvent event) { + float x = event.getX(0) - event.getX(1); + float y = event.getY(0) - event.getY(1); + return (float) Math.sqrt(x * x + y * y); + } + + private static float getXDist(MotionEvent e) { + float x = Math.abs(e.getX(0) - e.getX(1)); + return x; + } + + private static float getYDist(MotionEvent e) { + float y = Math.abs(e.getY(0) - e.getY(1)); + return y; + } + + + public boolean isCanX_drag() { + return canX_drag; + } + + public void setCanX_drag(boolean canX_drag) { + this.canX_drag = canX_drag; + } + + public boolean isCanY_drag() { + return canY_drag; + } + + public void setCanY_drag(boolean canY_drag) { + this.canY_drag = canY_drag; + } + + public boolean isCanX_zoom() { + return canX_zoom; + } + + public void setCanX_zoom(boolean canX_zoom) { + this.canX_zoom = canX_zoom; + } + + public boolean isZoom_alone() { + return zoom_alone; + } + + public void setZoom_alone(boolean zoom_alone) { + this.zoom_alone = zoom_alone; + } + + public boolean isCanY_zoom() { + return canY_zoom; + } + + public void setCanY_zoom(boolean canY_zoom) { + this.canY_zoom = canY_zoom; + } + + class GestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDoubleTap(MotionEvent e) { + + //禁用双击放大,以后有需求可以在这里打开 + if (true){ + return false; + } + + _Zoomer.stop(); + + _zoom_w = _MappingManager.get_currentViewPort().width(); + _zoom_h = _MappingManager.get_currentViewPort().height(); + + _zoom_cx = e.getX(); + _zoom_cy = e.getY(); + + _Zoomer.startZoom(0.6f); + + return true; + } + + @Override + public boolean onDown(MotionEvent e) { + return super.onDown(e); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + return super.onFling(e1, e2, velocityX, velocityY); + } + + @Override + public void onLongPress(MotionEvent e) { + super.onLongPress(e); + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + return super.onScroll(e1, e2, distanceX, distanceY); + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + _LineChart.highLight_PixXY(e.getX(), e.getY()); + return true; + } + } + + enum TouchMode { + NONE, DRAG, X_ZOOM, Y_ZOOM, PINCH_ZOOM, ROTATE, SINGLE_TAP, DOUBLE_TAP, LONG_PRESS, FLING + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/Zoomer.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/Zoomer.java new file mode 100644 index 0000000..843742c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/touch/Zoomer.java @@ -0,0 +1,69 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.touch; + +import android.os.SystemClock; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +public class Zoomer { + + long _startTime; + int _duration = 500;// 动画的持续时间 + Interpolator _Interpolator;//校对机 + + float _endZoom; + float _currentLevel; + + boolean _isFinish = true; + + + public Zoomer() { + _Interpolator = new LinearInterpolator(); + } + + public void startZoom(float endZoom) { + _startTime = SystemClock.elapsedRealtime(); + _endZoom = endZoom; + _currentLevel = 1; + _isFinish = false; + } + + public float getCurrentZoom() { + return _currentLevel; + } + + + /** + * 计算当前的缩放级别 + * + * @return true:需要计算,false:不需要计算 + */ + public boolean computeZoom() { + if (_isFinish) { + return false; + } + + long d = SystemClock.elapsedRealtime() - _startTime; + if (d > _duration) { + _currentLevel = _endZoom; + _isFinish = true; + return false; + } + + float t = d * 1f / _duration; + _currentLevel = 1 - (1 - _endZoom) * _Interpolator.getInterpolation(t); + return true; + } + + public void stop() { + _isFinish = true; + } + + + public long get_duration() { + return _duration; + } + + public void set_duration(int _duration) { + this._duration = _duration; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/RectD.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/RectD.java new file mode 100644 index 0000000..4c1085e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/RectD.java @@ -0,0 +1,53 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils; + + +/** + * 数据视图 + * --------------------------- + * 约定: + * left 必须小于 right + * bottom 必须小于 top + */ + +public class RectD { + + public double left; + public double top; + public double right; + public double bottom; + + public RectD() { + } + + public RectD(double left, double top, double right, double bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public RectD(RectD rectD) { + setRectD(rectD); + } + + public void setRectD(RectD rectD) { + left = rectD.left; + top = rectD.top; + right = rectD.right; + bottom = rectD.bottom; + } + + public double width() { + return right - left; + } + + public double height() { + return top - bottom; + } + + + public String toString() { + return "RectD(" + left + ", " + top + ", " + + right + ", " + bottom + ")"; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleD_XY.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleD_XY.java new file mode 100644 index 0000000..93765f1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleD_XY.java @@ -0,0 +1,50 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils; + +/** + * 考虑到性能的原因,采用单例模式 + * -------------------- + * 尽量少的分配内存 + *

    + *

    + */ + +public class SingleD_XY { + private double x; + private double y; + + private static SingleD_XY value; + + private SingleD_XY() { + + } + + public synchronized static SingleD_XY getInstance() { + if (value == null) { + value = new SingleD_XY(); + } + return value; + } + + public double getX() { + return x; + } + + public SingleD_XY setX(double x) { + this.x = x; + return this; + } + + public double getY() { + return y; + } + + public SingleD_XY setY(double y) { + this.y = y; + return this; + } + + @Override + public String toString() { + return "U_XY x: " + x + " y:" + y; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleF_XY.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleF_XY.java new file mode 100644 index 0000000..5ad44f9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/SingleF_XY.java @@ -0,0 +1,50 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils; + +/** + * 考虑到性能的原因,采用单例模式 + * -------------------- + * 尽量少的分配内存 + *

    + *

    + */ + +public class SingleF_XY { + private float x; + private float y; + + private static SingleF_XY value; + + private SingleF_XY() { + + } + + public synchronized static SingleF_XY getInstance() { + if (value == null) { + value = new SingleF_XY(); + } + return value; + } + + public float getX() { + return x; + } + + public SingleF_XY setX(float x) { + this.x = x; + return this; + } + + public float getY() { + return y; + } + + public SingleF_XY setY(float y) { + this.y = y; + return this; + } + + @Override + public String toString() { + return "U_XY x: " + x + " y:" + y; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/Utils.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/Utils.java new file mode 100644 index 0000000..8049a16 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/linechart/utils/Utils.java @@ -0,0 +1,70 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils; + +import android.content.res.Resources; +import android.graphics.Paint; +import android.text.TextUtils; + + +public class Utils { + + public static float dp2px(float dp) { + return (int) (dp * Resources.getSystem().getDisplayMetrics().density + 0.5f); + } + public static int sp2px(float spValue) + { + final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + public static float textWidth(Paint paint, String txt) { + return paint.measureText(txt); + } + + private static Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); + + public static int textHeightAsc(Paint paint) { + paint.getFontMetrics(mFontMetrics); + return (int) (Math.abs(mFontMetrics.ascent)); + } + + public static int textHeight(Paint paint) { + paint.getFontMetrics(mFontMetrics); + return (int) (Math.abs(mFontMetrics.ascent) + Math.abs(mFontMetrics.descent)); + } + + /** + * 将杂乱的数字变成里程碑。 + * + * @param number + * @return + */ + public static float roundNumber2One(double number) { + if (Double.isInfinite(number) || + Double.isNaN(number) || + number == 0.0) + return 0; + + final float d = (float) Math.ceil((float) Math.log10(number < 0 ? -number : number));//有几位? + final int pw = 1 - (int) d; + final float magnitude = (float) Math.pow(10, pw); + final long shifted = Math.round(number * magnitude); + return shifted / magnitude; + } + + /** + * 检测URL是否以http://或者https://开头,不是的话加上http:// + *

    + *

    + * + */ + public static String checkURL(String url) { + if (TextUtils.isEmpty(url)) { + return url; + } + if (!url.startsWith("http://") && !url.startsWith("https://")) { + url = "http://" + url; + } + return url; + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ScrollableViewHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ScrollableViewHelper.java new file mode 100644 index 0000000..4f6d913 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ScrollableViewHelper.java @@ -0,0 +1,63 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.slidinguplayout; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ListView; +import android.widget.ScrollView; + +/** + * Helper class for determining the current scroll positions for scrollable views. Currently works + * for ListView, ScrollView and RecyclerView, but the library users can override it to add support + * for other views. + */ +public class ScrollableViewHelper { + /** + * Returns the current scroll position of the scrollable view. If this method returns zero or + * less, it means at the scrollable view is in a position such as the panel should handle + * scrolling. If the method returns anything above zero, then the panel will let the scrollable + * view handle the scrolling + * + * @param scrollableView the scrollable view + * @param isSlidingUp whether or not the panel is sliding up or down + * @return the scroll position + */ + public int getScrollableViewScrollPosition(View scrollableView, boolean isSlidingUp) { + if (scrollableView == null) return 0; + if (scrollableView instanceof ScrollView) { + if (isSlidingUp) { + return scrollableView.getScrollY(); + } else { + ScrollView sv = ((ScrollView) scrollableView); + View child = sv.getChildAt(0); + return (child.getBottom() - (sv.getHeight() + sv.getScrollY())); + } + } else if (scrollableView instanceof ListView && ((ListView) scrollableView).getChildCount() > 0) { + ListView lv = ((ListView) scrollableView); + if (lv.getAdapter() == null) return 0; + if (isSlidingUp) { + View firstChild = lv.getChildAt(0); + // Approximate the scroll position based on the top child and the first visible item + return lv.getFirstVisiblePosition() * firstChild.getHeight() - firstChild.getTop(); + } else { + View lastChild = lv.getChildAt(lv.getChildCount() - 1); + // Approximate the scroll position based on the bottom child and the last visible item + return (lv.getAdapter().getCount() - lv.getLastVisiblePosition() - 1) * lastChild.getHeight() + lastChild.getBottom() - lv.getBottom(); + } + } else if (scrollableView instanceof RecyclerView && ((RecyclerView) scrollableView).getChildCount() > 0) { + RecyclerView rv = ((RecyclerView) scrollableView); + RecyclerView.LayoutManager lm = rv.getLayoutManager(); + if (rv.getAdapter() == null) return 0; + if (isSlidingUp) { + View firstChild = rv.getChildAt(0); + // Approximate the scroll position based on the top child and the first visible item + return rv.getChildLayoutPosition(firstChild) * lm.getDecoratedMeasuredHeight(firstChild) - lm.getDecoratedTop(firstChild); + } else { + View lastChild = rv.getChildAt(rv.getChildCount() - 1); + // Approximate the scroll position based on the bottom child and the last visible item + return (rv.getAdapter().getItemCount() - 1) * lm.getDecoratedMeasuredHeight(lastChild) + lm.getDecoratedBottom(lastChild) - rv.getBottom(); + } + } else { + return 0; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/SlidingUpPanelLayout.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/SlidingUpPanelLayout.java new file mode 100644 index 0000000..c683681 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/SlidingUpPanelLayout.java @@ -0,0 +1,1489 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.slidinguplayout; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +public class SlidingUpPanelLayout extends ViewGroup { + + private static final String TAG = SlidingUpPanelLayout.class.getSimpleName(); + + /** + * Default peeking out panel heightumanoScrollableView + */ + private static final int DEFAULT_PANEL_HEIGHT = 68; // dp; + + /** + * Default anchor point height + */ + private static final float DEFAULT_ANCHOR_POINT = 1.0f; // In relative % + + /** + * Default initial state for the component + */ + private static PanelState DEFAULT_SLIDE_STATE = PanelState.COLLAPSED; + + /** + * Default height of the shadow above the peeking out panel + */ + private static final int DEFAULT_SHADOW_HEIGHT = 4; // dp; + + /** + * If no fade color is given by default it will fade to 80% gray. + */ + private static final int DEFAULT_FADE_COLOR = 0x99000000; + + /** + * Default Minimum velocity that will be detected as a fling + */ + private static final int DEFAULT_MIN_FLING_VELOCITY = 400; // dips per second + /** + * Default is set to false because that is how it was written + */ + private static final boolean DEFAULT_OVERLAY_FLAG = false; + /** + * Default is set to true for clip panel for performance reasons + */ + private static final boolean DEFAULT_CLIP_PANEL_FLAG = true; + /** + * Default attributes for layout + */ + private static final int[] DEFAULT_ATTRS = new int[]{ + android.R.attr.gravity + }; + /** + * Tag for the sliding state stored inside the bundle + */ + public static final String SLIDING_STATE = "sliding_state"; + + /** + * Minimum velocity that will be detected as a fling + */ + private int mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY; + + /** + * The fade color used for the panel covered by the slider. 0 = no fading. + */ + private int mCoveredFadeColor = DEFAULT_FADE_COLOR; + + /** + * Default parallax length of the main view + */ + private static final int DEFAULT_PARALLAX_OFFSET = 0; + + /** + * The paint used to dim the main layout when sliding + */ + private final Paint mCoveredFadePaint = new Paint(); + + /** + * Drawable used to draw the shadow between panes. + */ + private final Drawable mShadowDrawable; + + /** + * The size of the overhang in pixels. + */ + private int mPanelHeight = -1; + + /** + * The size of the shadow in pixels. + */ + private int mShadowHeight = -1; + + /** + * Parallax offset + */ + private int mParallaxOffset = -1; + + /** + * True if the collapsed panel should be dragged up. + */ + private boolean mIsSlidingUp; + + /** + * Panel overlays the windows instead of putting it underneath it. + */ + private boolean mOverlayContent = DEFAULT_OVERLAY_FLAG; + + /** + * The main view is clipped to the main top border + */ + private boolean mClipPanel = DEFAULT_CLIP_PANEL_FLAG; + + /** + * If provided, the panel can be dragged by only this view. Otherwise, the entire panel can be + * used for dragging. + */ + private View mDragView; + + /** + * If provided, the panel can be dragged by only this view. Otherwise, the entire panel can be + * used for dragging. + */ + private int mDragViewResId = -1; + + /** + * If provided, the panel will transfer the scroll from this view to itself when needed. + */ + private View mScrollableView; + private int mScrollableViewResId; + private ScrollableViewHelper mScrollableViewHelper = new ScrollableViewHelper(); + + /** + * The child view that can slide, if any. + */ + private View mSlideableView; + + /** + * The main view + */ + private View mMainView; + + /** + * Current state of the slideable view. + */ + public enum PanelState { + EXPANDED, + COLLAPSED, + ANCHORED, + HIDDEN, + DRAGGING + } + + private PanelState mSlideState = DEFAULT_SLIDE_STATE; + + /** + * If the current slide state is DRAGGING, this will store the last non dragging state + */ + private PanelState mLastNotDraggingSlideState = DEFAULT_SLIDE_STATE; + + /** + * How far the panel is offset from its expanded position. + * range [0, 1] where 0 = collapsed, 1 = expanded. + */ + private float mSlideOffset; + + /** + * How far in pixels the slideable panel may move. + */ + private int mSlideRange; + + /** + * An anchor point where the panel can stop during sliding + */ + private float mAnchorPoint = 1.f; + + /** + * A panel view is locked into internal scrolling or another condition that + * is preventing a drag. + */ + private boolean mIsUnableToDrag; + + /** + * Flag indicating that sliding feature is enabled\disabled + */ + private boolean mIsTouchEnabled; + + private float mPrevMotionX; + private float mPrevMotionY; + private float mInitialMotionX; + private float mInitialMotionY; + private boolean mIsScrollableViewHandlingTouch = false; + + private final List mPanelSlideListeners = new CopyOnWriteArrayList<>(); + private OnClickListener mFadeOnClickListener; + + private final ViewDragHelper mDragHelper; + + /** + * Stores whether or not the pane was expanded the last time it was slideable. + * If expand/collapse operations are invoked this state is modified. Used by + * instance state save/restore. + */ + private boolean mFirstLayout = true; + + private final Rect mTmpRect = new Rect(); + + /** + * Listener for monitoring events about sliding panes. + */ + public interface PanelSlideListener { + /** + * Called when a sliding pane's position changes. + * + * @param panel The child view that was moved + * @param slideOffset The new offset of this sliding pane within its range, from 0-1 + */ + public void onPanelSlide(View panel, float slideOffset); + + /** + * Called when a sliding panel state changes + * + * @param panel The child view that was slid to an collapsed position + */ + public void onPanelStateChanged(View panel, PanelState previousState, PanelState newState); + } + + /** + * No-op stubs for {@link PanelSlideListener}. If you only want to implement a subset + * of the listener methods you can extend this instead of implement the full interface. + */ + public static class SimplePanelSlideListener implements PanelSlideListener { + @Override + public void onPanelSlide(View panel, float slideOffset) { + } + + @Override + public void onPanelStateChanged(View panel, PanelState previousState, PanelState newState) { + } + } + + public SlidingUpPanelLayout(Context context) { + this(context, null); + } + + public SlidingUpPanelLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + if (isInEditMode()) { + mShadowDrawable = null; + mDragHelper = null; + return; + } + + Interpolator scrollerInterpolator = null; + if (attrs != null) { + TypedArray defAttrs = context.obtainStyledAttributes(attrs, DEFAULT_ATTRS); + + if (defAttrs != null) { + int gravity = defAttrs.getInt(0, Gravity.NO_GRAVITY); + setGravity(gravity); + defAttrs.recycle(); + } + + + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingUpPanelLayout); + + if (ta != null) { + mPanelHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoPanelHeight, -1); + mShadowHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoShadowHeight, -1); + mParallaxOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoParallaxOffset, -1); + + mMinFlingVelocity = ta.getInt(R.styleable.SlidingUpPanelLayout_umanoFlingVelocity, DEFAULT_MIN_FLING_VELOCITY); + mCoveredFadeColor = ta.getColor(R.styleable.SlidingUpPanelLayout_umanoFadeColor, DEFAULT_FADE_COLOR); + + mDragViewResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_umanoDragView, -1); + mScrollableViewResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_umanoScrollableView, -1); + + mOverlayContent = ta.getBoolean(R.styleable.SlidingUpPanelLayout_umanoOverlay, DEFAULT_OVERLAY_FLAG); + mClipPanel = ta.getBoolean(R.styleable.SlidingUpPanelLayout_umanoClipPanel, DEFAULT_CLIP_PANEL_FLAG); + + mAnchorPoint = ta.getFloat(R.styleable.SlidingUpPanelLayout_umanoAnchorPoint, DEFAULT_ANCHOR_POINT); + + mSlideState = PanelState.values()[ta.getInt(R.styleable.SlidingUpPanelLayout_umanoInitialState, DEFAULT_SLIDE_STATE.ordinal())]; + + int interpolatorResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_umanoScrollInterpolator, -1); + ta.recycle(); + if (interpolatorResId != -1) { + scrollerInterpolator = AnimationUtils.loadInterpolator(context, interpolatorResId); + } + } + } + + final float density = context.getResources().getDisplayMetrics().density; + if (mPanelHeight == -1) { + mPanelHeight = (int) (DEFAULT_PANEL_HEIGHT * density + 0.5f); + } + if (mShadowHeight == -1) { + mShadowHeight = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f); + } + if (mParallaxOffset == -1) { + mParallaxOffset = (int) (DEFAULT_PARALLAX_OFFSET * density); + } + // If the shadow height is zero, don't show the shadow + if (mShadowHeight > 0) { + if (mIsSlidingUp) { + mShadowDrawable = getResources().getDrawable(R.drawable.above_shadow); + } else { + mShadowDrawable = getResources().getDrawable(R.drawable.below_shadow); + } + } else { + mShadowDrawable = null; + } + + setWillNotDraw(false); + + mDragHelper = ViewDragHelper.create(this, 0.5f, scrollerInterpolator, new DragHelperCallback()); + mDragHelper.setMinVelocity(mMinFlingVelocity * density); + + mIsTouchEnabled = true; + } + + /** + * Set the Drag View after the view is inflated + */ + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + if (mDragViewResId != -1) { + setDragView(findViewById(mDragViewResId)); + } + if (mScrollableViewResId != -1) { + setScrollableView(findViewById(mScrollableViewResId)); + } + } + + public void setGravity(int gravity) { + if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) { + throw new IllegalArgumentException("gravity must be set to either top or bottom"); + } + mIsSlidingUp = gravity == Gravity.BOTTOM; + if (!mFirstLayout) { + requestLayout(); + } + } + + /** + * Set the color used to fade the pane covered by the sliding pane out when the pane + * will become fully covered in the expanded state. + * + * @param color An ARGB-packed color value + */ + public void setCoveredFadeColor(int color) { + mCoveredFadeColor = color; + requestLayout(); + } + + /** + * @return The ARGB-packed color value used to fade the fixed pane + */ + public int getCoveredFadeColor() { + return mCoveredFadeColor; + } + + /** + * Set sliding enabled flag + * + * @param enabled flag value + */ + public void setTouchEnabled(boolean enabled) { + mIsTouchEnabled = enabled; + } + + public boolean isTouchEnabled() { + return mIsTouchEnabled && mSlideableView != null && mSlideState != PanelState.HIDDEN; + } + + /** + * Set the collapsed panel height in pixels + * + * @param val A height in pixels + */ + public void setPanelHeight(int val) { + if (getPanelHeight() == val) { + return; + } + + mPanelHeight = val; + if (!mFirstLayout) { + requestLayout(); + } + + if (getPanelState() == PanelState.COLLAPSED) { + smoothToBottom(); + invalidate(); + return; + } + } + + protected void smoothToBottom() { + smoothSlideTo(0, 0); + } + + /** + * @return The current shadow height + */ + public int getShadowHeight() { + return mShadowHeight; + } + + /** + * Set the shadow height + * + * @param val A height in pixels + */ + public void setShadowHeight(int val) { + mShadowHeight = val; + if (!mFirstLayout) { + invalidate(); + } + } + + /** + * @return The current collapsed panel height + */ + public int getPanelHeight() { + return mPanelHeight; + } + + /** + * @return The current parallax offset + */ + public int getCurrentParallaxOffset() { + // Clamp slide offset at zero for parallax computation; + int offset = (int) (mParallaxOffset * Math.max(mSlideOffset, 0)); + return mIsSlidingUp ? -offset : offset; + } + + /** + * Set parallax offset for the panel + * + * @param val A height in pixels + */ + public void setParallaxOffset(int val) { + mParallaxOffset = val; + if (!mFirstLayout) { + requestLayout(); + } + } + + /** + * @return The current minimin fling velocity + */ + public int getMinFlingVelocity() { + return mMinFlingVelocity; + } + + /** + * Sets the minimum fling velocity for the panel + * + * @param val the new value + */ + public void setMinFlingVelocity(int val) { + mMinFlingVelocity = val; + } + + /** + * Adds a panel slide listener + * + * @param listener + */ + public void addPanelSlideListener(PanelSlideListener listener) { + synchronized (mPanelSlideListeners) { + mPanelSlideListeners.add(listener); + } + } + + /** + * Removes a panel slide listener + * + * @param listener + */ + public void removePanelSlideListener(PanelSlideListener listener) { + synchronized (mPanelSlideListeners) { + mPanelSlideListeners.remove(listener); + } + } + + /** + * Provides an on click for the portion of the main view that is dimmed. The listener is not + * triggered if the panel is in a collapsed or a hidden position. If the on click listener is + * not provided, the clicks on the dimmed area are passed through to the main layout. + * + * @param listener + */ + public void setFadeOnClickListener(OnClickListener listener) { + mFadeOnClickListener = listener; + } + + /** + * Set the draggable view portion. Use to null, to allow the whole panel to be draggable + * + * @param dragView A view that will be used to drag the panel. + */ + public void setDragView(View dragView) { + if (mDragView != null) { + mDragView.setOnClickListener(null); + } + mDragView = dragView; + if (mDragView != null) { + mDragView.setClickable(true); + mDragView.setFocusable(false); + mDragView.setFocusableInTouchMode(false); + mDragView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (!isEnabled() || !isTouchEnabled()) return; + if (mSlideState != PanelState.EXPANDED && mSlideState != PanelState.ANCHORED) { + if (mAnchorPoint < 1.0f) { + setPanelState(PanelState.ANCHORED); + } else { + setPanelState(PanelState.EXPANDED); + } + } else { + setPanelState(PanelState.COLLAPSED); + } + } + }); + ; + } + } + + /** + * Set the draggable view portion. Use to null, to allow the whole panel to be draggable + * + * @param dragViewResId The resource ID of the new drag view + */ + public void setDragView(int dragViewResId) { + mDragViewResId = dragViewResId; + setDragView(findViewById(dragViewResId)); + } + + /** + * Set the scrollable child of the sliding layout. If set, scrolling will be transfered between + * the panel and the view when necessary + * + * @param scrollableView The scrollable view + */ + public void setScrollableView(View scrollableView) { + mScrollableView = scrollableView; + } + + /** + * Sets the current scrollable view helper. See ScrollableViewHelper description for details. + * + * @param helper + */ + public void setScrollableViewHelper(ScrollableViewHelper helper) { + mScrollableViewHelper = helper; + } + + /** + * Set an anchor point where the panel can stop during sliding + * + * @param anchorPoint A value between 0 and 1, determining the position of the anchor point + * starting from the top of the layout. + */ + public void setAnchorPoint(float anchorPoint) { + if (anchorPoint > 0 && anchorPoint <= 1) { + mAnchorPoint = anchorPoint; + mFirstLayout = true; + requestLayout(); + } + } + + /** + * Gets the currently set anchor point + * + * @return the currently set anchor point + */ + public float getAnchorPoint() { + return mAnchorPoint; + } + + /** + * Sets whether or not the panel overlays the content + * + * @param overlayed + */ + public void setOverlayed(boolean overlayed) { + mOverlayContent = overlayed; + } + + /** + * Check if the panel is set as an overlay. + */ + public boolean isOverlayed() { + return mOverlayContent; + } + + /** + * Sets whether or not the main content is clipped to the top of the panel + * + * @param clip + */ + public void setClipPanel(boolean clip) { + mClipPanel = clip; + } + + /** + * Check whether or not the main content is clipped to the top of the panel + */ + public boolean isClipPanel() { + return mClipPanel; + } + + + void dispatchOnPanelSlide(View panel) { + synchronized (mPanelSlideListeners) { + for (PanelSlideListener l : mPanelSlideListeners) { + l.onPanelSlide(panel, mSlideOffset); + } + } + } + + + void dispatchOnPanelStateChanged(View panel, PanelState previousState, PanelState newState) { + synchronized (mPanelSlideListeners) { + for (PanelSlideListener l : mPanelSlideListeners) { + l.onPanelStateChanged(panel, previousState, newState); + } + } + sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + + void updateObscuredViewVisibility() { + if (getChildCount() == 0) { + return; + } + final int leftBound = getPaddingLeft(); + final int rightBound = getWidth() - getPaddingRight(); + final int topBound = getPaddingTop(); + final int bottomBound = getHeight() - getPaddingBottom(); + final int left; + final int right; + final int top; + final int bottom; + if (mSlideableView != null && hasOpaqueBackground(mSlideableView)) { + left = mSlideableView.getLeft(); + right = mSlideableView.getRight(); + top = mSlideableView.getTop(); + bottom = mSlideableView.getBottom(); + } else { + left = right = top = bottom = 0; + } + View child = getChildAt(0); + final int clampedChildLeft = Math.max(leftBound, child.getLeft()); + final int clampedChildTop = Math.max(topBound, child.getTop()); + final int clampedChildRight = Math.min(rightBound, child.getRight()); + final int clampedChildBottom = Math.min(bottomBound, child.getBottom()); + final int vis; + if (clampedChildLeft >= left && clampedChildTop >= top && + clampedChildRight <= right && clampedChildBottom <= bottom) { + vis = INVISIBLE; + } else { + vis = VISIBLE; + } + child.setVisibility(vis); + } + + void setAllChildrenVisible() { + for (int i = 0, childCount = getChildCount(); i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == INVISIBLE) { + child.setVisibility(VISIBLE); + } + } + } + + private static boolean hasOpaqueBackground(View v) { + final Drawable bg = v.getBackground(); + return bg != null && bg.getOpacity() == PixelFormat.OPAQUE; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + final int widthSize = MeasureSpec.getSize(widthMeasureSpec); + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + final int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthMode != MeasureSpec.EXACTLY && widthMode != MeasureSpec.AT_MOST) { + throw new IllegalStateException("Width must have an exact value or MATCH_PARENT"); + } else if (heightMode != MeasureSpec.EXACTLY && heightMode != MeasureSpec.AT_MOST) { + throw new IllegalStateException("Height must have an exact value or MATCH_PARENT"); + } + + final int childCount = getChildCount(); + + if (childCount != 2) { + throw new IllegalStateException("Sliding up panel layout must have exactly 2 children!"); + } + + mMainView = getChildAt(0); + mSlideableView = getChildAt(1); + if (mDragView == null) { + setDragView(mSlideableView); + } + + // If the sliding panel is not visible, then put the whole view in the hidden state + if (mSlideableView.getVisibility() != VISIBLE) { + mSlideState = PanelState.HIDDEN; + } + + int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom(); + int layoutWidth = widthSize - getPaddingLeft() - getPaddingRight(); + + // First pass. Measure based on child LayoutParams width/height. + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + // We always measure the sliding panel in order to know it's height (needed for show panel) + if (child.getVisibility() == GONE && i == 0) { + continue; + } + + int height = layoutHeight; + int width = layoutWidth; + if (child == mMainView) { + if (!mOverlayContent && mSlideState != PanelState.HIDDEN) { + height -= mPanelHeight; + } + + width -= lp.leftMargin + lp.rightMargin; + } else if (child == mSlideableView) { + // The slideable view should be aware of its top margin. + // See https://github.com/umano/AndroidSlidingUpPanel/issues/412. + height -= lp.topMargin; + } + + int childWidthSpec; + if (lp.width == LayoutParams.WRAP_CONTENT) { + childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST); + } else if (lp.width == LayoutParams.MATCH_PARENT) { + childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); + } else { + childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); + } + + int childHeightSpec; + if (lp.height == LayoutParams.WRAP_CONTENT) { + childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + } else { + // Modify the height based on the weight. + if (lp.weight > 0 && lp.weight < 1) { + height = (int) (height * lp.weight); + } else if (lp.height != LayoutParams.MATCH_PARENT) { + height = lp.height; + } + childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + } + + child.measure(childWidthSpec, childHeightSpec); + + if (child == mSlideableView) { + mSlideRange = mSlideableView.getMeasuredHeight() - mPanelHeight; + } + } + + setMeasuredDimension(widthSize, heightSize); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int paddingLeft = getPaddingLeft(); + final int paddingTop = getPaddingTop(); + + final int childCount = getChildCount(); + + if (mFirstLayout) { + switch (mSlideState) { + case EXPANDED: + mSlideOffset = 1.0f; + break; + case ANCHORED: + mSlideOffset = mAnchorPoint; + break; + case HIDDEN: + int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight); + mSlideOffset = computeSlideOffset(newTop); + break; + default: + mSlideOffset = 0.f; + break; + } + } + + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + // Always layout the sliding view on the first layout + if (child.getVisibility() == GONE && (i == 0 || mFirstLayout)) { + continue; + } + + final int childHeight = child.getMeasuredHeight(); + int childTop = paddingTop; + + if (child == mSlideableView) { + childTop = computePanelTopPosition(mSlideOffset); + } + + if (!mIsSlidingUp) { + if (child == mMainView && !mOverlayContent) { + childTop = computePanelTopPosition(mSlideOffset) + mSlideableView.getMeasuredHeight(); + } + } + final int childBottom = childTop + childHeight; + final int childLeft = paddingLeft + lp.leftMargin; + final int childRight = childLeft + child.getMeasuredWidth(); + + child.layout(childLeft, childTop, childRight, childBottom); + } + + if (mFirstLayout) { + updateObscuredViewVisibility(); + } + applyParallaxForCurrentSlideOffset(); + + mFirstLayout = false; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + // Recalculate sliding panes and their details + if (h != oldh) { + mFirstLayout = true; + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + // If the scrollable view is handling touch, never intercept + if (mIsScrollableViewHandlingTouch || !isTouchEnabled()) { + mDragHelper.abort(); + return false; + } + + final int action = MotionEventCompat.getActionMasked(ev); + final float x = ev.getX(); + final float y = ev.getY(); + final float adx = Math.abs(x - mInitialMotionX); + final float ady = Math.abs(y - mInitialMotionY); + final int dragSlop = mDragHelper.getTouchSlop(); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + mIsUnableToDrag = false; + mInitialMotionX = x; + mInitialMotionY = y; + if (!isViewUnder(mDragView, (int) x, (int) y)) { + mDragHelper.cancel(); + mIsUnableToDrag = true; + return false; + } + + break; + } + + case MotionEvent.ACTION_MOVE: { + if (ady > dragSlop && adx > ady) { + mDragHelper.cancel(); + mIsUnableToDrag = true; + return false; + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + // If the dragView is still dragging when we get here, we need to call processTouchEvent + // so that the view is settled + // Added to make scrollable views work (tokudu) + if (mDragHelper.isDragging()) { + mDragHelper.processTouchEvent(ev); + return true; + } + // Check if this was a click on the faded part of the screen, and fire off the listener if there is one. + if (ady <= dragSlop + && adx <= dragSlop + && mSlideOffset > 0 && !isViewUnder(mSlideableView, (int) mInitialMotionX, (int) mInitialMotionY) && mFadeOnClickListener != null) { + playSoundEffect(android.view.SoundEffectConstants.CLICK); + mFadeOnClickListener.onClick(this); + return true; + } + break; + } + return mDragHelper.shouldInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (!isEnabled() || !isTouchEnabled()) { + return super.onTouchEvent(ev); + } + try { + mDragHelper.processTouchEvent(ev); + return true; + } catch (Exception ex) { + // Ignore the pointer out of range exception + return false; + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final int action = MotionEventCompat.getActionMasked(ev); + + if (!isEnabled() || !isTouchEnabled() || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) { + mDragHelper.abort(); + return super.dispatchTouchEvent(ev); + } + + final float x = ev.getX(); + final float y = ev.getY(); + + if (action == MotionEvent.ACTION_DOWN) { + mIsScrollableViewHandlingTouch = false; + mPrevMotionX = x; + mPrevMotionY = y; + } else if (action == MotionEvent.ACTION_MOVE) { + float dx = x - mPrevMotionX; + float dy = y - mPrevMotionY; + mPrevMotionX = x; + mPrevMotionY = y; + + if (Math.abs(dx) > Math.abs(dy)) { + // Scrolling horizontally, so ignore + return super.dispatchTouchEvent(ev); + } + + // If the scroll view isn't under the touch, pass the + // event along to the dragView. + if (!isViewUnder(mScrollableView, (int) mInitialMotionX, (int) mInitialMotionY)) { + return super.dispatchTouchEvent(ev); + } + + // Which direction (up or down) is the drag moving? + if (dy * (mIsSlidingUp ? 1 : -1) > 0) { // Collapsing + // Is the child less than fully scrolled? + // Then let the child handle it. + if (mScrollableViewHelper.getScrollableViewScrollPosition(mScrollableView, mIsSlidingUp) > 0) { + mIsScrollableViewHandlingTouch = true; + return super.dispatchTouchEvent(ev); + } + + // Was the child handling the touch previously? + // Then we need to rejigger things so that the + // drag panel gets a proper down event. + if (mIsScrollableViewHandlingTouch) { + // Send an 'UP' event to the child. + MotionEvent up = MotionEvent.obtain(ev); + up.setAction(MotionEvent.ACTION_CANCEL); + super.dispatchTouchEvent(up); + up.recycle(); + + // Send a 'DOWN' event to the panel. (We'll cheat + // and hijack this one) + ev.setAction(MotionEvent.ACTION_DOWN); + } + + mIsScrollableViewHandlingTouch = false; + return this.onTouchEvent(ev); + } else if (dy * (mIsSlidingUp ? 1 : -1) < 0) { // Expanding + // Is the panel less than fully expanded? + // Then we'll handle the drag here. + if (mSlideOffset < 1.0f) { + mIsScrollableViewHandlingTouch = false; + return this.onTouchEvent(ev); + } + + // Was the panel handling the touch previously? + // Then we need to rejigger things so that the + // child gets a proper down event. + if (!mIsScrollableViewHandlingTouch && mDragHelper.isDragging()) { + mDragHelper.cancel(); + ev.setAction(MotionEvent.ACTION_DOWN); + } + + mIsScrollableViewHandlingTouch = true; + return super.dispatchTouchEvent(ev); + } + } else if (action == MotionEvent.ACTION_UP) { + // If the scrollable view was handling the touch and we receive an up + // we want to clear any previous dragging state so we don't intercept a touch stream accidentally + if (mIsScrollableViewHandlingTouch) { + mDragHelper.setDragState(ViewDragHelper.STATE_IDLE); + } + } + + // In all other cases, just let the default behavior take over. + return super.dispatchTouchEvent(ev); + } + + private boolean isViewUnder(View view, int x, int y) { + if (view == null) return false; + int[] viewLocation = new int[2]; + view.getLocationOnScreen(viewLocation); + int[] parentLocation = new int[2]; + this.getLocationOnScreen(parentLocation); + int screenX = parentLocation[0] + x; + int screenY = parentLocation[1] + y; + return screenX >= viewLocation[0] && screenX < viewLocation[0] + view.getWidth() && + screenY >= viewLocation[1] && screenY < viewLocation[1] + view.getHeight(); + } + + /* + * Computes the top position of the panel based on the slide offset. + */ + private int computePanelTopPosition(float slideOffset) { + int slidingViewHeight = mSlideableView != null ? mSlideableView.getMeasuredHeight() : 0; + int slidePixelOffset = (int) (slideOffset * mSlideRange); + // Compute the top of the panel if its collapsed + return mIsSlidingUp + ? getMeasuredHeight() - getPaddingBottom() - mPanelHeight - slidePixelOffset + : getPaddingTop() - slidingViewHeight + mPanelHeight + slidePixelOffset; + } + + /* + * Computes the slide offset based on the top position of the panel + */ + private float computeSlideOffset(int topPosition) { + // Compute the panel top position if the panel is collapsed (offset 0) + final int topBoundCollapsed = computePanelTopPosition(0); + + // Determine the new slide offset based on the collapsed top position and the new required + // top position + return (mIsSlidingUp + ? (float) (topBoundCollapsed - topPosition) / mSlideRange + : (float) (topPosition - topBoundCollapsed) / mSlideRange); + } + + /** + * Returns the current state of the panel as an enum. + * + * @return the current panel state + */ + public PanelState getPanelState() { + return mSlideState; + } + + /** + * Change panel state to the given state with + * + * @param state - new panel state + */ + public void setPanelState(PanelState state) { + + // Abort any running animation, to allow state change + if(mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING){ + LogUtil.debugLog(TAG, "View is settling. Aborting animation."); + mDragHelper.abort(); + } + + if (state == null || state == PanelState.DRAGGING) { + throw new IllegalArgumentException("Panel state cannot be null or DRAGGING."); + } + if (!isEnabled() + || (!mFirstLayout && mSlideableView == null) + || state == mSlideState + || mSlideState == PanelState.DRAGGING) return; + + if (mFirstLayout) { + setPanelStateInternal(state); + } else { + if (mSlideState == PanelState.HIDDEN) { + mSlideableView.setVisibility(View.VISIBLE); + requestLayout(); + } + switch (state) { + case ANCHORED: + smoothSlideTo(mAnchorPoint, 0); + break; + case COLLAPSED: + smoothSlideTo(0, 0); + break; + case EXPANDED: + smoothSlideTo(1.0f, 0); + break; + case HIDDEN: + int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight); + smoothSlideTo(computeSlideOffset(newTop), 0); + break; + } + } + } + + private void setPanelStateInternal(PanelState state) { + if (mSlideState == state) return; + PanelState oldState = mSlideState; + mSlideState = state; + dispatchOnPanelStateChanged(this, oldState, state); + } + + /** + * Update the parallax based on the current slide offset. + */ + @SuppressLint("NewApi") + private void applyParallaxForCurrentSlideOffset() { + if (mParallaxOffset > 0) { + int mainViewOffset = getCurrentParallaxOffset(); + ViewCompat.setTranslationY(mMainView, mainViewOffset); + } + } + + private void onPanelDragged(int newTop) { + if (mSlideState != PanelState.DRAGGING) { + mLastNotDraggingSlideState = mSlideState; + } + setPanelStateInternal(PanelState.DRAGGING); + // Recompute the slide offset based on the new top position + mSlideOffset = computeSlideOffset(newTop); + applyParallaxForCurrentSlideOffset(); + // Dispatch the slide event + dispatchOnPanelSlide(mSlideableView); + // If the slide offset is negative, and overlay is not on, we need to increase the + // height of the main content + LayoutParams lp = (LayoutParams) mMainView.getLayoutParams(); + int defaultHeight = getHeight() - getPaddingBottom() - getPaddingTop() - mPanelHeight; + + if (mSlideOffset <= 0 && !mOverlayContent) { + // expand the main view + lp.height = mIsSlidingUp ? (newTop - getPaddingBottom()) : (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() - newTop); + if (lp.height == defaultHeight) { + lp.height = LayoutParams.MATCH_PARENT; + } + mMainView.requestLayout(); + } else if (lp.height != LayoutParams.MATCH_PARENT && !mOverlayContent) { + lp.height = LayoutParams.MATCH_PARENT; + mMainView.requestLayout(); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean result; + + final int save = canvas.save(); + if (mSlideableView != null && mSlideableView != child) { // if main view + // Clip against the slider; no sense drawing what will immediately be covered, + // Unless the panel is set to overlay content + canvas.getClipBounds(mTmpRect); + if (!mOverlayContent) { + if (mIsSlidingUp) { + mTmpRect.bottom = Math.min(mTmpRect.bottom, mSlideableView.getTop()); + } else { + mTmpRect.top = Math.max(mTmpRect.top, mSlideableView.getBottom()); + } + } + if (mClipPanel) { + canvas.clipRect(mTmpRect); + } + + result = super.drawChild(canvas, child, drawingTime); + + if (mCoveredFadeColor != 0 && mSlideOffset > 0) { + final int baseAlpha = (mCoveredFadeColor & 0xff000000) >>> 24; + final int imag = (int) (baseAlpha * mSlideOffset); + final int color = imag << 24 | (mCoveredFadeColor & 0xffffff); + mCoveredFadePaint.setColor(color); + canvas.drawRect(mTmpRect, mCoveredFadePaint); + } + } else { + result = super.drawChild(canvas, child, drawingTime); + } + + canvas.restoreToCount(save); + + return result; + } + + /** + * Smoothly animate mDraggingPane to the target X position within its range. + * + * @param slideOffset position to animate to + * @param velocity initial velocity in case of fling, or 0. + */ + boolean smoothSlideTo(float slideOffset, int velocity) { + if (!isEnabled() || mSlideableView == null) { + // Nothing to do. + return false; + } + + int panelTop = computePanelTopPosition(slideOffset); + + if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop)) { + setAllChildrenVisible(); + ViewCompat.postInvalidateOnAnimation(this); + return true; + } + return false; + } + + @Override + public void computeScroll() { + if (mDragHelper != null && mDragHelper.continueSettling(true)) { + if (!isEnabled()) { + mDragHelper.abort(); + return; + } + + ViewCompat.postInvalidateOnAnimation(this); + } + } + + @Override + public void draw(Canvas c) { + super.draw(c); + + // draw the shadow + if (mShadowDrawable != null && mSlideableView != null) { + final int right = mSlideableView.getRight(); + final int top; + final int bottom; + if (mIsSlidingUp) { + top = mSlideableView.getTop() - mShadowHeight; + bottom = mSlideableView.getTop(); + } else { + top = mSlideableView.getBottom(); + bottom = mSlideableView.getBottom() + mShadowHeight; + } + final int left = mSlideableView.getLeft(); + mShadowDrawable.setBounds(left, top, right, bottom); + mShadowDrawable.draw(c); + } + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dx Delta scrolled in pixels + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + final View child = group.getChildAt(i); + if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + canScroll(child, true, dx, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + return checkV && ViewCompat.canScrollHorizontally(v, -dx); + } + + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof MarginLayoutParams + ? new LayoutParams((MarginLayoutParams) p) + : new LayoutParams(p); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("superState", super.onSaveInstanceState()); + bundle.putSerializable(SLIDING_STATE, mSlideState != PanelState.DRAGGING ? mSlideState : mLastNotDraggingSlideState); + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mSlideState = (PanelState) bundle.getSerializable(SLIDING_STATE); + mSlideState = mSlideState == null ? DEFAULT_SLIDE_STATE : mSlideState; + state = bundle.getParcelable("superState"); + } + super.onRestoreInstanceState(state); + } + + private class DragHelperCallback extends ViewDragHelper.Callback { + + @Override + public boolean tryCaptureView(View child, int pointerId) { + return !mIsUnableToDrag && child == mSlideableView; + + } + + @Override + public void onViewDragStateChanged(int state) { + if (mDragHelper != null && mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) { + mSlideOffset = computeSlideOffset(mSlideableView.getTop()); + applyParallaxForCurrentSlideOffset(); + + if (mSlideOffset == 1) { + updateObscuredViewVisibility(); + setPanelStateInternal(PanelState.EXPANDED); + } else if (mSlideOffset == 0) { + setPanelStateInternal(PanelState.COLLAPSED); + } else if (mSlideOffset < 0) { + setPanelStateInternal(PanelState.HIDDEN); + mSlideableView.setVisibility(View.INVISIBLE); + } else { + updateObscuredViewVisibility(); + setPanelStateInternal(PanelState.ANCHORED); + } + } + } + + @Override + public void onViewCaptured(View capturedChild, int activePointerId) { + setAllChildrenVisible(); + } + + @Override + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { + onPanelDragged(top); + invalidate(); + } + + @Override + public void onViewReleased(View releasedChild, float xvel, float yvel) { + int target = 0; + + // direction is always positive if we are sliding in the expanded direction + float direction = mIsSlidingUp ? -yvel : yvel; + + if (direction > 0 && mSlideOffset <= mAnchorPoint) { + // swipe up -> expand and stop at anchor point + target = computePanelTopPosition(mAnchorPoint); + } else if (direction > 0 && mSlideOffset > mAnchorPoint) { + // swipe up past anchor -> expand + target = computePanelTopPosition(1.0f); + } else if (direction < 0 && mSlideOffset >= mAnchorPoint) { + // swipe down -> collapse and stop at anchor point + target = computePanelTopPosition(mAnchorPoint); + } else if (direction < 0 && mSlideOffset < mAnchorPoint) { + // swipe down past anchor -> collapse + target = computePanelTopPosition(0.0f); + } else if (mSlideOffset >= (1.f + mAnchorPoint) / 2) { + // zero velocity, and far enough from anchor point => expand to the top + target = computePanelTopPosition(1.0f); + } else if (mSlideOffset >= mAnchorPoint / 2) { + // zero velocity, and close enough to anchor point => go to anchor + target = computePanelTopPosition(mAnchorPoint); + } else { + // settle at the bottom + target = computePanelTopPosition(0.0f); + } + + if (mDragHelper != null) { + mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target); + } + invalidate(); + } + + @Override + public int getViewVerticalDragRange(View child) { + return mSlideRange; + } + + @Override + public int clampViewPositionVertical(View child, int top, int dy) { + final int collapsedTop = computePanelTopPosition(0.f); + final int expandedTop = computePanelTopPosition(1.0f); + if (mIsSlidingUp) { + return Math.min(Math.max(top, expandedTop), collapsedTop); + } else { + return Math.min(Math.max(top, collapsedTop), expandedTop); + } + } + } + + public static class LayoutParams extends MarginLayoutParams { + private static final int[] ATTRS = new int[]{ + android.R.attr.layout_weight + }; + + public float weight = 0; + + public LayoutParams() { + super(MATCH_PARENT, MATCH_PARENT); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(int width, int height, float weight) { + super(width, height); + this.weight = weight; + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(MarginLayoutParams source) { + super(source); + } + + public LayoutParams(LayoutParams source) { + super(source); + } + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + + final TypedArray ta = c.obtainStyledAttributes(attrs, ATTRS); + if (ta != null) { + this.weight = ta.getFloat(0, 0); + ta.recycle(); + } + + + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ViewDragHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ViewDragHelper.java new file mode 100644 index 0000000..0e20ade --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/slidinguplayout/ViewDragHelper.java @@ -0,0 +1,1488 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.slidinguplayout; + +import android.content.Context; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.VelocityTrackerCompat; +import android.support.v4.view.ViewCompat; +import android.support.v4.widget.ScrollerCompat; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.animation.Interpolator; + +import java.util.Arrays; + +/** + * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number + * of useful operations and state tracking for allowing a user to drag and reposition + * views within their parent ViewGroup. + */ +public class ViewDragHelper { + private static final String TAG = "ViewDragHelper"; + + /** + * A null/invalid pointer ID. + */ + public static final int INVALID_POINTER = -1; + + /** + * A view is not currently being dragged or animating as a result of a fling/snap. + */ + public static final int STATE_IDLE = 0; + + /** + * A view is currently being dragged. The position is currently changing as a result + * of user input or simulated user input. + */ + public static final int STATE_DRAGGING = 1; + + /** + * A view is currently settling into place as a result of a fling or + * predefined non-interactive motion. + */ + public static final int STATE_SETTLING = 2; + + /** + * Edge flag indicating that the left edge should be affected. + */ + public static final int EDGE_LEFT = 1 << 0; + + /** + * Edge flag indicating that the right edge should be affected. + */ + public static final int EDGE_RIGHT = 1 << 1; + + /** + * Edge flag indicating that the top edge should be affected. + */ + public static final int EDGE_TOP = 1 << 2; + + /** + * Edge flag indicating that the bottom edge should be affected. + */ + public static final int EDGE_BOTTOM = 1 << 3; + + /** + * Edge flag set indicating all edges should be affected. + */ + public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM; + + /** + * Indicates that a check should occur along the horizontal axis + */ + public static final int DIRECTION_HORIZONTAL = 1 << 0; + + /** + * Indicates that a check should occur along the vertical axis + */ + public static final int DIRECTION_VERTICAL = 1 << 1; + + /** + * Indicates that a check should occur along all axes + */ + public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + + private static final int EDGE_SIZE = 20; // dp + + private static final int BASE_SETTLE_DURATION = 256; // ms + private static final int MAX_SETTLE_DURATION = 600; // ms + + // Current drag state; idle, dragging or settling + private int mDragState; + + // Distance to travel before a drag may begin + private int mTouchSlop; + + // Last known position/pointer tracking + private int mActivePointerId = INVALID_POINTER; + private float[] mInitialMotionX; + private float[] mInitialMotionY; + private float[] mLastMotionX; + private float[] mLastMotionY; + private int[] mInitialEdgesTouched; + private int[] mEdgeDragsInProgress; + private int[] mEdgeDragsLocked; + private int mPointersDown; + + private VelocityTracker mVelocityTracker; + private float mMaxVelocity; + private float mMinVelocity; + + private int mEdgeSize; + private int mTrackingEdges; + + private ScrollerCompat mScroller; + + private final Callback mCallback; + + private View mCapturedView; + private boolean mReleaseInProgress; + + private final ViewGroup mParentView; + + /** + * A Callback is used as a communication channel with the ViewDragHelper back to the + * parent view using it. on*methods are invoked on siginficant events and several + * accessor methods are expected to provide the ViewDragHelper with more information + * about the state of the parent view upon request. The callback also makes decisions + * governing the range and draggability of child views. + */ + public static abstract class Callback { + /** + * Called when the drag state changes. See the STATE_* constants + * for more information. + * + * @param state The new drag state + * + * @see #STATE_IDLE + * @see #STATE_DRAGGING + * @see #STATE_SETTLING + */ + public void onViewDragStateChanged(int state) {} + + /** + * Called when the captured view's position changes as the result of a drag or settle. + * + * @param changedView View whose position changed + * @param left New X coordinate of the left edge of the view + * @param top New Y coordinate of the top edge of the view + * @param dx Change in X position from the last call + * @param dy Change in Y position from the last call + */ + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} + + /** + * Called when a child view is captured for dragging or settling. The ID of the pointer + * currently dragging the captured view is supplied. If activePointerId is + * identified as {@link #INVALID_POINTER} the capture is programmatic instead of + * pointer-initiated. + * + * @param capturedChild Child view that was captured + * @param activePointerId Pointer id tracking the child capture + */ + public void onViewCaptured(View capturedChild, int activePointerId) {} + + /** + * Called when the child view is no longer being actively dragged. + * The fling velocity is also supplied, if relevant. The velocity values may + * be clamped to system minimums or maximums. + * + *

    Calling code may decide to fling or otherwise release the view to let it + * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)} + * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes + * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING} + * and the view capture will not fully end until it comes to a complete stop. + * If neither of these methods is invoked before onViewReleased returns, + * the view will stop in place and the ViewDragHelper will return to + * {@link #STATE_IDLE}.

    + * + * @param releasedChild The captured child view now being released + * @param xvel X velocity of the pointer as it left the screen in pixels per second. + * @param yvel Y velocity of the pointer as it left the screen in pixels per second. + */ + public void onViewReleased(View releasedChild, float xvel, float yvel) {} + + /** + * Called when one of the subscribed edges in the parent view has been touched + * by the user while no child view is currently captured. + * + * @param edgeFlags A combination of edge flags describing the edge(s) currently touched + * @param pointerId ID of the pointer touching the described edge(s) + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void onEdgeTouched(int edgeFlags, int pointerId) {} + + /** + * Called when the given edge may become locked. This can happen if an edge drag + * was preliminarily rejected before beginning, but after {@link #onEdgeTouched(int, int)} + * was called. This method should return true to lock this edge or false to leave it + * unlocked. The default behavior is to leave edges unlocked. + * + * @param edgeFlags A combination of edge flags describing the edge(s) locked + * @return true to lock the edge, false to leave it unlocked + */ + public boolean onEdgeLock(int edgeFlags) { + return false; + } + + /** + * Called when the user has started a deliberate drag away from one + * of the subscribed edges in the parent view while no child view is currently captured. + * + * @param edgeFlags A combination of edge flags describing the edge(s) dragged + * @param pointerId ID of the pointer touching the described edge(s) + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void onEdgeDragStarted(int edgeFlags, int pointerId) {} + + /** + * Called to determine the Z-order of child views. + * + * @param index the ordered position to query for + * @return index of the view that should be ordered at position index + */ + public int getOrderedChildIndex(int index) { + return index; + } + + /** + * Return the magnitude of a draggable child view's horizontal range of motion in pixels. + * This method should return 0 for views that cannot move horizontally. + * + * @param child Child view to check + * @return range of horizontal motion in pixels + */ + public int getViewHorizontalDragRange(View child) { + return 0; + } + + /** + * Return the magnitude of a draggable child view's vertical range of motion in pixels. + * This method should return 0 for views that cannot move vertically. + * + * @param child Child view to check + * @return range of vertical motion in pixels + */ + public int getViewVerticalDragRange(View child) { + return 0; + } + + /** + * Called when the user's input indicates that they want to capture the given child view + * with the pointer indicated by pointerId. The callback should return true if the user + * is permitted to drag the given view with the indicated pointer. + * + *

    ViewDragHelper may call this method multiple times for the same view even if + * the view is already captured; this indicates that a new pointer is trying to take + * control of the view.

    + * + *

    If this method returns true, a call to {@link #onViewCaptured(View, int)} + * will follow if the capture is successful.

    + * + * @param child Child the user is attempting to capture + * @param pointerId ID of the pointer attempting the capture + * @return true if capture should be allowed, false otherwise + */ + public abstract boolean tryCaptureView(View child, int pointerId); + + /** + * Restrict the motion of the dragged child view along the horizontal axis. + * The default implementation does not allow horizontal motion; the extending + * class must override this method and provide the desired clamping. + * + * + * @param child Child view being dragged + * @param left Attempted motion along the X axis + * @param dx Proposed change in position for left + * @return The new clamped position for left + */ + public int clampViewPositionHorizontal(View child, int left, int dx) { + return 0; + } + + /** + * Restrict the motion of the dragged child view along the vertical axis. + * The default implementation does not allow vertical motion; the extending + * class must override this method and provide the desired clamping. + * + * + * @param child Child view being dragged + * @param top Attempted motion along the Y axis + * @param dy Proposed change in position for top + * @return The new clamped position for top + */ + public int clampViewPositionVertical(View child, int top, int dy) { + return 0; + } + } + + /** + * Interpolator defining the animation curve for mScroller + */ + private static final Interpolator sInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + private final Runnable mSetIdleRunnable = new Runnable() { + public void run() { + setDragState(STATE_IDLE); + } + }; + + /** + * Factory method to create a new ViewDragHelper. + * + * @param forParent Parent view to monitor + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, Callback cb) { + return new ViewDragHelper(forParent.getContext(), forParent, null, cb); + } + + /** + * Factory method to create a new ViewDragHelper with the specified interpolator. + * + * @param forParent Parent view to monitor + * @param interpolator interpolator for scroller + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, Interpolator interpolator, Callback cb) { + return new ViewDragHelper(forParent.getContext(), forParent, interpolator, cb); + } + + /** + * Factory method to create a new ViewDragHelper. + * + * @param forParent Parent view to monitor + * @param sensitivity Multiplier for how sensitive the helper should be about detecting + * the start of a drag. Larger values are more sensitive. 1.0f is normal. + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) { + final ViewDragHelper helper = create(forParent, cb); + helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity)); + return helper; + } + + /** + * Factory method to create a new ViewDragHelper with the specified interpolator. + * + * @param forParent Parent view to monitor + * @param sensitivity Multiplier for how sensitive the helper should be about detecting + * the start of a drag. Larger values are more sensitive. 1.0f is normal. + * @param interpolator interpolator for scroller + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Interpolator interpolator, Callback cb) { + final ViewDragHelper helper = create(forParent, interpolator, cb); + helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity)); + return helper; + } + + /** + * Apps should use ViewDragHelper.create() to get a new instance. + * This will allow VDH to use internal compatibility implementations for different + * platform versions. + * If the interpolator is null, the default interpolator will be used. + * + * @param context Context to initialize config-dependent params from + * @param forParent Parent view to monitor + * @param interpolator interpolator for scroller + */ + private ViewDragHelper(Context context, ViewGroup forParent, Interpolator interpolator, Callback cb) { + if (forParent == null) { + throw new IllegalArgumentException("Parent view may not be null"); + } + if (cb == null) { + throw new IllegalArgumentException("Callback may not be null"); + } + + mParentView = forParent; + mCallback = cb; + + final ViewConfiguration vc = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + mEdgeSize = (int) (EDGE_SIZE * density + 0.5f); + + mTouchSlop = vc.getScaledTouchSlop(); + mMaxVelocity = vc.getScaledMaximumFlingVelocity(); + mMinVelocity = vc.getScaledMinimumFlingVelocity(); + mScroller = ScrollerCompat.create(context, interpolator != null ? interpolator : sInterpolator); + } + + /** + * Set the minimum velocity that will be detected as having a magnitude greater than zero + * in pixels per second. Callback methods accepting a velocity will be clamped appropriately. + * + * @param minVel Minimum velocity to detect + */ + public void setMinVelocity(float minVel) { + mMinVelocity = minVel; + } + + /** + * Return the currently configured minimum velocity. Any flings with a magnitude less + * than this value in pixels per second. Callback methods accepting a velocity will receive + * zero as a velocity value if the real detected velocity was below this threshold. + * + * @return the minimum velocity that will be detected + */ + public float getMinVelocity() { + return mMinVelocity; + } + + /** + * Retrieve the current drag state of this helper. This will return one of + * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}. + * @return The current drag state + */ + public int getViewDragState() { + return mDragState; + } + + /** + * Enable edge tracking for the selected edges of the parent view. + * The callback's {@link Callback#onEdgeTouched(int, int)} and + * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked + * for edges for which edge tracking has been enabled. + * + * @param edgeFlags Combination of edge flags describing the edges to watch + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void setEdgeTrackingEnabled(int edgeFlags) { + mTrackingEdges = edgeFlags; + } + + /** + * Return the size of an edge. This is the range in pixels along the edges of this view + * that will actively detect edge touches or drags if edge tracking is enabled. + * + * @return The size of an edge in pixels + * @see #setEdgeTrackingEnabled(int) + */ + public int getEdgeSize() { + return mEdgeSize; + } + + /** + * Capture a specific child view for dragging within the parent. The callback will be notified + * but {@link Callback#tryCaptureView(View, int)} will not be asked permission to + * capture this view. + * + * @param childView Child view to capture + * @param activePointerId ID of the pointer that is dragging the captured child view + */ + public void captureChildView(View childView, int activePointerId) { + if (childView.getParent() != mParentView) { + throw new IllegalArgumentException("captureChildView: parameter must be a descendant " + + "of the ViewDragHelper's tracked parent view (" + mParentView + ")"); + } + + mCapturedView = childView; + mActivePointerId = activePointerId; + mCallback.onViewCaptured(childView, activePointerId); + setDragState(STATE_DRAGGING); + } + + /** + * @return The currently captured view, or null if no view has been captured. + */ + public View getCapturedView() { + return mCapturedView; + } + + /** + * @return The ID of the pointer currently dragging the captured view, + * or {@link #INVALID_POINTER}. + */ + public int getActivePointerId() { + return mActivePointerId; + } + + /** + * @return The minimum distance in pixels that the user must travel to initiate a drag + */ + public int getTouchSlop() { + return mTouchSlop; + } + + /** + * The result of a call to this method is equivalent to + * {@link #processTouchEvent(MotionEvent)} receiving an ACTION_CANCEL event. + */ + public void cancel() { + mActivePointerId = INVALID_POINTER; + clearMotionHistory(); + + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + /** + * {@link #cancel()}, but also abort all motion in progress and snap to the end of any + * animation. + */ + public void abort() { + cancel(); + if (mDragState == STATE_SETTLING) { + final int oldX = mScroller.getCurrX(); + final int oldY = mScroller.getCurrY(); + mScroller.abortAnimation(); + final int newX = mScroller.getCurrX(); + final int newY = mScroller.getCurrY(); + mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY); + } + setDragState(STATE_IDLE); + } + + /** + * Animate the view child to the given (left, top) position. + * If this method returns true, the caller should invoke {@link #continueSettling(boolean)} + * on each subsequent frame to continue the motion until it returns false. If this method + * returns false there is no further work to do to complete the movement. + * + *

    This operation does not count as a capture event, though {@link #getCapturedView()} + * will still report the sliding view while the slide is in progress.

    + * + * @param child Child view to capture and animate + * @param finalLeft Final left position of child + * @param finalTop Final top position of child + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) { + mCapturedView = child; + mActivePointerId = INVALID_POINTER; + + return forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0); + } + + /** + * Settle the captured view at the given (left, top) position. + * The appropriate velocity from prior motion will be taken into account. + * If this method returns true, the caller should invoke {@link #continueSettling(boolean)} + * on each subsequent frame to continue the motion until it returns false. If this method + * returns false there is no further work to do to complete the movement. + * + * @param finalLeft Settled left edge position for the captured view + * @param finalTop Settled top edge position for the captured view + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + public boolean settleCapturedViewAt(int finalLeft, int finalTop) { + if (!mReleaseInProgress) { + throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " + + "Callback#onViewReleased"); + } + + return forceSettleCapturedViewAt(finalLeft, finalTop, + (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), + (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId)); + } + + /** + * Settle the captured view at the given (left, top) position. + * + * @param finalLeft Target left position for the captured view + * @param finalTop Target top position for the captured view + * @param xvel Horizontal velocity + * @param yvel Vertical velocity + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) { + final int startLeft = mCapturedView.getLeft(); + final int startTop = mCapturedView.getTop(); + final int dx = finalLeft - startLeft; + final int dy = finalTop - startTop; + + if (dx == 0 && dy == 0) { + // Nothing to do. Send callbacks, be done. + mScroller.abortAnimation(); + setDragState(STATE_IDLE); + return false; + } + + final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel); + mScroller.startScroll(startLeft, startTop, dx, dy, duration); + + setDragState(STATE_SETTLING); + return true; + } + + private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) { + xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity); + yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity); + final int absDx = Math.abs(dx); + final int absDy = Math.abs(dy); + final int absXVel = Math.abs(xvel); + final int absYVel = Math.abs(yvel); + final int addedVel = absXVel + absYVel; + final int addedDistance = absDx + absDy; + + final float xweight = xvel != 0 ? (float) absXVel / addedVel : + (float) absDx / addedDistance; + final float yweight = yvel != 0 ? (float) absYVel / addedVel : + (float) absDy / addedDistance; + + int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child)); + int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child)); + + return (int) (xduration * xweight + yduration * yweight); + } + + private int computeAxisDuration(int delta, int velocity, int motionRange) { + if (delta == 0) { + return 0; + } + + final int width = mParentView.getWidth(); + final int halfWidth = width / 2; + final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width); + final float distance = halfWidth + halfWidth * + distanceInfluenceForSnapDuration(distanceRatio); + + int duration; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + if(motionRange == 0){ + return 0; + } + final float range = (float) Math.abs(delta) / motionRange; + duration = (int) ((range + 1) * BASE_SETTLE_DURATION); + } + return Math.min(duration, MAX_SETTLE_DURATION); + } + + /** + * Clamp the magnitude of value for absMin and absMax. + * If the value is below the minimum, it will be clamped to zero. + * If the value is above the maximum, it will be clamped to the maximum. + * + * @param value Value to clamp + * @param absMin Absolute value of the minimum significant value to return + * @param absMax Absolute value of the maximum value to return + * @return The clamped value with the same sign as value + */ + private int clampMag(int value, int absMin, int absMax) { + final int absValue = Math.abs(value); + if (absValue < absMin) return 0; + if (absValue > absMax) return value > 0 ? absMax : -absMax; + return value; + } + + /** + * Clamp the magnitude of value for absMin and absMax. + * If the value is below the minimum, it will be clamped to zero. + * If the value is above the maximum, it will be clamped to the maximum. + * + * @param value Value to clamp + * @param absMin Absolute value of the minimum significant value to return + * @param absMax Absolute value of the maximum value to return + * @return The clamped value with the same sign as value + */ + private float clampMag(float value, float absMin, float absMax) { + final float absValue = Math.abs(value); + if (absValue < absMin) return 0; + if (absValue > absMax) return value > 0 ? absMax : -absMax; + return value; + } + + private float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + /** + * Settle the captured view based on standard free-moving fling behavior. + * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame + * to continue the motion until it returns false. + * + * @param minLeft Minimum X position for the view's left edge + * @param minTop Minimum Y position for the view's top edge + * @param maxLeft Maximum X position for the view's left edge + * @param maxTop Maximum Y position for the view's top edge + */ + public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) { + if (!mReleaseInProgress) { + throw new IllegalStateException("Cannot flingCapturedView outside of a call to " + + "Callback#onViewReleased"); + } + + mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(), + (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), + (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId), + minLeft, maxLeft, minTop, maxTop); + + setDragState(STATE_SETTLING); + } + + /** + * Move the captured settling view by the appropriate amount for the current time. + * If continueSettling returns true, the caller should call it again + * on the next frame to continue. + * + * @param deferCallbacks true if state callbacks should be deferred via posted message. + * Set this to true if you are calling this method from + * {@link View#computeScroll()} or similar methods + * invoked as part of layout or drawing. + * @return true if settle is still in progress + */ + public boolean continueSettling(boolean deferCallbacks) { + // Make sure, there is a captured view + if (mCapturedView == null) { + return false; + } + if (mDragState == STATE_SETTLING) { + boolean keepGoing = mScroller.computeScrollOffset(); + final int x = mScroller.getCurrX(); + final int y = mScroller.getCurrY(); + final int dx = x - mCapturedView.getLeft(); + final int dy = y - mCapturedView.getTop(); + + if(!keepGoing && dy != 0) { //fix #525 + //Invalid drag state + mCapturedView.setTop(0); + return true; + } + + if (dx != 0) { + mCapturedView.offsetLeftAndRight(dx); + } + if (dy != 0) { + mCapturedView.offsetTopAndBottom(dy); + } + + if (dx != 0 || dy != 0) { + mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy); + } + + if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) { + // Close enough. The interpolator/scroller might think we're still moving + // but the user sure doesn't. + mScroller.abortAnimation(); + keepGoing = mScroller.isFinished(); + } + + if (!keepGoing) { + if (deferCallbacks) { + mParentView.post(mSetIdleRunnable); + } else { + setDragState(STATE_IDLE); + } + } + } + + return mDragState == STATE_SETTLING; + } + + /** + * Like all callback events this must happen on the UI thread, but release + * involves some extra semantics. During a release (mReleaseInProgress) + * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)} + * or {@link #flingCapturedView(int, int, int, int)}. + */ + private void dispatchViewReleased(float xvel, float yvel) { + mReleaseInProgress = true; + mCallback.onViewReleased(mCapturedView, xvel, yvel); + mReleaseInProgress = false; + + if (mDragState == STATE_DRAGGING) { + // onViewReleased didn't call a method that would have changed this. Go idle. + setDragState(STATE_IDLE); + } + } + + private void clearMotionHistory() { + if (mInitialMotionX == null) { + return; + } + Arrays.fill(mInitialMotionX, 0); + Arrays.fill(mInitialMotionY, 0); + Arrays.fill(mLastMotionX, 0); + Arrays.fill(mLastMotionY, 0); + Arrays.fill(mInitialEdgesTouched, 0); + Arrays.fill(mEdgeDragsInProgress, 0); + Arrays.fill(mEdgeDragsLocked, 0); + mPointersDown = 0; + } + + private void clearMotionHistory(int pointerId) { + if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) { + return; + } + mInitialMotionX[pointerId] = 0; + mInitialMotionY[pointerId] = 0; + mLastMotionX[pointerId] = 0; + mLastMotionY[pointerId] = 0; + mInitialEdgesTouched[pointerId] = 0; + mEdgeDragsInProgress[pointerId] = 0; + mEdgeDragsLocked[pointerId] = 0; + mPointersDown &= ~(1 << pointerId); + } + + private void ensureMotionHistorySizeForId(int pointerId) { + if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) { + float[] imx = new float[pointerId + 1]; + float[] imy = new float[pointerId + 1]; + float[] lmx = new float[pointerId + 1]; + float[] lmy = new float[pointerId + 1]; + int[] iit = new int[pointerId + 1]; + int[] edip = new int[pointerId + 1]; + int[] edl = new int[pointerId + 1]; + + if (mInitialMotionX != null) { + System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length); + System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length); + System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length); + System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length); + System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length); + System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length); + System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length); + } + + mInitialMotionX = imx; + mInitialMotionY = imy; + mLastMotionX = lmx; + mLastMotionY = lmy; + mInitialEdgesTouched = iit; + mEdgeDragsInProgress = edip; + mEdgeDragsLocked = edl; + } + } + + private void saveInitialMotion(float x, float y, int pointerId) { + ensureMotionHistorySizeForId(pointerId); + mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x; + mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y; + mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y); + mPointersDown |= 1 << pointerId; + } + + private void saveLastMotion(MotionEvent ev) { + final int pointerCount = MotionEventCompat.getPointerCount(ev); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = MotionEventCompat.getPointerId(ev, i); + final float x = MotionEventCompat.getX(ev, i); + final float y = MotionEventCompat.getY(ev, i); + // Sometimes we can try and save last motion for a pointer never recorded in initial motion. In this case we just discard it. + if (mLastMotionX != null && mLastMotionY != null + && mLastMotionX.length > pointerId && mLastMotionY.length > pointerId) { + mLastMotionX[pointerId] = x; + mLastMotionY[pointerId] = y; + } + } + } + + /** + * Check if the given pointer ID represents a pointer that is currently down (to the best + * of the ViewDragHelper's knowledge). + * + *

    The state used to report this information is populated by the methods + * {@link #shouldInterceptTouchEvent(MotionEvent)} or + * {@link #processTouchEvent(MotionEvent)}. If one of these methods has not + * been called for all relevant MotionEvents to track, the information reported + * by this method may be stale or incorrect.

    + * + * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent + * @return true if the pointer with the given ID is still down + */ + public boolean isPointerDown(int pointerId) { + return (mPointersDown & 1 << pointerId) != 0; + } + + void setDragState(int state) { + if (mDragState != state) { + mDragState = state; + mCallback.onViewDragStateChanged(state); + if (mDragState == STATE_IDLE) { + mCapturedView = null; + } + } + } + + /** + * Attempt to capture the view with the given pointer ID. The callback will be involved. + * This will put us into the "dragging" state. If we've already captured this view with + * this pointer this method will immediately return true without consulting the callback. + * + * @param toCapture View to capture + * @param pointerId Pointer to capture with + * @return true if capture was successful + */ + boolean tryCaptureViewForDrag(View toCapture, int pointerId) { + if (toCapture == mCapturedView && mActivePointerId == pointerId) { + // Already done! + return true; + } + if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) { + mActivePointerId = pointerId; + captureChildView(toCapture, pointerId); + return true; + } + return false; + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dx Delta scrolled in pixels along the X axis + * @param dy Delta scrolled in pixels along the Y axis + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + // TODO: Add versioned support here for transformed views. + // This will not work for transformed views in Honeycomb+ + final View child = group.getChildAt(i); + if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + canScroll(child, true, dx, dy, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkV && (ViewCompat.canScrollHorizontally(v, -dx) || + ViewCompat.canScrollVertically(v, -dy)); + } + + /** + * Check if this event as provided to the parent view's onInterceptTouchEvent should + * cause the parent to intercept the touch event stream. + * + * @param ev MotionEvent provided to onInterceptTouchEvent + * @return true if the parent view should return true from onInterceptTouchEvent + */ + public boolean shouldInterceptTouchEvent(MotionEvent ev) { + final int action = MotionEventCompat.getActionMasked(ev); + final int actionIndex = MotionEventCompat.getActionIndex(ev); + + if (action == MotionEvent.ACTION_DOWN) { + // Reset things for a new event stream, just in case we didn't get + // the whole previous stream. + cancel(); + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + final int pointerId = MotionEventCompat.getPointerId(ev, 0); + saveInitialMotion(x, y, pointerId); + + final View toCapture = findTopChildUnder((int) x, (int) y); + + // Catch a settling view if possible. + if (toCapture == mCapturedView && mDragState == STATE_SETTLING) { + tryCaptureViewForDrag(toCapture, pointerId); + } + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + break; + } + + case MotionEventCompat.ACTION_POINTER_DOWN: { + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + final float x = MotionEventCompat.getX(ev, actionIndex); + final float y = MotionEventCompat.getY(ev, actionIndex); + + saveInitialMotion(x, y, pointerId); + + // A ViewDragHelper can only manipulate one view at a time. + if (mDragState == STATE_IDLE) { + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + } else if (mDragState == STATE_SETTLING) { + // Catch a settling view if possible. + final View toCapture = findTopChildUnder((int) x, (int) y); + if (toCapture == mCapturedView) { + tryCaptureViewForDrag(toCapture, pointerId); + } + } + break; + } + + case MotionEvent.ACTION_MOVE: { + // First to cross a touch slop over a draggable view wins. Also report edge drags. + final int pointerCount = MotionEventCompat.getPointerCount(ev); + for (int i = 0; i < pointerCount && mInitialMotionX != null && mInitialMotionY != null; i++) { + final int pointerId = MotionEventCompat.getPointerId(ev, i); + if (pointerId >= mInitialMotionX.length || pointerId >= mInitialMotionY.length) { + continue; + } + final float x = MotionEventCompat.getX(ev, i); + final float y = MotionEventCompat.getY(ev, i); + final float dx = x - mInitialMotionX[pointerId]; + final float dy = y - mInitialMotionY[pointerId]; + + reportNewEdgeDrags(dx, dy, pointerId); + if (mDragState == STATE_DRAGGING) { + // Callback might have started an edge drag + break; + } + + final View toCapture = findTopChildUnder((int)mInitialMotionX[pointerId], (int)mInitialMotionY[pointerId]); + if (toCapture != null && checkTouchSlop(toCapture, dx, dy) && + tryCaptureViewForDrag(toCapture, pointerId)) { + break; + } + } + saveLastMotion(ev); + break; + } + + case MotionEventCompat.ACTION_POINTER_UP: { + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + clearMotionHistory(pointerId); + break; + } + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + cancel(); + break; + } + } + + return mDragState == STATE_DRAGGING; + } + + /** + * Process a touch event received by the parent view. This method will dispatch callback events + * as needed before returning. The parent view's onTouchEvent implementation should call this. + * + * @param ev The touch event received by the parent view + */ + public void processTouchEvent(MotionEvent ev) { + final int action = MotionEventCompat.getActionMasked(ev); + final int actionIndex = MotionEventCompat.getActionIndex(ev); + + if (action == MotionEvent.ACTION_DOWN) { + // Reset things for a new event stream, just in case we didn't get + // the whole previous stream. + cancel(); + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + final int pointerId = MotionEventCompat.getPointerId(ev, 0); + final View toCapture = findTopChildUnder((int) x, (int) y); + + saveInitialMotion(x, y, pointerId); + + // Since the parent is already directly processing this touch event, + // there is no reason to delay for a slop before dragging. + // Start immediately if possible. + tryCaptureViewForDrag(toCapture, pointerId); + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + break; + } + + case MotionEventCompat.ACTION_POINTER_DOWN: { + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + final float x = MotionEventCompat.getX(ev, actionIndex); + final float y = MotionEventCompat.getY(ev, actionIndex); + + saveInitialMotion(x, y, pointerId); + + // A ViewDragHelper can only manipulate one view at a time. + if (mDragState == STATE_IDLE) { + // If we're idle we can do anything! Treat it like a normal down event. + + final View toCapture = findTopChildUnder((int) x, (int) y); + tryCaptureViewForDrag(toCapture, pointerId); + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + } else if (isCapturedViewUnder((int) x, (int) y)) { + // We're still tracking a captured view. If the same view is under this + // point, we'll swap to controlling it with this pointer instead. + // (This will still work if we're "catching" a settling view.) + + tryCaptureViewForDrag(mCapturedView, pointerId); + } + break; + } + + case MotionEvent.ACTION_MOVE: { + if (mDragState == STATE_DRAGGING) { + final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); + final float x = MotionEventCompat.getX(ev, index); + final float y = MotionEventCompat.getY(ev, index); + final int idx = (int) (x - mLastMotionX[mActivePointerId]); + final int idy = (int) (y - mLastMotionY[mActivePointerId]); + + dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy); + + saveLastMotion(ev); + } else { + // Check to see if any pointer is now over a draggable view. + final int pointerCount = MotionEventCompat.getPointerCount(ev); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = MotionEventCompat.getPointerId(ev, i) + ; + final float x = MotionEventCompat.getX(ev, i); + final float y = MotionEventCompat.getY(ev, i); + final float dx = x - mInitialMotionX[pointerId]; + final float dy = y - mInitialMotionY[pointerId]; + + reportNewEdgeDrags(dx, dy, pointerId); + if (mDragState == STATE_DRAGGING) { + // Callback might have started an edge drag. + break; + } + + final View toCapture = findTopChildUnder((int) mInitialMotionX[pointerId], (int) mInitialMotionY[pointerId]); + if (checkTouchSlop(toCapture, dx, dy) && + tryCaptureViewForDrag(toCapture, pointerId)) { + break; + } + } + saveLastMotion(ev); + } + break; + } + + case MotionEventCompat.ACTION_POINTER_UP: { + final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) { + // Try to find another pointer that's still holding on to the captured view. + int newActivePointer = INVALID_POINTER; + final int pointerCount = MotionEventCompat.getPointerCount(ev); + for (int i = 0; i < pointerCount; i++) { + final int id = MotionEventCompat.getPointerId(ev, i); + if (id == mActivePointerId) { + // This one's going away, skip. + continue; + } + + final float x = MotionEventCompat.getX(ev, i); + final float y = MotionEventCompat.getY(ev, i); + if (findTopChildUnder((int) x, (int) y) == mCapturedView && + tryCaptureViewForDrag(mCapturedView, id)) { + newActivePointer = mActivePointerId; + break; + } + } + + if (newActivePointer == INVALID_POINTER) { + // We didn't find another pointer still touching the view, release it. + releaseViewForPointerUp(); + } + } + clearMotionHistory(pointerId); + break; + } + + case MotionEvent.ACTION_UP: { + if (mDragState == STATE_DRAGGING) { + releaseViewForPointerUp(); + } + cancel(); + break; + } + + case MotionEvent.ACTION_CANCEL: { + if (mDragState == STATE_DRAGGING) { + dispatchViewReleased(0, 0); + } + cancel(); + break; + } + } + } + + private void reportNewEdgeDrags(float dx, float dy, int pointerId) { + int dragsStarted = 0; + if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) { + dragsStarted |= EDGE_LEFT; + } + if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) { + dragsStarted |= EDGE_TOP; + } + if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) { + dragsStarted |= EDGE_RIGHT; + } + if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) { + dragsStarted |= EDGE_BOTTOM; + } + + if (dragsStarted != 0) { + mEdgeDragsInProgress[pointerId] |= dragsStarted; + mCallback.onEdgeDragStarted(dragsStarted, pointerId); + } + } + + private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) { + final float absDelta = Math.abs(delta); + final float absODelta = Math.abs(odelta); + + if ((mInitialEdgesTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0 || + (mEdgeDragsLocked[pointerId] & edge) == edge || + (mEdgeDragsInProgress[pointerId] & edge) == edge || + (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) { + return false; + } + if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) { + mEdgeDragsLocked[pointerId] |= edge; + return false; + } + return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop; + } + + /** + * Check if we've crossed a reasonable touch slop for the given child view. + * If the child cannot be dragged along the horizontal or vertical axis, motion + * along that axis will not count toward the slop check. + * + * @param child Child to check + * @param dx Motion since initial position along X axis + * @param dy Motion since initial position along Y axis + * @return true if the touch slop has been crossed + */ + private boolean checkTouchSlop(View child, float dx, float dy) { + if (child == null) { + return false; + } + final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0; + final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0; + + if (checkHorizontal && checkVertical) { + return dx * dx + dy * dy > mTouchSlop * mTouchSlop; + } else if (checkHorizontal) { + return Math.abs(dx) > mTouchSlop; + } else if (checkVertical) { + return Math.abs(dy) > mTouchSlop; + } + return false; + } + + /** + * Check if any pointer tracked in the current gesture has crossed + * the required slop threshold. + * + *

    This depends on internal state populated by + * {@link #shouldInterceptTouchEvent(MotionEvent)} or + * {@link #processTouchEvent(MotionEvent)}. You should only rely on + * the results of this method after all currently available touch data + * has been provided to one of these two methods.

    + * + * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, + * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} + * @return true if the slop threshold has been crossed, false otherwise + */ + public boolean checkTouchSlop(int directions) { + final int count = mInitialMotionX.length; + for (int i = 0; i < count; i++) { + if (checkTouchSlop(directions, i)) { + return true; + } + } + return false; + } + + /** + * Check if the specified pointer tracked in the current gesture has crossed + * the required slop threshold. + * + *

    This depends on internal state populated by + * {@link #shouldInterceptTouchEvent(MotionEvent)} or + * {@link #processTouchEvent(MotionEvent)}. You should only rely on + * the results of this method after all currently available touch data + * has been provided to one of these two methods.

    + * + * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, + * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} + * @param pointerId ID of the pointer to slop check as specified by MotionEvent + * @return true if the slop threshold has been crossed, false otherwise + */ + public boolean checkTouchSlop(int directions, int pointerId) { + if (!isPointerDown(pointerId)) { + return false; + } + + final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL; + final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL; + + final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId]; + final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId]; + + if (checkHorizontal && checkVertical) { + return dx * dx + dy * dy > mTouchSlop * mTouchSlop; + } else if (checkHorizontal) { + return Math.abs(dx) > mTouchSlop; + } else if (checkVertical) { + return Math.abs(dy) > mTouchSlop; + } + return false; + } + + /** + * Check if any of the edges specified were initially touched in the currently active gesture. + * If there is no currently active gesture this method will return false. + * + * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, + * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and + * {@link #EDGE_ALL} + * @return true if any of the edges specified were initially touched in the current gesture + */ + public boolean isEdgeTouched(int edges) { + final int count = mInitialEdgesTouched.length; + for (int i = 0; i < count; i++) { + if (isEdgeTouched(edges, i)) { + return true; + } + } + return false; + } + + /** + * Check if any of the edges specified were initially touched by the pointer with + * the specified ID. If there is no currently active gesture or if there is no pointer with + * the given ID currently down this method will return false. + * + * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, + * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and + * {@link #EDGE_ALL} + * @return true if any of the edges specified were initially touched in the current gesture + */ + public boolean isEdgeTouched(int edges, int pointerId) { + return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0; + } + + public boolean isDragging() { + return mDragState == STATE_DRAGGING; + } + + private void releaseViewForPointerUp() { + mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); + final float xvel = clampMag( + VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), + mMinVelocity, mMaxVelocity); + final float yvel = clampMag( + VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId), + mMinVelocity, mMaxVelocity); + dispatchViewReleased(xvel, yvel); + } + + private void dragTo(int left, int top, int dx, int dy) { + int clampedX = left; + int clampedY = top; + final int oldLeft = mCapturedView.getLeft(); + final int oldTop = mCapturedView.getTop(); + if (dx != 0) { + clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx); + mCapturedView.offsetLeftAndRight(clampedX - oldLeft); + } + if (dy != 0) { + clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy); + mCapturedView.offsetTopAndBottom(clampedY - oldTop); + } + + if (dx != 0 || dy != 0) { + final int clampedDx = clampedX - oldLeft; + final int clampedDy = clampedY - oldTop; + mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY, + clampedDx, clampedDy); + } + } + + /** + * Determine if the currently captured view is under the given point in the + * parent view's coordinate system. If there is no captured view this method + * will return false. + * + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return true if the captured view is under the given point, false otherwise + */ + public boolean isCapturedViewUnder(int x, int y) { + return isViewUnder(mCapturedView, x, y); + } + + /** + * Determine if the supplied view is under the given point in the + * parent view's coordinate system. + * + * @param view Child view of the parent to hit test + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return true if the supplied view is under the given point, false otherwise + */ + public boolean isViewUnder(View view, int x, int y) { + if (view == null) { + return false; + } + return x >= view.getLeft() && + x < view.getRight() && + y >= view.getTop() && + y < view.getBottom(); + } + + /** + * Find the topmost child under the given point within the parent view's coordinate system. + * The child order is determined using {@link Callback#getOrderedChildIndex(int)}. + * + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return The topmost child view under (x, y) or null if none found. + */ + public View findTopChildUnder(int x, int y) { + final int childCount = mParentView.getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i)); + if (x >= child.getLeft() && x < child.getRight() && + y >= child.getTop() && y < child.getBottom()) { + return child; + } + } + return null; + } + + private int getEdgesTouched(int x, int y) { + int result = 0; + + if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT; + if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP; + if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT; + if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM; + + return result; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapter.java new file mode 100644 index 0000000..3357a8b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapter.java @@ -0,0 +1,43 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListAdapter; + +/** + * Base adapter interface for StickyGridHeadersGridView. The adapter expects two sets of data, + * items, and headers. Implement this interface to provide an optimised method for generating the + * header data set. Otherwise see {@link StickyGridHeadersSimpleAdapter} for a solution which will + * auto-generate the set of headers. + */ +public interface StickyGridHeadersBaseAdapter extends ListAdapter { + /** + * Get the number of items with a given header. + * + * @return The number of items for the specified header. + */ + public int getCountForHeader(int header); + + /** + * Get the number of headers in the adapter's data set. + * + * @return Number of headers. + */ + public int getNumHeaders(); + + /** + * Get a View that displays the header data at the specified position in the set. You can either + * create a View manually or inflate it from an XML layout file. + * + * @param position + * The position of the header within the adapter's header data set. + * @param convertView + * The old view to reuse, if possible. Note: You should check that this view is + * non-null and of an appropriate type before using. If it is not possible to convert + * this view to display the correct data, this method can create a new view. + * @param parent + * The parent that this view will eventually be attached to. + * @return A View corresponding to the data at the specified position. + */ + View getHeaderView(int position, View convertView, ViewGroup parent); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapterWrapper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapterWrapper.java new file mode 100644 index 0000000..5956b0f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersBaseAdapterWrapper.java @@ -0,0 +1,443 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.content.Context; +import android.database.DataSetObserver; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; + +/** + * Adapter wrapper to insert extra views and otherwise hack around GridView to add sections and + * headers. + */ +public class StickyGridHeadersBaseAdapterWrapper extends BaseAdapter { + private static final int sNumViewTypes = 3; + + protected static final int ID_FILLER = -0x02; + + protected static final int ID_HEADER = -0x01; + + protected static final int ID_HEADER_FILLER = -0x03; + + protected static final int POSITION_FILLER = -0x01; + + protected static final int POSITION_HEADER = -0x02; + + protected static final int POSITION_HEADER_FILLER = -0x03; + + protected static final int VIEW_TYPE_FILLER = 0x00; + + protected static final int VIEW_TYPE_HEADER = 0x01; + + protected static final int VIEW_TYPE_HEADER_FILLER = 0x02; + + private final Context mContext; + + private int mCount; + + private boolean mCounted = false; + + private DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateCount(); + } + + @Override + public void onInvalidated() { + mCounted = false; + } + }; + + private final StickyGridHeadersBaseAdapter mDelegate; + + private StickyGridHeadersGridView mGridView; + + private View mLastHeaderViewSeen; + + private View mLastViewSeen; + + private int mNumColumns = 1; + + public StickyGridHeadersBaseAdapterWrapper(Context context, StickyGridHeadersGridView gridView, + StickyGridHeadersBaseAdapter delegate) { + mContext = context; + mDelegate = delegate; + mGridView = gridView; + delegate.registerDataSetObserver(mDataSetObserver); + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public int getCount() { + if (mCounted) { + return mCount; + } + mCount = 0; + int numHeaders = mDelegate.getNumHeaders(); + if (numHeaders == 0) { + mCount = mDelegate.getCount(); + mCounted = true; + return mCount; + } + + for (int i = 0; i < numHeaders; i++) { + // Pad count with space for header and trailing filler in header + // group. + mCount += mDelegate.getCountForHeader(i) + unFilledSpacesInHeaderGroup(i) + mNumColumns; + } + mCounted = true; + return mCount; + } + + /** + * Get the data item associated with the specified position in the data set. + *

    + * Since this wrapper inserts fake entries to fill out items grouped by header and also spaces + * to insert headers into some positions will return null. + *

    + * + * @param position + * Position of the item whose data we want within the adapter's data set. + * @return The data at the specified position. + */ + @Override + public Object getItem(int position) throws ArrayIndexOutOfBoundsException { + Position adapterPosition = translatePosition(position); + if (adapterPosition.mPosition == POSITION_FILLER || adapterPosition.mPosition == POSITION_HEADER) { + // Fake entry in view. + return null; + } + + return mDelegate.getItem(adapterPosition.mPosition); + } + + @Override + public long getItemId(int position) { + Position adapterPosition = translatePosition(position); + if (adapterPosition.mPosition == POSITION_HEADER) { + return ID_HEADER; + } + if (adapterPosition.mPosition == POSITION_FILLER) { + return ID_FILLER; + } + if (adapterPosition.mPosition == POSITION_HEADER_FILLER) { + return ID_HEADER_FILLER; + } + return mDelegate.getItemId(adapterPosition.mPosition); + } + + @Override + public int getItemViewType(int position) { + Position adapterPosition = translatePosition(position); + if (adapterPosition.mPosition == POSITION_HEADER) { + return VIEW_TYPE_HEADER; + } + if (adapterPosition.mPosition == POSITION_FILLER) { + return VIEW_TYPE_FILLER; + } + if (adapterPosition.mPosition == POSITION_HEADER_FILLER) { + return VIEW_TYPE_HEADER_FILLER; + } + int itemViewType = mDelegate.getItemViewType(adapterPosition.mPosition); + if (itemViewType == IGNORE_ITEM_VIEW_TYPE) { + return itemViewType; + } + return itemViewType + sNumViewTypes; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Position adapterPosition = translatePosition(position); + if (adapterPosition.mPosition == POSITION_HEADER) { + HeaderFillerView v = getHeaderFillerView(adapterPosition.mHeader, convertView, parent); + View view = mDelegate.getHeaderView(adapterPosition.mHeader, (View) v.getTag(), parent); + mGridView.detachHeader((View) v.getTag()); + v.setTag(view); + mGridView.attachHeader(view); + convertView = v; + mLastHeaderViewSeen = v; + v.forceLayout(); + } else if (adapterPosition.mPosition == POSITION_HEADER_FILLER) { + convertView = getFillerView(convertView, parent, mLastHeaderViewSeen); + convertView.forceLayout(); + } else if (adapterPosition.mPosition == POSITION_FILLER) { + convertView = getFillerView(convertView, parent, mLastViewSeen); + } else { + convertView = mDelegate.getView(adapterPosition.mPosition, convertView, parent); + mLastViewSeen = convertView; + } + + return convertView; + } + + @Override + public int getViewTypeCount() { + return mDelegate.getViewTypeCount() + sNumViewTypes; + } + + /** + * @return the adapter wrapped by this adapter. + */ + public StickyGridHeadersBaseAdapter getWrappedAdapter() { + return mDelegate; + } + + @Override + public boolean hasStableIds() { + return mDelegate.hasStableIds(); + } + + @Override + public boolean isEmpty() { + return mDelegate.isEmpty(); + } + + @Override + public boolean isEnabled(int position) { + Position adapterPosition = translatePosition(position); + if (adapterPosition.mPosition == POSITION_FILLER || adapterPosition.mPosition == POSITION_HEADER) { + return false; + } + + return mDelegate.isEnabled(adapterPosition.mPosition); + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + super.registerDataSetObserver(observer); + mDelegate.registerDataSetObserver(observer); + } + + public void setNumColumns(int numColumns) { + mNumColumns = numColumns; + mCounted = false; + // notifyDataSetChanged(); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + super.unregisterDataSetObserver(observer); + mDelegate.unregisterDataSetObserver(observer); + } + + private FillerView getFillerView(View convertView, ViewGroup parent, View lastViewSeen) { + FillerView fillerView = (FillerView) convertView; + if (fillerView == null) { + fillerView = new FillerView(mContext); + } + + fillerView.setMeasureTarget(lastViewSeen); + + return fillerView; + } + + private HeaderFillerView getHeaderFillerView(int headerPosition, View convertView, ViewGroup parent) { + HeaderFillerView headerFillerView = (HeaderFillerView) convertView; + if (headerFillerView == null) { + headerFillerView = new HeaderFillerView(mContext); + } + + return headerFillerView; + } + + /** + * Counts the number of items that would be need to fill out the last row in the group of items + * with the given header. + * + * @param header + * Header set of items are grouped by. + * @return The count of unfilled spaces in the last row. + */ + private int unFilledSpacesInHeaderGroup(int header) { + // If mNumColumns is equal to zero we will have a divide by 0 exception + if (mNumColumns == 0) { + return 0; + } + + int remainder = mDelegate.getCountForHeader(header) % mNumColumns; + return remainder == 0 ? 0 : mNumColumns - remainder; + } + + protected long getHeaderId(int position) { + return translatePosition(position).mHeader; + } + + protected View getHeaderView(int position, View convertView, ViewGroup parent) { + if (mDelegate.getNumHeaders() == 0) { + return null; + } + + return mDelegate.getHeaderView(translatePosition(position).mHeader, convertView, parent); + } + + protected Position translatePosition(int position) { + int numHeaders = mDelegate.getNumHeaders(); + if (numHeaders == 0) { + if (position >= mDelegate.getCount()) { + return new Position(POSITION_FILLER, 0); + } + return new Position(position, 0); + } + + // Translate GridView position to Adapter position. + int adapterPosition = position; + int place = position; + int i; + + for (i = 0; i < numHeaders; i++) { + int sectionCount = mDelegate.getCountForHeader(i); + + // Skip past fake items making space for header in front of + // sections. + if (place == 0) { + // Position is first column where header will be. + return new Position(POSITION_HEADER, i); + } + place -= mNumColumns; + if (place < 0) { + // Position is a fake so return null. + return new Position(POSITION_HEADER_FILLER, i); + } + adapterPosition -= mNumColumns; + + if (place < sectionCount) { + return new Position(adapterPosition, i); + } + + // Skip past section end of section row filler; + int filler = unFilledSpacesInHeaderGroup(i); + adapterPosition -= filler; + place -= sectionCount + filler; + + if (place < 0) { + // Position is a fake so return null. + return new Position(POSITION_FILLER, i); + } + } + + // Position is a fake. + return new Position(POSITION_FILLER, i); + } + + protected void updateCount() { + mCount = 0; + int numHeaders = mDelegate.getNumHeaders(); + if (numHeaders == 0) { + mCount = mDelegate.getCount(); + mCounted = true; + return; + } + + for (int i = 0; i < numHeaders; i++) { + mCount += mDelegate.getCountForHeader(i) + mNumColumns; + } + mCounted = true; + } + + /** + * Simple view to fill space in grid view. + * + */ + protected static class FillerView extends View { + private View mMeasureTarget; + + public FillerView(Context context) { + super(context); + } + + public FillerView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FillerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setMeasureTarget(View lastViewSeen) { + mMeasureTarget = lastViewSeen; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMeasureTarget.getMeasuredHeight(), MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + /** + * A view to hold the section header and measure the header row height correctly. + * + */ + protected class HeaderFillerView extends FrameLayout { + private int mHeaderId; + + public HeaderFillerView(Context context) { + super(context); + } + + public HeaderFillerView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public HeaderFillerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public int getHeaderId() { + return mHeaderId; + } + + /** + * Set the adapter id for this header so we can easily pull it later. + */ + public void setHeaderId(int headerId) { + mHeaderId = headerId; + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + View v = (View) getTag(); + ViewGroup.LayoutParams params = v.getLayoutParams(); + if (params == null) { + params = generateDefaultLayoutParams(); + v.setLayoutParams(params); + } + if (v.getVisibility() != View.GONE) { + int heightSpec = getChildMeasureSpec(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, + params.height); + int widthSpec = getChildMeasureSpec( + MeasureSpec.makeMeasureSpec(mGridView.getWidth(), MeasureSpec.EXACTLY), 0, params.width); + v.measure(widthSpec, heightSpec); + } + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), v.getMeasuredHeight()); + } + } + +// protected static class HeaderHolder { +// protected View mHeaderView; +// } + + protected static class Position { + protected int mHeader; + + protected int mPosition; + + protected Position(int position, int header) { + mPosition = position; + mHeader = header; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersGridView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersGridView.java new file mode 100644 index 0000000..e469f65 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersGridView.java @@ -0,0 +1,1197 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.Build; +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.GridView; +import android.widget.ListAdapter; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * GridView that displays items in sections with headers that stick to the top of the view. + * + */ +public class StickyGridHeadersGridView extends GridView implements OnScrollListener, OnItemClickListener, + OnItemSelectedListener, OnItemLongClickListener { + private static final String ERROR_PLATFORM = "Error supporting platform " + Build.VERSION.SDK_INT + "."; + + private static final int MATCHED_STICKIED_HEADER = -2; + + private static final int NO_MATCHED_HEADER = -1; + + protected static final int TOUCH_MODE_DONE_WAITING = 2; + + protected static final int TOUCH_MODE_DOWN = 0; + + protected static final int TOUCH_MODE_FINISHED_LONG_PRESS = -2; + + protected static final int TOUCH_MODE_REST = -1; + + protected static final int TOUCH_MODE_TAP = 1; + + static final String TAG = StickyGridHeadersGridView.class.getSimpleName(); + + private static MotionEvent.PointerCoords[] getPointerCoords(MotionEvent e) { + int n = e.getPointerCount(); + MotionEvent.PointerCoords[] r = new MotionEvent.PointerCoords[n]; + for (int i = 0; i < n; i++) { + r[i] = new MotionEvent.PointerCoords(); + e.getPointerCoords(i, r[i]); + } + return r; + } + + private static int[] getPointerIds(MotionEvent e) { + int n = e.getPointerCount(); + int[] r = new int[n]; + for (int i = 0; i < n; i++) { + r[i] = e.getPointerId(i); + } + return r; + } + + public CheckForHeaderLongPress mPendingCheckForLongPress; + + public CheckForHeaderTap mPendingCheckForTap; + + private boolean mAreHeadersSticky = true; + + private final Rect mClippingRect = new Rect(); + + private boolean mClippingToPadding; + + private boolean mClipToPaddingHasBeenSet; + + private int mColumnWidth; + + private long mCurrentHeaderId = -1; + + private DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + reset(); + } + + @Override + public void onInvalidated() { + reset(); + } + }; + + private int mHeaderBottomPosition; + + private boolean mHeadersIgnorePadding; + + private int mHorizontalSpacing; + + private boolean mMaskStickxinzaieaderRegion = true; + + private float mMotionY; + + /** + * Must be set from the wrapped GridView in the constructor. + */ + private int mNumColumns; + + private boolean mNumColumnsSet; + + private int mNumMeasuredColumns = 1; + + private OnHeaderClickListener mOnHeaderClickListener; + + private OnHeaderLongClickListener mOnHeaderLongClickListener; + + private OnItemClickListener mOnItemClickListener; + + private OnItemLongClickListener mOnItemLongClickListener; + + private OnItemSelectedListener mOnItemSelectedListener; + + private PerformHeaderClick mPerformHeaderClick; + + private OnScrollListener mScrollListener; + + private int mScrollState = SCROLL_STATE_IDLE; + + private View mStickiedHeader; + + private Runnable mTouchModeReset; + + private int mTouchSlop; + + private int mVerticalSpacing; + + protected StickyGridHeadersBaseAdapterWrapper mAdapter; + + protected boolean mDataChanged; + + protected int mMotionHeaderPosition; + + protected int mTouchMode; + + boolean mHeaderChildBeingPressed = false; + + public StickyGridHeadersGridView(Context context) { + this(context, null); + } + + public StickyGridHeadersGridView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.gridViewStyle); + } + + public StickyGridHeadersGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + super.setOnScrollListener(this); + setVerticalFadingEdgeEnabled(false); + + if (!mNumColumnsSet) { + mNumColumns = AUTO_FIT; + } + + ViewConfiguration vc = ViewConfiguration.get(context); + mTouchSlop = vc.getScaledTouchSlop(); + } + + public boolean areHeadersSticky() { + return mAreHeadersSticky; + } + + /** + * Gets the header at an item position. However, the position must be that of a HeaderFiller. + * + * @param position + * Position of HeaderFiller. + * @return Header View wrapped in HeaderFiller or null if no header was found. + */ + public View getHeaderAt(int position) { + if (position == MATCHED_STICKIED_HEADER) { + return mStickiedHeader; + } + + try { + return (View) getChildAt(position).getTag(); + } catch (Exception e) { + } + return null; + } + + /** + * Get the currently stickied header. + * + * @return Current stickied header. + */ + public View getStickiedHeader() { + return mStickiedHeader; + } + + public boolean getStickxinzaieaderIsTranscluent() { + return !mMaskStickxinzaieaderRegion; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + mOnItemClickListener.onItemClick(parent, view, mAdapter.translatePosition(position).mPosition, id); + } + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + return mOnItemLongClickListener.onItemLongClick(parent, view, mAdapter.translatePosition(position).mPosition, + id); + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + mOnItemSelectedListener.onItemSelected(parent, view, mAdapter.translatePosition(position).mPosition, id); + } + + @Override + public void onNothingSelected(AdapterView parent) { + mOnItemSelectedListener.onNothingSelected(parent); + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + + try { + super.onRestoreInstanceState(ss.getSuperState()); + }catch (Exception e){ + e.printStackTrace(); + } + mAreHeadersSticky = ss.areHeadersSticky; + + requestLayout(); + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + + SavedState ss = new SavedState(superState); + ss.areHeadersSticky = mAreHeadersSticky; + return ss; + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (mScrollListener != null) { + mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { + scrollChanged(firstVisibleItem); + } + } + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (mScrollListener != null) { + mScrollListener.onScrollStateChanged(view, scrollState); + } + + mScrollState = scrollState; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + final int action = ev.getAction(); + boolean wasHeaderChildBeingPressed = mHeaderChildBeingPressed; + if (mHeaderChildBeingPressed) { + final View tempHeader = getHeaderAt(mMotionHeaderPosition); + final View headerHolder = mMotionHeaderPosition == MATCHED_STICKIED_HEADER ? tempHeader + : getChildAt(mMotionHeaderPosition); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + mHeaderChildBeingPressed = false; + } + if (tempHeader != null) { + tempHeader.dispatchTouchEvent(transformEvent(ev, mMotionHeaderPosition)); + tempHeader.invalidate(); + tempHeader.postDelayed(new Runnable() { + public void run() { + invalidate(0, headerHolder.getTop(), getWidth(), + headerHolder.getTop() + headerHolder.getHeight()); + } + }, ViewConfiguration.getPressedStateDuration()); + invalidate(0, headerHolder.getTop(), getWidth(), headerHolder.getTop() + headerHolder.getHeight()); + } + } + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + if (mPendingCheckForTap == null) { + mPendingCheckForTap = new CheckForHeaderTap(); + } + postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); + + final int y = (int) ev.getY(); + mMotionY = y; + mMotionHeaderPosition = findMotionHeader(y); + if (mMotionHeaderPosition == NO_MATCHED_HEADER || mScrollState == SCROLL_STATE_FLING) { + // Don't consume the event and pass it to super because we + // can't handle it yet. + break; + } else { + View tempHeader = getHeaderAt(mMotionHeaderPosition); + if (tempHeader != null) { + if (tempHeader.dispatchTouchEvent(transformEvent(ev, mMotionHeaderPosition))) { + mHeaderChildBeingPressed = true; + tempHeader.setPressed(true); + } + tempHeader.invalidate(); + if (mMotionHeaderPosition != MATCHED_STICKIED_HEADER) { + tempHeader = getChildAt(mMotionHeaderPosition); + } + invalidate(0, tempHeader.getTop(), getWidth(), tempHeader.getTop() + tempHeader.getHeight()); + } + } + mTouchMode = TOUCH_MODE_DOWN; + return true; + case MotionEvent.ACTION_MOVE: + if (mMotionHeaderPosition != NO_MATCHED_HEADER && Math.abs(ev.getY() - mMotionY) > mTouchSlop) { + // Detected scroll initiation so cancel touch completion on + // header. + mTouchMode = TOUCH_MODE_REST; + // if (!mHeaderChildBeingPressed) { + final View header = getHeaderAt(mMotionHeaderPosition); + if (header != null) { + header.setPressed(false); + header.invalidate(); + } + final Handler handler = getHandler(); + if (handler != null) { + handler.removeCallbacks(mPendingCheckForLongPress); + } + mMotionHeaderPosition = NO_MATCHED_HEADER; + // } + } + break; + case MotionEvent.ACTION_UP: + if (mTouchMode == TOUCH_MODE_FINISHED_LONG_PRESS) { + mTouchMode = TOUCH_MODE_REST; + return true; + } + if (mTouchMode == TOUCH_MODE_REST || mMotionHeaderPosition == NO_MATCHED_HEADER) { + break; + } + + final View header = getHeaderAt(mMotionHeaderPosition); + if (!wasHeaderChildBeingPressed) { + if (header != null) { + if (mTouchMode != TOUCH_MODE_DOWN) { + header.setPressed(false); + } + + if (mPerformHeaderClick == null) { + mPerformHeaderClick = new PerformHeaderClick(); + } + + final PerformHeaderClick performHeaderClick = mPerformHeaderClick; + performHeaderClick.mClickMotionPosition = mMotionHeaderPosition; + performHeaderClick.rememberWindowAttachCount(); + + if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) { + final Handler handler = getHandler(); + if (handler != null) { + handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ? mPendingCheckForTap + : mPendingCheckForLongPress); + } + + if (!mDataChanged) { + /* + * Got here so must be a tap. The long press would have triggered on + * the callback handler. + */ + mTouchMode = TOUCH_MODE_TAP; + header.setPressed(true); + setPressed(true); + if (mTouchModeReset != null) { + removeCallbacks(mTouchModeReset); + } + mTouchModeReset = new Runnable() { + @Override + public void run() { + mMotionHeaderPosition = NO_MATCHED_HEADER; + mTouchModeReset = null; + mTouchMode = TOUCH_MODE_REST; + header.setPressed(false); + setPressed(false); + header.invalidate(); + invalidate(0, header.getTop(), getWidth(), header.getHeight()); + if (!mDataChanged) { + performHeaderClick.run(); + } + } + }; + postDelayed(mTouchModeReset, ViewConfiguration.getPressedStateDuration()); + } else { + mTouchMode = TOUCH_MODE_REST; + } + } else if (!mDataChanged) { + performHeaderClick.run(); + } + } + } + mTouchMode = TOUCH_MODE_REST; + return true; + } + return super.onTouchEvent(ev); + } + + public boolean performHeaderClick(View view, long id) { + if (mOnHeaderClickListener != null) { + playSoundEffect(SoundEffectConstants.CLICK); + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + } + mOnHeaderClickListener.onHeaderClick(this, view, id); + return true; + } + + return false; + } + + public boolean performHeaderLongPress(View view, long id) { + boolean handled = false; + if (mOnHeaderLongClickListener != null) { + handled = mOnHeaderLongClickListener.onHeaderLongClick(this, view, id); + } + + if (handled) { + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + } + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + + return handled; + } + + @Override + public void setAdapter(ListAdapter adapter) { + if (mAdapter != null && mDataSetObserver != null) { + mAdapter.unregisterDataSetObserver(mDataSetObserver); + } + + if (!mClipToPaddingHasBeenSet) { + mClippingToPadding = true; + } + + StickyGridHeadersBaseAdapter baseAdapter; + if (adapter instanceof StickyGridHeadersBaseAdapter) { + baseAdapter = (StickyGridHeadersBaseAdapter) adapter; + } else if (adapter instanceof StickyGridHeadersSimpleAdapter) { + // Wrap up simple adapter to auto-generate the data we need. + baseAdapter = new StickyGridHeadersSimpleAdapterWrapper((StickyGridHeadersSimpleAdapter) adapter); + } else { + // Wrap up a list adapter so it is an adapter with zero headers. + baseAdapter = new StickyGridHeadersListAdapterWrapper(adapter); + } + + this.mAdapter = new StickyGridHeadersBaseAdapterWrapper(getContext(), this, baseAdapter); + this.mAdapter.registerDataSetObserver(mDataSetObserver); + reset(); + super.setAdapter(this.mAdapter); + } + + public int translatePosition(int position) { + return mAdapter.translatePosition(position).mPosition; + } + + public void setAreHeadersSticky(boolean useStickxinzaieaders) { + if (useStickxinzaieaders != mAreHeadersSticky) { + mAreHeadersSticky = useStickxinzaieaders; + requestLayout(); + } + } + + @Override + public void setClipToPadding(boolean clipToPadding) { + super.setClipToPadding(clipToPadding); + mClippingToPadding = clipToPadding; + mClipToPaddingHasBeenSet = true; + } + + @Override + public void setColumnWidth(int columnWidth) { + super.setColumnWidth(columnWidth); + mColumnWidth = columnWidth; + } + + /** + * If set to true, headers will ignore horizontal padding. + * + * @param b + * if true, horizontal padding is ignored by headers + */ + public void setHeadersIgnorePadding(boolean b) { + mHeadersIgnorePadding = b; + } + + @Override + public void setHorizontalSpacing(int horizontalSpacing) { + super.setHorizontalSpacing(horizontalSpacing); + mHorizontalSpacing = horizontalSpacing; + } + + @Override + public void setNumColumns(int numColumns) { + super.setNumColumns(numColumns); + mNumColumnsSet = true; + this.mNumColumns = numColumns; + if (numColumns != AUTO_FIT && mAdapter != null) { + mAdapter.setNumColumns(numColumns); + } + } + + public void setOnHeaderClickListener(OnHeaderClickListener listener) { + mOnHeaderClickListener = listener; + } + + public void setOnHeaderLongClickListener(OnHeaderLongClickListener listener) { + if (!isLongClickable()) { + setLongClickable(true); + } + mOnHeaderLongClickListener = listener; + } + + @Override + public void setOnItemClickListener(OnItemClickListener listener) { + this.mOnItemClickListener = listener; + super.setOnItemClickListener(this); + } + + @Override + public void setOnItemLongClickListener(OnItemLongClickListener listener) { + this.mOnItemLongClickListener = listener; + super.setOnItemLongClickListener(this); + } + + @Override + public void setOnItemSelectedListener(OnItemSelectedListener listener) { + this.mOnItemSelectedListener = listener; + super.setOnItemSelectedListener(this); + } + + @Override + public void setOnScrollListener(OnScrollListener listener) { + this.mScrollListener = listener; + } + + public void setStickxinzaieaderIsTranscluent(boolean isTranscluent) { + mMaskStickxinzaieaderRegion = !isTranscluent; + } + + @Override + public void setVerticalSpacing(int verticalSpacing) { + super.setVerticalSpacing(verticalSpacing); + mVerticalSpacing = verticalSpacing; + } + + private int findMotionHeader(float y) { + if (mStickiedHeader != null && y <= mHeaderBottomPosition) { + return MATCHED_STICKIED_HEADER; + } + + int vi = 0; + for (int i = getFirstVisiblePosition(); i <= getLastVisiblePosition();) { + long id = getItemIdAtPosition(i); + if (id == StickyGridHeadersBaseAdapterWrapper.ID_HEADER) { + View headerWrapper = getChildAt(vi); + + int bottom = headerWrapper.getBottom(); + int top = headerWrapper.getTop(); + if (y <= bottom && y >= top) { + return vi; + } + } + i += mNumMeasuredColumns; + vi += mNumMeasuredColumns; + } + + return NO_MATCHED_HEADER; + } + + private int getHeaderHeight() { + if (mStickiedHeader != null) { + return mStickiedHeader.getMeasuredHeight(); + } + return 0; + } + + private long headerViewPositionToId(int pos) { + if (pos == MATCHED_STICKIED_HEADER) { + return mCurrentHeaderId; + } + return mAdapter.getHeaderId(getFirstVisiblePosition() + pos); + } + + private void measureHeader() { + if (mStickiedHeader == null) { + return; + } + + int widthMeasureSpec; + if (mHeadersIgnorePadding) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY); + } else { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth() - getPaddingLeft() - getPaddingRight(), + MeasureSpec.EXACTLY); + } + + int heightMeasureSpec = 0; + + ViewGroup.LayoutParams params = mStickiedHeader.getLayoutParams(); + if (params != null && params.height > 0) { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY); + } else { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + mStickiedHeader.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + mStickiedHeader.measure(widthMeasureSpec, heightMeasureSpec); + + if (mHeadersIgnorePadding) { + mStickiedHeader.layout(getLeft(), 0, getRight(), mStickiedHeader.getMeasuredHeight()); + } else { + mStickiedHeader.layout(getLeft() + getPaddingLeft(), 0, getRight() - getPaddingRight(), + mStickiedHeader.getMeasuredHeight()); + } + } + + private void reset() { + mHeaderBottomPosition = 0; + swapStickiedHeader(null); + mCurrentHeaderId = INVALID_ROW_ID; + } + + private void scrollChanged(int firstVisibleItem) { + if (mAdapter == null || mAdapter.getCount() == 0 || !mAreHeadersSticky) { + return; + } + + View firstItem = getChildAt(0); + if (firstItem == null) { + return; + } + + long newHeaderId; + int selectedHeaderPosition = firstVisibleItem; + + int beforeRowPosition = firstVisibleItem - mNumMeasuredColumns; + if (beforeRowPosition < 0) { + beforeRowPosition = firstVisibleItem; + } + + int secondRowPosition = firstVisibleItem + mNumMeasuredColumns; + if (secondRowPosition >= mAdapter.getCount()) { + secondRowPosition = firstVisibleItem; + } + + if (mVerticalSpacing == 0) { + newHeaderId = mAdapter.getHeaderId(firstVisibleItem); + } else if (mVerticalSpacing < 0) { + newHeaderId = mAdapter.getHeaderId(firstVisibleItem); + View firstSecondRowView = getChildAt(mNumMeasuredColumns); + if (firstSecondRowView.getTop() <= 0) { + newHeaderId = mAdapter.getHeaderId(secondRowPosition); + selectedHeaderPosition = secondRowPosition; + } else { + newHeaderId = mAdapter.getHeaderId(firstVisibleItem); + } + } else { + int margin = getChildAt(0).getTop(); + if (0 < margin && margin < mVerticalSpacing) { + newHeaderId = mAdapter.getHeaderId(beforeRowPosition); + selectedHeaderPosition = beforeRowPosition; + } else { + newHeaderId = mAdapter.getHeaderId(firstVisibleItem); + } + } + + if (mCurrentHeaderId != newHeaderId) { + swapStickiedHeader(mAdapter.getHeaderView(selectedHeaderPosition, mStickiedHeader, this)); + measureHeader(); + mCurrentHeaderId = newHeaderId; + } + + final int childCount = getChildCount(); + if (childCount != 0) { + View viewToWatch = null; + int watchingChildDistance = 99999; + + // Find the next header after the stickied one. + for (int i = 0; i < childCount; i += mNumMeasuredColumns) { + View child = super.getChildAt(i); + + int childDistance; + if (mClippingToPadding) { + childDistance = child.getTop() - getPaddingTop(); + } else { + childDistance = child.getTop(); + } + + if (childDistance < 0) { + continue; + } + + if (mAdapter.getItemId(getPositionForView(child)) == StickyGridHeadersBaseAdapterWrapper.ID_HEADER + && childDistance < watchingChildDistance) { + viewToWatch = child; + watchingChildDistance = childDistance; + } + } + + int headerHeight = getHeaderHeight(); + + // Work out where to draw stickied header using synchronised + // scrolling. + if (viewToWatch != null) { + if (firstVisibleItem == 0 && super.getChildAt(0).getTop() > 0 && !mClippingToPadding) { + mHeaderBottomPosition = 0; + } else { + if (mClippingToPadding) { + mHeaderBottomPosition = Math.min(viewToWatch.getTop(), headerHeight + getPaddingTop()); + mHeaderBottomPosition = mHeaderBottomPosition < getPaddingTop() ? headerHeight + + getPaddingTop() : mHeaderBottomPosition; + } else { + mHeaderBottomPosition = Math.min(viewToWatch.getTop(), headerHeight); + mHeaderBottomPosition = mHeaderBottomPosition < 0 ? headerHeight : mHeaderBottomPosition; + } + } + } else { + mHeaderBottomPosition = headerHeight; + if (mClippingToPadding) { + mHeaderBottomPosition += getPaddingTop(); + } + } + } + } + + private void swapStickiedHeader(View newStickiedHeader) { + detachHeader(mStickiedHeader); + attachHeader(newStickiedHeader); + mStickiedHeader = newStickiedHeader; + } + + private MotionEvent transformEvent(MotionEvent e, int headerPosition) { + if (headerPosition == MATCHED_STICKIED_HEADER) { + return e; + } + + long downTime = e.getDownTime(); + long eventTime = e.getEventTime(); + int action = e.getAction(); + int pointerCount = e.getPointerCount(); + int[] pointerIds = getPointerIds(e); + MotionEvent.PointerCoords[] pointerCoords = getPointerCoords(e); + int metaState = e.getMetaState(); + float xPrecision = e.getXPrecision(); + float yPrecision = e.getYPrecision(); + int deviceId = e.getDeviceId(); + int edgeFlags = e.getEdgeFlags(); + int source = e.getSource(); + int flags = e.getFlags(); + + View headerHolder = getChildAt(headerPosition); + for (int i = 0; i < pointerCount; i++) { + pointerCoords[i].y -= headerHolder.getTop(); + } + MotionEvent n = MotionEvent.obtain(downTime, eventTime, action, pointerCount, pointerIds, pointerCoords, + metaState, xPrecision, yPrecision, deviceId, edgeFlags, source, flags); + return n; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { + scrollChanged(getFirstVisiblePosition()); + } + + boolean drawStickiedHeader = mStickiedHeader != null && mAreHeadersSticky + && mStickiedHeader.getVisibility() == View.VISIBLE; + int headerHeight = getHeaderHeight(); + int top = mHeaderBottomPosition - headerHeight; + + // Mask the region where we will draw the header later, but only if we + // will draw a header and masking is requested. + if (drawStickiedHeader && mMaskStickxinzaieaderRegion) { + if (mHeadersIgnorePadding) { + mClippingRect.left = 0; + mClippingRect.right = getWidth(); + } else { + mClippingRect.left = getPaddingLeft(); + mClippingRect.right = getWidth() - getPaddingRight(); + } + mClippingRect.top = mHeaderBottomPosition; + mClippingRect.bottom = getHeight(); + + canvas.save(); + canvas.clipRect(mClippingRect); + } + + // ...and draw the grid view. + super.dispatchDraw(canvas); + + // Find headers. + List headerPositions = new ArrayList<>(); + int vi = 0; + for (int i = getFirstVisiblePosition(); i <= getLastVisiblePosition();) { + long id = getItemIdAtPosition(i); + if (id == StickyGridHeadersBaseAdapterWrapper.ID_HEADER) { + headerPositions.add(vi); + } + i += mNumMeasuredColumns; + vi += mNumMeasuredColumns; + } + + // Draw headers in list. + for (int i = 0; i < headerPositions.size(); i++) { + View frame = getChildAt(headerPositions.get(i)); + View header; + try { + header = (View) frame.getTag(); + } catch (Exception e) { + return; + } + + boolean headerIsStickied = ((StickyGridHeadersBaseAdapterWrapper.HeaderFillerView) frame).getHeaderId() == mCurrentHeaderId + && frame.getTop() < 0 && mAreHeadersSticky; + if (header.getVisibility() != View.VISIBLE || headerIsStickied) { + continue; + } + + int widthMeasureSpec; + if (mHeadersIgnorePadding) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY); + } else { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth() - getPaddingLeft() - getPaddingRight(), + MeasureSpec.EXACTLY); + } + + int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + header.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + header.measure(widthMeasureSpec, heightMeasureSpec); + + if (mHeadersIgnorePadding) { + header.layout(getLeft(), 0, getRight(), frame.getHeight()); + } else { + header.layout(getLeft() + getPaddingLeft(), 0, getRight() - getPaddingRight(), frame.getHeight()); + } + + if (mHeadersIgnorePadding) { + mClippingRect.left = 0; + mClippingRect.right = getWidth(); + } else { + mClippingRect.left = getPaddingLeft(); + mClippingRect.right = getWidth() - getPaddingRight(); + } + + mClippingRect.bottom = frame.getBottom(); + mClippingRect.top = frame.getTop(); + canvas.save(); + canvas.clipRect(mClippingRect); + if (mHeadersIgnorePadding) { + canvas.translate(0, frame.getTop()); + } else { + canvas.translate(getPaddingLeft(), frame.getTop()); + } + header.draw(canvas); + canvas.restore(); + } + + if (drawStickiedHeader && mMaskStickxinzaieaderRegion) { + canvas.restore(); + } else if (!drawStickiedHeader) { + // Done. + return; + } + + // Draw stickied header. + int wantedWidth; + if (mHeadersIgnorePadding) { + wantedWidth = getWidth(); + } else { + wantedWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + } + if (mStickiedHeader.getWidth() != wantedWidth) { + int widthMeasureSpec; + if (mHeadersIgnorePadding) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY); + } else { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth() - getPaddingLeft() - getPaddingRight(), + MeasureSpec.EXACTLY); // Bug here + } + int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mStickiedHeader.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + mStickiedHeader.measure(widthMeasureSpec, heightMeasureSpec); + if (mHeadersIgnorePadding) { + mStickiedHeader.layout(getLeft(), 0, getRight(), mStickiedHeader.getHeight()); + } else { + mStickiedHeader.layout(getLeft() + getPaddingLeft(), 0, getRight() - getPaddingRight(), + mStickiedHeader.getHeight()); + } + } + + if (mHeadersIgnorePadding) { + mClippingRect.left = 0; + mClippingRect.right = getWidth(); + } else { + mClippingRect.left = getPaddingLeft(); + mClippingRect.right = getWidth() - getPaddingRight(); + } + mClippingRect.bottom = top + headerHeight; + if (mClippingToPadding) { + mClippingRect.top = getPaddingTop(); + } else { + mClippingRect.top = 0; + } + + canvas.save(); + canvas.clipRect(mClippingRect); + + if (mHeadersIgnorePadding) { + canvas.translate(0, top); + } else { + canvas.translate(getPaddingLeft(), top); + } + + if (mHeaderBottomPosition != headerHeight) { + canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255 * mHeaderBottomPosition + / headerHeight); + } + + mStickiedHeader.draw(canvas); + + if (mHeaderBottomPosition != headerHeight) { + canvas.restore(); + } + canvas.restore(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mNumColumns == AUTO_FIT) { + int numFittedColumns; + if (mColumnWidth > 0) { + int gridWidth = Math.max(MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(), + 0); + numFittedColumns = gridWidth / mColumnWidth; + // Calculate measured columns accounting for requested grid + // spacing. + if (numFittedColumns > 0) { + while (numFittedColumns != 1) { + if (numFittedColumns * mColumnWidth + (numFittedColumns - 1) * mHorizontalSpacing > gridWidth) { + numFittedColumns--; + } else { + break; + } + } + } else { + // Could not fit any columns in grid width, so default to a + // single column. + numFittedColumns = 1; + } + } else { + // Mimic vanilla GridView behaviour where there is not enough + // information to auto-fit columns. + numFittedColumns = 2; + } + mNumMeasuredColumns = numFittedColumns; + } else { + // There were some number of columns requested so we will try to + // fulfil the request. + mNumMeasuredColumns = mNumColumns; + } + + // Update adapter with number of columns. + if (mAdapter != null) { + mAdapter.setNumColumns(mNumMeasuredColumns); + } + + measureHeader(); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + void attachHeader(View header) { + if (header == null) { + return; + } + + try { + Field attachInfoField = View.class.getDeclaredField("mAttachInfo"); + attachInfoField.setAccessible(true); + Method method = View.class.getDeclaredMethod("dispatchAttachedToWindow", + Class.forName("android.view.View$AttachInfo"), Integer.TYPE); + method.setAccessible(true); + method.invoke(header, attachInfoField.get(this), View.GONE); + } catch (NoSuchMethodException e) { + throw new RuntimePlatformSupportException(e); + } catch (ClassNotFoundException e) { + throw new RuntimePlatformSupportException(e); + } catch (IllegalArgumentException e) { + throw new RuntimePlatformSupportException(e); + } catch (IllegalAccessException e) { + throw new RuntimePlatformSupportException(e); + } catch (InvocationTargetException e) { + throw new RuntimePlatformSupportException(e); + } catch (NoSuchFieldException e) { + throw new RuntimePlatformSupportException(e); + } + } + + void detachHeader(View header) { + if (header == null) { + return; + } + + try { + Method method = View.class.getDeclaredMethod("dispatchDetachedFromWindow"); + method.setAccessible(true); + method.invoke(header); + } catch (NoSuchMethodException e) { + throw new RuntimePlatformSupportException(e); + } catch (IllegalArgumentException e) { + throw new RuntimePlatformSupportException(e); + } catch (IllegalAccessException e) { + throw new RuntimePlatformSupportException(e); + } catch (InvocationTargetException e) { + throw new RuntimePlatformSupportException(e); + } + } + + public interface OnHeaderClickListener { + void onHeaderClick(AdapterView parent, View view, long id); + } + + public interface OnHeaderLongClickListener { + boolean onHeaderLongClick(AdapterView parent, View view, long id); + } + + private class CheckForHeaderLongPress extends WindowRunnable implements Runnable { + @Override + public void run() { + final View child = getHeaderAt(mMotionHeaderPosition); + if (child != null) { + final long longPressId = headerViewPositionToId(mMotionHeaderPosition); + + boolean handled = false; + if (sameWindow() && !mDataChanged) { + handled = performHeaderLongPress(child, longPressId); + } + if (handled) { + mTouchMode = TOUCH_MODE_FINISHED_LONG_PRESS; + setPressed(false); + child.setPressed(false); + } else { + mTouchMode = TOUCH_MODE_DONE_WAITING; + } + } + } + } + + private class PerformHeaderClick extends WindowRunnable implements Runnable { + int mClickMotionPosition; + + @Override + public void run() { + // The data has changed since we posted this action to the event + // queue, bail out before bad things happen. + if (mDataChanged) + return; + + if (mAdapter != null && mAdapter.getCount() > 0 && mClickMotionPosition != INVALID_POSITION + && mClickMotionPosition < mAdapter.getCount() && sameWindow()) { + final View view = getHeaderAt(mClickMotionPosition); + // If there is no view then something bad happened, the view + // probably scrolled off the screen, and we should cancel the + // click. + if (view != null) { + performHeaderClick(view, headerViewPositionToId(mClickMotionPosition)); + } + } + } + } + + /** + * A base class for Runnables that will check that their view is still attached to the original + * window as when the Runnable was created. + */ + private class WindowRunnable { + private int mOriginalAttachCount; + + public void rememberWindowAttachCount() { + mOriginalAttachCount = getWindowAttachCount(); + } + + public boolean sameWindow() { + return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount; + } + } + + final class CheckForHeaderTap implements Runnable { + @Override + public void run() { + if (mTouchMode == TOUCH_MODE_DOWN) { + mTouchMode = TOUCH_MODE_TAP; + final View header = getHeaderAt(mMotionHeaderPosition); + if (header != null && !mHeaderChildBeingPressed) { + if (!mDataChanged) { + header.setPressed(true); + setPressed(true); + refreshDrawableState(); + + final int longPressTimeout = ViewConfiguration.getLongPressTimeout(); + final boolean longClickable = isLongClickable(); + + if (longClickable) { + if (mPendingCheckForLongPress == null) { + mPendingCheckForLongPress = new CheckForHeaderLongPress(); + } + mPendingCheckForLongPress.rememberWindowAttachCount(); + postDelayed(mPendingCheckForLongPress, longPressTimeout); + } else { + mTouchMode = TOUCH_MODE_DONE_WAITING; + } + } else { + mTouchMode = TOUCH_MODE_DONE_WAITING; + } + } + } + } + } + + class RuntimePlatformSupportException extends RuntimeException { + private static final long serialVersionUID = -6512098808936536538L; + + public RuntimePlatformSupportException(Exception e) { + super(ERROR_PLATFORM, e); + } + } + + /** + * Constructor called from {@link #CREATOR} + */ + static class SavedState extends BaseSavedState { + public static final Creator CREATOR = new Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + + boolean areHeadersSticky; + + public SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + areHeadersSticky = in.readByte() != 0; + } + + @Override + public String toString() { + return "StickyGridHeadersGridView.SavedState{" + Integer.toHexString(System.identityHashCode(this)) + + " areHeadersSticky=" + areHeadersSticky + "}"; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeByte((byte) (areHeadersSticky ? 1 : 0)); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersListAdapterWrapper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersListAdapterWrapper.java new file mode 100644 index 0000000..dc8f13c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersListAdapterWrapper.java @@ -0,0 +1,87 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListAdapter; + +public class StickyGridHeadersListAdapterWrapper extends BaseAdapter implements StickyGridHeadersBaseAdapter { + private DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + notifyDataSetChanged(); + } + + @Override + public void onInvalidated() { + notifyDataSetInvalidated(); + } + }; + + private ListAdapter mDelegate; + + public StickyGridHeadersListAdapterWrapper(ListAdapter adapter) { + mDelegate = adapter; + if (adapter != null) { + adapter.registerDataSetObserver(mDataSetObserver); + } + } + + @Override + public int getCount() { + if (mDelegate == null) { + return 0; + } + return mDelegate.getCount(); + } + + @Override + public int getCountForHeader(int header) { + return 0; + } + + @Override + public View getHeaderView(int position, View convertView, ViewGroup parent) { + return null; + } + + @Override + public Object getItem(int position) { + if (mDelegate == null) { + return null; + } + return mDelegate.getItem(position); + } + + @Override + public long getItemId(int position) { + return mDelegate.getItemId(position); + } + + @Override + public int getItemViewType(int position) { + return mDelegate.getItemViewType(position); + } + + @Override + public int getNumHeaders() { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return mDelegate.getView(position, convertView, parent); + } + + @Override + public int getViewTypeCount() { + return mDelegate.getViewTypeCount(); + } + + @Override + public boolean hasStableIds() { + return mDelegate.hasStableIds(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapter.java new file mode 100644 index 0000000..21de9bb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapter.java @@ -0,0 +1,38 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListAdapter; + +/** + * Adapter interface for StickyGridHeadersGridView. The adapter expects two sets of data, items, and + * headers. Implement this interface to provide an optimised method for generating the header data + * set. The is a second interface + * {@link StickyGridHeadersBaseAdapter}. + */ +public interface StickyGridHeadersSimpleAdapter extends ListAdapter { + /** + * Get the header id associated with the specified position in the list. + * + * @param position + * The position of the item within the adapter's data set whose header id we want. + * @return The id of the header at the specified position. + */ + long getHeaderId(int position); + + /** + * Get a View that displays the header data at the specified position in the set. You can either + * create a View manually or inflate it from an XML layout file. + * + * @param position + * The position of the header within the adapter's header data set. + * @param convertView + * The old view to reuse, if possible. Note: You should check that this view is + * non-null and of an appropriate type before using. If it is not possible to convert + * this view to display the correct data, this method can create a new view. + * @param parent + * The parent that this view will eventually be attached to. + * @return A View corresponding to the data at the specified position. + */ + View getHeaderView(int position, View convertView, ViewGroup parent); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapterWrapper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapterWrapper.java new file mode 100644 index 0000000..d9433f0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickygridheaders/StickyGridHeadersSimpleAdapterWrapper.java @@ -0,0 +1,145 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders; + +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Adapter wrapper to insert extra views and otherwise hack around GridView to add sections and + * headers. + */ +public class StickyGridHeadersSimpleAdapterWrapper extends BaseAdapter implements StickyGridHeadersBaseAdapter { + private StickyGridHeadersSimpleAdapter mDelegate; + + private HeaderData[] mHeaders; + + public StickyGridHeadersSimpleAdapterWrapper(StickyGridHeadersSimpleAdapter adapter) { + mDelegate = adapter; + adapter.registerDataSetObserver(new DataSetObserverExtension()); + mHeaders = generateHeaderList(adapter); + } + + @Override + public int getCount() { + return mDelegate.getCount(); + } + + @Override + public int getCountForHeader(int position) { + int headerPosition = 0; + if(position <0 || position>=mHeaders.length){ + headerPosition = 0; + }else{ + headerPosition = position; + } + + return mHeaders[headerPosition].getCount(); + } + + @Override + public View getHeaderView(int position, View convertView, ViewGroup parent) { + int headerPosition = 0; + if(position <0 || position>=mHeaders.length){ + headerPosition = 0; + }else{ + headerPosition = mHeaders[position].getRefPosition(); + } + return mDelegate.getHeaderView(headerPosition, convertView, parent); + } + + @Override + public Object getItem(int position) { + return mDelegate.getItem(position); + } + + @Override + public long getItemId(int position) { + return mDelegate.getItemId(position); + } + + @Override + public int getItemViewType(int position) { + return mDelegate.getItemViewType(position); + } + + @Override + public int getNumHeaders() { + return mHeaders.length; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return mDelegate.getView(position, convertView, parent); + } + + @Override + public int getViewTypeCount() { + return mDelegate.getViewTypeCount(); + } + + @Override + public boolean hasStableIds() { + return mDelegate.hasStableIds(); + } + + protected HeaderData[] generateHeaderList(StickyGridHeadersSimpleAdapter adapter) { + Map mapping = new HashMap<>(); + List headers = new ArrayList<>(); + + for (int i = 0; i < adapter.getCount(); i++) { + long headerId = adapter.getHeaderId(i); + HeaderData headerData = mapping.get(headerId); + if (headerData == null) { + headerData = new HeaderData(i); + headers.add(headerData); + } + headerData.incrementCount(); + mapping.put(headerId, headerData); + } + + return headers.toArray(new HeaderData[headers.size()]); + } + + private final class DataSetObserverExtension extends DataSetObserver { + @Override + public void onChanged() { + mHeaders = generateHeaderList(mDelegate); + notifyDataSetChanged(); + } + + @Override + public void onInvalidated() { + mHeaders = generateHeaderList(mDelegate); + notifyDataSetInvalidated(); + } + } + + private static class HeaderData { + private int mCount; + + private int mRefPosition; + + public HeaderData(int refPosition) { + mRefPosition = refPosition; + mCount = 0; + } + + public int getCount() { + return mCount; + } + + public int getRefPosition() { + return mRefPosition; + } + + public void incrementCount() { + mCount++; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/CheckableWrapperView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/CheckableWrapperView.java new file mode 100644 index 0000000..140abbe --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/CheckableWrapperView.java @@ -0,0 +1,26 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickylistheaders; + +import android.content.Context; +import android.widget.Checkable; + +class CheckableWrapperView extends WrapperView implements Checkable { + + public CheckableWrapperView(final Context context) { + super(context); + } + + @Override + public boolean isChecked() { + return ((Checkable) item).isChecked(); + } + + @Override + public void setChecked(final boolean checked) { + ((Checkable) item).setChecked(checked); + } + + @Override + public void toggle() { + setChecked(!isChecked()); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapter.java new file mode 100644 index 0000000..12a23b1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapter.java @@ -0,0 +1,38 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickylistheaders; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListAdapter; + +public interface StickyListHeadersAdapter extends ListAdapter { + /** + * Get a View that displays the header data at the specified position in the + * set. You can either create a View manually or inflate it from an XML layout + * file. + * + * @param position + * The position of the item within the adapter's data set of the item whose + * header view we want. + * @param convertView + * The old view to reuse, if possible. Note: You should check that this view is + * non-null and of an appropriate type before using. If it is not possible to + * convert this view to display the correct data, this method can create a new + * view. + * @param parent + * The parent that this view will eventually be attached to. + * @return + * A View corresponding to the data at the specified position. + */ + View getHeaderView(int position, View convertView, ViewGroup parent); + + /** + * Get the header id associated with the specified position in the list. + * + * @param position + * The position of the item within the adapter's data set whose header id we + * want. + * @return + * The id of the header at the specified position. + */ + long getHeaderId(int position); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapterWrapper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapterWrapper.java new file mode 100644 index 0000000..a39327e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersAdapterWrapper.java @@ -0,0 +1,217 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickylistheaders; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Checkable; +import android.widget.ListAdapter; + +import java.util.ArrayList; +import java.util.List; + +final class StickyListHeadersAdapterWrapper extends BaseAdapter implements StickyListHeadersAdapter { + + + public interface OnHeaderClickListener{ + public void onHeaderClick(View header, int itemPosition, long headerId); + } + + private final List headerCache = new ArrayList<>(); + private final Context context; + private final StickyListHeadersAdapter delegate; + private Drawable divider; + private int dividerHeight; + private DataSetObserver dataSetObserver = new DataSetObserver() { + + @Override + public void onInvalidated() { + headerCache.clear(); + } + }; + private OnHeaderClickListener onHeaderClickListener; + + StickyListHeadersAdapterWrapper(Context context, + StickyListHeadersAdapter delegate) { + this.context = context; + this.delegate = delegate; + delegate.registerDataSetObserver(dataSetObserver); + } + + void setDivider(Drawable divider) { + this.divider = divider; + } + + void setDividerHeight(int dividerHeight) { + this.dividerHeight = dividerHeight; + } + + @Override + public boolean areAllItemsEnabled() { + return delegate.areAllItemsEnabled(); + } + + @Override + public boolean isEnabled(int position) { + return delegate.isEnabled(position); + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + delegate.registerDataSetObserver(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + delegate.unregisterDataSetObserver(observer); + } + + @Override + public int getCount() { + return delegate.getCount(); + } + + @Override + public Object getItem(int position) { + return delegate.getItem(position); + } + + @Override + public long getItemId(int position) { + return delegate.getItemId(position); + } + + @Override + public boolean hasStableIds() { + return delegate.hasStableIds(); + } + + @Override + public int getItemViewType(int position) { + return delegate.getItemViewType(position); + } + + @Override + public int getViewTypeCount() { + return delegate.getViewTypeCount(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + /** + * Will recycle header from {@link WrapperView} if it exists + */ + private void recycleHeaderIfExists(WrapperView wv) { + View header = wv.header; + if (header != null) { + headerCache.add(header); + } + } + + /** + * Get a header view. This optionally pulls a header from the supplied + * {@link WrapperView} and will also recycle the divider if it exists. + */ + private View configureHeader(WrapperView wv, final int position) { + View header = wv.header; + header = delegate.getHeaderView(position, header, wv); + if (header == null) { + throw new NullPointerException("Header view must not be null."); + } + //if the header isn't clickable, the listselector will be drawn on top of the header + header.setClickable(true); + header.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if(onHeaderClickListener != null){ + long headerId = delegate.getHeaderId(position); + onHeaderClickListener.onHeaderClick(v, position, headerId); + } + } + }); + return header; + } + + /** Returns {@code true} if the previous position has the same header ID. */ + private boolean previousPositionHasSameHeader(int position) { + return position != 0 + && delegate.getHeaderId(position) == delegate + .getHeaderId(position - 1); + } + + @Override + public WrapperView getView(int position, View convertView, ViewGroup parent) { + WrapperView wv = (convertView == null) ? new WrapperView(context) : (WrapperView) convertView; + View item = delegate.getView(position, wv.item, wv); + View header = null; + if (previousPositionHasSameHeader(position)) { + recycleHeaderIfExists(wv); + } else { + header = configureHeader(wv, position); + } + if((item instanceof Checkable) && !(wv instanceof CheckableWrapperView)) { + // Need to create Checkable subclass of WrapperView for ListView to work correctly + wv = new CheckableWrapperView(context); + } else if(!(item instanceof Checkable) && (wv instanceof CheckableWrapperView)) { + wv = new WrapperView(context); + } + wv.update(item, header, divider, dividerHeight); + return wv; + } + + public void setOnHeaderClickListener(OnHeaderClickListener onHeaderClickListener){ + this.onHeaderClickListener = onHeaderClickListener; + } + + @Override + public boolean equals(Object o) { + if(delegate == null){ + return o == null; + } + return delegate.equals(o); + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + return ((BaseAdapter) delegate).getDropDownView(position, convertView, parent); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + ((BaseAdapter) delegate).notifyDataSetChanged(); + } + + @Override + public void notifyDataSetInvalidated() { + ((BaseAdapter) delegate).notifyDataSetInvalidated(); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public View getHeaderView(int position, View convertView, ViewGroup parent) { + return delegate.getHeaderView(position, convertView, parent); + } + + @Override + public long getHeaderId(int position) { + return delegate.getHeaderId(position); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersListView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersListView.java new file mode 100644 index 0000000..cd3c731 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/StickyListHeadersListView.java @@ -0,0 +1,476 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickylistheaders; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.ListAdapter; +import android.widget.ListView; + +import java.util.ArrayList; + +public class StickyListHeadersListView extends ListView implements + OnScrollListener { + + public interface OnHeaderClickListener { + public void onHeaderClick(StickyListHeadersListView l, View header, + int itemPosition, long headerId, boolean currentlySticky); + } + + private OnScrollListener scrollListener; + private boolean areHeadersSticky = true; + private int headerBottomPosition; + private View header; + private int dividerHeight; + private Drawable divider; + private boolean clippingToPadding; + private boolean clipToPaddingHasBeenSet; + private final Rect clippingRect = new Rect(); + private Long currentHeaderId = null; + private StickyListHeadersAdapterWrapper adapter; + private float headerDownY = -1; + private boolean headerBeingPressed = false; + private OnHeaderClickListener onHeaderClickListener; + private int headerPosition; + private ViewConfiguration viewConfig; + private ArrayList footerViews; + + private StickyListHeadersAdapterWrapper.OnHeaderClickListener addapterHeaderClickListener = new StickyListHeadersAdapterWrapper.OnHeaderClickListener() { + + @Override + public void onHeaderClick(View header, int itemPosition, long headerId) { + if (onHeaderClickListener != null) { + onHeaderClickListener.onHeaderClick( + StickyListHeadersListView.this, header, itemPosition, + headerId, false); + } + } + }; + + private DataSetObserver dataSetChangedObserver = new DataSetObserver() { + @Override + public void onChanged() { + reset(); + } + + @Override + public void onInvalidated() { + reset(); + } + }; + + public StickyListHeadersListView(Context context) { + this(context, null); + } + + public StickyListHeadersListView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.listViewStyle); + } + + public StickyListHeadersListView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + + super.setOnScrollListener(this); + // null out divider, dividers are handled by adapter so they look good + // with headers + super.setDivider(null); + super.setDividerHeight(0); + setVerticalFadingEdgeEnabled(false); + viewConfig = ViewConfiguration.get(context); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if(changed){ + reset(); + } + } + + private void reset() { + headerBottomPosition = 0; + header = null; + currentHeaderId = null; + } + + @Override + public boolean performItemClick(View view, int position, long id) { + if(view instanceof WrapperView){ + view = ((WrapperView) view).item; + } + return super.performItemClick(view, position, id); + } + + /** + * can only be set to false if headers are sticky, not compatible with + * fading edges + */ + @Override + public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { + if (areHeadersSticky) { + super.setVerticalFadingEdgeEnabled(false); + } else { + super.setVerticalFadingEdgeEnabled(verticalFadingEdgeEnabled); + } + } + + @Override + public void setDivider(Drawable divider) { + this.divider = divider; + if(divider != null){ + int dividerDrawableHeight = divider.getIntrinsicHeight(); + if(dividerDrawableHeight>=0){ + setDividerHeight(dividerDrawableHeight); + } + } + if (adapter != null) { + adapter.setDivider(divider); + requestLayout(); + invalidate(); + } + } + + @Override + public void setDividerHeight(int height) { + dividerHeight = height; + if (adapter != null) { + adapter.setDividerHeight(height); + requestLayout(); + invalidate(); + } + } + + @Override + public void setOnScrollListener(OnScrollListener l) { + scrollListener = l; + } + + public void setAreHeadersSticky(boolean areHeadersSticky) { + if (this.areHeadersSticky != areHeadersSticky) { + if (areHeadersSticky) { + super.setVerticalFadingEdgeEnabled(false); + } + requestLayout(); + this.areHeadersSticky = areHeadersSticky; + } + } + + public boolean getAreHeadersSticky() { + return areHeadersSticky; + } + + @Override + public void setAdapter(ListAdapter adapter) { + if (!clipToPaddingHasBeenSet) { + clippingToPadding = true; + } + if (!(adapter instanceof StickyListHeadersAdapter)) { + throw new IllegalArgumentException( + "Adapter must implement StickyListHeadersAdapter"); + } + this.adapter = new StickyListHeadersAdapterWrapper(getContext(), + (StickyListHeadersAdapter) adapter); + this.adapter.setDivider(divider); + this.adapter.setDividerHeight(dividerHeight); + this.adapter.registerDataSetObserver(dataSetChangedObserver); + this.adapter.setOnHeaderClickListener(addapterHeaderClickListener); + reset(); + super.setAdapter(this.adapter); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { + scrollChanged(getFirstVisiblePosition()); + } + super.dispatchDraw(canvas); + if (header == null || !areHeadersSticky) { + return; + } + + int headerHeight = getHeaderHeight(); + int top = headerBottomPosition - headerHeight; + clippingRect.left = getPaddingLeft(); + clippingRect.right = getWidth() - getPaddingRight(); + clippingRect.bottom = top + headerHeight; + if (clippingToPadding) { + clippingRect.top = getPaddingTop(); + } else { + clippingRect.top = 0; + } + + canvas.save(); + canvas.clipRect(clippingRect); + canvas.translate(getPaddingLeft(), top); + header.draw(canvas); + canvas.restore(); + } + + private void measureHeader() { + int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth(), + MeasureSpec.EXACTLY); + int heightMeasureSpec = 0; + + ViewGroup.LayoutParams params = header.getLayoutParams(); + if (params != null && params.height > 0) { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY); + } else { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + header.measure(widthMeasureSpec, heightMeasureSpec); + header.layout(getLeft() + getPaddingLeft(), 0, getRight() + - getPaddingRight(), header.getMeasuredHeight()); + } + + private int getHeaderHeight() { + if (header != null) { + return header.getMeasuredHeight(); + } + return 0; + } + + @Override + public void setClipToPadding(boolean clipToPadding) { + super.setClipToPadding(clipToPadding); + clippingToPadding = clipToPadding; + clipToPaddingHasBeenSet = true; + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + if (scrollListener != null) { + scrollListener.onScroll(view, firstVisibleItem, visibleItemCount, + totalItemCount); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { + scrollChanged(firstVisibleItem); + } + } + + private void scrollChanged(int firstVisibleItem) { + if (adapter == null){ + return; + } + + int adapterCount = adapter.getCount(); + if(adapterCount == 0 || !areHeadersSticky){ + + } + + final int listViewHeaderCount = getHeaderViewsCount(); + firstVisibleItem = getFixedFirstVisibleItem(firstVisibleItem) - listViewHeaderCount; + + if(firstVisibleItem < 0 || firstVisibleItem > adapterCount-1){ + header = null; + currentHeaderId = null; + headerBottomPosition = -1; + updateHeaderVisibilities(); + invalidate(); + return; + } + + long newHeaderId = adapter.getHeaderId(firstVisibleItem); + if (currentHeaderId == null || currentHeaderId != newHeaderId) { + headerPosition = firstVisibleItem; + header = adapter.getHeaderView(headerPosition, header, + this); + measureHeader(); + } + currentHeaderId = newHeaderId; + + int childCount = getChildCount(); + + if (childCount != 0) { + View viewToWatch = null; + int watchingChildDistance = 99999; + boolean viewToWatchIsFooter = false; + + for (int i = 0; i < childCount; i++) { + View child = super.getChildAt(i); + boolean childIsFooter = footerViews != null && footerViews.contains(child); + + int childDistance; + if (clippingToPadding) { + childDistance = child.getTop() - getPaddingTop(); + } else { + childDistance = child.getTop(); + } + + if (childDistance < 0) { + continue; + } + + if (viewToWatch == null + || (!viewToWatchIsFooter && !((WrapperView)viewToWatch).hasHeader()) + || ((childIsFooter || ((WrapperView)child).hasHeader()) && childDistance < watchingChildDistance)) { + viewToWatch = child; + viewToWatchIsFooter = childIsFooter; + watchingChildDistance = childDistance; + } + } + + int headerHeight = getHeaderHeight(); + + if (viewToWatch != null && (viewToWatchIsFooter || ((WrapperView)viewToWatch).hasHeader())) { + + if (firstVisibleItem == listViewHeaderCount && super.getChildAt(0).getTop() > 0 + && !clippingToPadding) { + headerBottomPosition = 0; + } else { + if (clippingToPadding) { + headerBottomPosition = Math.min(viewToWatch.getTop(), + headerHeight + getPaddingTop()); + headerBottomPosition = headerBottomPosition < getPaddingTop() ? headerHeight + + getPaddingTop() + : headerBottomPosition; + } else { + headerBottomPosition = Math.min(viewToWatch.getTop(), + headerHeight); + headerBottomPosition = headerBottomPosition < 0 ? headerHeight + : headerBottomPosition; + } + } + } else { + headerBottomPosition = headerHeight; + if (clippingToPadding) { + headerBottomPosition += getPaddingTop(); + } + } + } + + updateHeaderVisibilities(); + invalidate(); + } + + @Override + public void addFooterView(View v) { + super.addFooterView(v); + if(footerViews == null){ + footerViews = new ArrayList<>(); + } + footerViews.add(v); + } + + @Override + public boolean removeFooterView(View v) { + boolean removed = super.removeFooterView(v); + if(removed){ + footerViews.remove(v); + } + return removed; + } + + private void updateHeaderVisibilities(){ + int top = clippingToPadding ? getPaddingTop() : 0; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = super.getChildAt(i); + if(child instanceof WrapperView){ + WrapperView wrapperViewChild = (WrapperView) child; + if (wrapperViewChild.hasHeader()) { + View childHeader = wrapperViewChild.header; + if (wrapperViewChild.getTop() < top) { + childHeader.setVisibility(View.INVISIBLE); + } else { + childHeader.setVisibility(View.VISIBLE); + } + } + } + } + } + + private int getFixedFirstVisibleItem(int firstVisibleItem) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + return firstVisibleItem; + } + + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i).getBottom() >= 0) { + firstVisibleItem += i; + break; + } + } + + // work around to fix bug with firstVisibleItem being to high because + // listview does not take clipToPadding=false into account + if (!clippingToPadding && getPaddingTop() > 0) { + if (super.getChildAt(0).getTop() > 0) { + if (firstVisibleItem > 0) { + firstVisibleItem -= 1; + } + } + } + return firstVisibleItem; + } + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (scrollListener != null) { + scrollListener.onScrollStateChanged(view, scrollState); + } + } + + @Override + public void setSelectionFromTop(int position, int y) { + if (areHeadersSticky) { + y += getHeaderHeight(); + } + super.setSelectionFromTop(position, y); + } + + public void setOnHeaderClickListener( + OnHeaderClickListener onHeaderClickListener) { + this.onHeaderClickListener = onHeaderClickListener; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + int action = ev.getAction(); + if (action == MotionEvent.ACTION_DOWN + && ev.getY() <= headerBottomPosition) { + headerDownY = ev.getY(); + headerBeingPressed = true; + header.setPressed(true); + header.invalidate(); + invalidate(0, 0, getWidth(), headerBottomPosition); + return true; + } + if (headerBeingPressed) { + if (Math.abs(ev.getY() - headerDownY) < viewConfig + .getScaledTouchSlop()) { + if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_CANCEL) { + headerDownY = -1; + headerBeingPressed = false; + header.setPressed(false); + header.invalidate(); + invalidate(0, 0, getWidth(), headerBottomPosition); + if (onHeaderClickListener != null) { + onHeaderClickListener.onHeaderClick(this, header, + headerPosition, currentHeaderId, true); + } + } + return true; + } else { + headerDownY = -1; + headerBeingPressed = false; + header.setPressed(false); + header.invalidate(); + invalidate(0, 0, getWidth(), headerBottomPosition); + } + } + return super.onTouchEvent(ev); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/WrapperView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/WrapperView.java new file mode 100644 index 0000000..1683161 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/sticky/stickylistheaders/WrapperView.java @@ -0,0 +1,125 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickylistheaders; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +class WrapperView extends ViewGroup { + + View item; + Drawable divider; + int dividerHeight; + View header; + + public WrapperView(Context c) { + super(c); + } + + void update(View item, View header, Drawable divider, int dividerHeight) { + if (item == null) { + throw new NullPointerException("List view item must not be null."); + } + + if (this.item != item) { + removeView(this.item); + this.item = item; + final ViewParent parent = item.getParent(); + if(parent != null && parent != this) { + if(parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(item); + } + } + addView(item); + } + + if (this.header != header) { + if (this.header != null) { + removeView(this.header); + } + this.header = header; + if (header != null) { + addView(header); + } + } + + if (this.divider != divider) { + this.divider = divider; + this.dividerHeight = dividerHeight; + invalidate(); + } + } + + boolean hasHeader() { + return header != null; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int measuredWidth = MeasureSpec.getSize(widthMeasureSpec); + int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth, + MeasureSpec.EXACTLY); + int measuredHeight = 0; + if (header != null) { + LayoutParams params = header.getLayoutParams(); + if (params != null && params.height > 0) { + header.measure(childWidthMeasureSpec, + MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY)); + } else { + header.measure(childWidthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + } + measuredHeight += header.getMeasuredHeight(); + } else if (divider != null) { + measuredHeight += dividerHeight; + } + LayoutParams params = item.getLayoutParams(); + if (params != null && params.height > 0) { + item.measure(childWidthMeasureSpec, + MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY)); + } else { + item.measure(childWidthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + } + measuredHeight += item.getMeasuredHeight(); + + setMeasuredDimension(measuredWidth, measuredHeight); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + + // don't really know why these values aren't what i want them to be from + // the start + l = 0; + t = 0; + r = getWidth(); + b = getHeight(); + + if (header != null) { + header.layout(l, t, r, header.getMeasuredHeight()); + item.layout(l, header.getMeasuredHeight(), r, b); + } else if (divider != null) { + divider.setBounds(l, t, r, dividerHeight); + item.layout(l, dividerHeight, r, b); + } else { + item.layout(l, t, r, b); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (header == null && divider != null) { + // Drawable.setBounds() does not seem to work pre-honeycomb. So have + // to do this instead + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + canvas.clipRect(0, 0, getWidth(), dividerHeight); + } + divider.draw(canvas); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SimpleSwipeListener.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SimpleSwipeListener.java new file mode 100644 index 0000000..96fe49b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SimpleSwipeListener.java @@ -0,0 +1,28 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.swipe; + +public class SimpleSwipeListener implements SwipeLayout.SwipeListener { + + @Override + public void onStartOpen(SwipeLayout layout) { + } + + @Override + public void onOpen(SwipeLayout layout) { + } + + @Override + public void onStartClose(SwipeLayout layout) { + } + + @Override + public void onClose(SwipeLayout layout) { + } + + @Override + public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset) { + } + + @Override + public void onHandRelease(SwipeLayout layout, float xvel, float yvel) { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SwipeLayout.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SwipeLayout.java new file mode 100644 index 0000000..9757edd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/SwipeLayout.java @@ -0,0 +1,1305 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.swipe; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.support.v4.view.ViewCompat; +import android.support.v4.widget.ViewDragHelper; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.Adapter; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.ListAdapter; + +import com.mm.android.deviceaddmodule.R; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressLint("WrongCall") public class SwipeLayout extends FrameLayout { + + private ViewDragHelper mDragHelper; + + private int mDragDistance = 0; + private DragEdge mDragEdge; + private ShowMode mShowMode; + + private List mSwipeListeners = new ArrayList<>(); + private List mSwipeDeniers = new ArrayList<>(); + private Map> mRevealListeners = new HashMap<>(); + private Map mShowEntirely = new HashMap<>(); + + private DoubleClickListener mDoubleClickListener; + + private boolean mSwipeEnabled = true; + + public static enum DragEdge { + Left, + Right, + Top, + Bottom; + }; + + public static enum ShowMode { + LayDown, PullOut + } + + + public SwipeLayout(Context context) { + this(context, null); + } + + public SwipeLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mDragHelper = ViewDragHelper.create(this, mDragHelperCallback); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeLayout); + int ordinal = a.getInt(R.styleable.SwipeLayout_drag_edge, DragEdge.Right.ordinal()); + mDragEdge = DragEdge.values()[ordinal]; + ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal()); + mShowMode = ShowMode.values()[ordinal]; + a.recycle(); + } + + + public interface SwipeListener{ + public void onStartOpen(SwipeLayout layout); + public void onOpen(SwipeLayout layout); + public void onStartClose(SwipeLayout layout); + public void onClose(SwipeLayout layout); + public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset); + public void onHandRelease(SwipeLayout layout, float xvel, float yvel); + } + + public void addSwipeListener(SwipeListener l){ + mSwipeListeners.add(l); + } + + public void removeSwipeListener(SwipeListener l){ + mSwipeListeners.remove(l); + } + + public static interface SwipeDenier { + /* + * Called in onInterceptTouchEvent + * Determines if this swipe event should be denied + * Implement this interface if you are using views with swipe gestures + * As a child of SwipeLayout + * + * @return true deny + * false allow + */ + public boolean shouldDenySwipe(MotionEvent ev); + } + + public void addSwipeDenier(SwipeDenier denier) { + mSwipeDeniers.add(denier); + } + + public void removeSwipeDenier(SwipeDenier denier) { + mSwipeDeniers.remove(denier); + } + + public void removeAllSwipeDeniers() { + mSwipeDeniers.clear(); + } + + public interface OnRevealListener { + public void onReveal(View child, DragEdge edge, float fraction, int distance); + } + + /** + * bind a view with a specific {@link OnRevealListener} + * @param childId the view id. + * @param l the target {@link OnRevealListener} + */ + public void addRevealListener(int childId, OnRevealListener l){ + View child = findViewById(childId); + if(child == null){ + throw new IllegalArgumentException("Child does not belong to SwipeListener."); + } + + if(!mShowEntirely.containsKey(child)){ + mShowEntirely.put(child, false); + } + if(mRevealListeners.get(child) == null) + mRevealListeners.put(child, new ArrayList()); + + mRevealListeners.get(child).add(l); + } + + /** + * bind multiple views with an {@link OnRevealListener}. + * @param childIds the view id. + * @param l the {@link OnRevealListener} + */ + public void addRevealListener(int[] childIds, OnRevealListener l){ + for(int i : childIds) + addRevealListener(i, l); + } + + public void removeRevealListener(int childId, OnRevealListener l){ + View child = findViewById(childId); + + if(child == null) + return; + + mShowEntirely.remove(child); + if(mRevealListeners.containsKey(child)) + mRevealListeners.get(child).remove(l); + } + + public void removeAllRevealListeners(int childId){ + View child = findViewById(childId); + if(child != null){ + mRevealListeners.remove(child); + mShowEntirely.remove(child); + } + } + + private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() { + + @Override + public int clampViewPositionHorizontal(View child, int left, int dx) { + if(child == getSurfaceView()){ + switch (mDragEdge){ + case Top: + case Bottom: + return getPaddingLeft(); + case Left: + if(left < getPaddingLeft()) + return getPaddingLeft(); + if(left > getPaddingLeft() + mDragDistance) + return getPaddingLeft() + mDragDistance; + break; + case Right: + if(left > getPaddingLeft()) + return getPaddingLeft(); + if(left < getPaddingLeft() - mDragDistance) + return getPaddingLeft() - mDragDistance; + break; + } + }else if(child == getBottomView()){ + + switch (mDragEdge){ + case Top: + case Bottom: + return getPaddingLeft(); + case Left: + if(mShowMode == ShowMode.PullOut){ + if(left > getPaddingLeft()) + return getPaddingLeft(); + } + break; + case Right: + if(mShowMode == ShowMode.PullOut){ + if(left < getMeasuredWidth() - mDragDistance){ + return getMeasuredWidth() - mDragDistance; + } + } + break; + } + } + return left; + } + + @Override + public int clampViewPositionVertical(View child, int top, int dy) { + if(child == getSurfaceView()){ + switch (mDragEdge){ + case Left: + case Right: + return getPaddingTop(); + case Top: + if(top < getPaddingTop()) + return getPaddingTop(); + if(top > getPaddingTop() + mDragDistance) + return getPaddingTop() + mDragDistance; + break; + case Bottom: + if(top < getPaddingTop() - mDragDistance){ + return getPaddingTop() - mDragDistance; + } + if(top > getPaddingTop()){ + return getPaddingTop(); + } + } + }else{ + switch (mDragEdge){ + case Left: + case Right: + return getPaddingTop(); + case Top: + if(mShowMode == ShowMode.PullOut){ + if(top > getPaddingTop()) + return getPaddingTop(); + }else{ + if(getSurfaceView().getTop() + dy < getPaddingTop()) + return getPaddingTop(); + if(getSurfaceView().getTop() + dy > getPaddingTop() + mDragDistance) + return getPaddingTop() + mDragDistance; + } + break; + case Bottom: + if(mShowMode == ShowMode.PullOut){ + if(top < getMeasuredHeight() - mDragDistance) + return getMeasuredHeight() - mDragDistance; + }else{ + if(getSurfaceView().getTop() + dy >= getPaddingTop()) + return getPaddingTop(); + if(getSurfaceView().getTop() + dy <= getPaddingTop() - mDragDistance) + return getPaddingTop() - mDragDistance; + } + } + } + return top; + } + + @Override + public boolean tryCaptureView(View child, int pointerId) { + return child == getSurfaceView() || child == getBottomView(); + } + + @Override + public int getViewHorizontalDragRange(View child) { + return mDragDistance; + } + + @Override + public int getViewVerticalDragRange(View child) { + return mDragDistance; + } + + @Override + public void onViewReleased(View releasedChild, float xvel, float yvel) { + super.onViewReleased(releasedChild, xvel, yvel); + for(SwipeListener l : mSwipeListeners) + l.onHandRelease(SwipeLayout.this, xvel, yvel); + if(releasedChild == getSurfaceView()){ + processSurfaceRelease(xvel, yvel); + }else if(releasedChild == getBottomView()){ + if(getShowMode() == ShowMode.PullOut){ + processBottomPullOutRelease(xvel, yvel); + }else if(getShowMode() == ShowMode.LayDown){ + processBottomLayDownMode(xvel, yvel); + } + } + + invalidate(); + } + + @Override + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { + int evLeft = getSurfaceView().getLeft(), evRight = getSurfaceView().getRight(), + evTop = getSurfaceView().getTop(),evBottom = getSurfaceView().getBottom(); + if(changedView == getSurfaceView()){ + + if(mShowMode == ShowMode.PullOut){ + if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) + getBottomView().offsetLeftAndRight(dx); + else + getBottomView().offsetTopAndBottom(dy); + } + + }else if(changedView == getBottomView()){ + + if(mShowMode == ShowMode.PullOut){ + getSurfaceView().offsetLeftAndRight(dx); + getSurfaceView().offsetTopAndBottom(dy); + }else{ + Rect rect = computeBottomLayDown(mDragEdge); + getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + + int newLeft = getSurfaceView().getLeft() + dx, newTop = getSurfaceView().getTop() + dy; + + if(mDragEdge == DragEdge.Left && newLeft < getPaddingLeft()) newLeft = getPaddingLeft(); + else if(mDragEdge == DragEdge.Right && newLeft > getPaddingLeft()) newLeft = getPaddingLeft(); + else if(mDragEdge == DragEdge.Top && newTop < getPaddingTop()) newTop = getPaddingTop(); + else if(mDragEdge == DragEdge.Bottom && newTop > getPaddingTop()) newTop = getPaddingTop(); + + getSurfaceView().layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight()); + } + } + + dispatchRevealEvent(evLeft, evTop, evRight, evBottom); + + dispatchSwipeEvent(evLeft, evTop, dx, dy); + + invalidate(); + } + }; + + /** + * the dispatchRevealEvent method may not always get accurate position, it makes the view may not always get the event when the view is + * totally show( fraction = 1), so , we need to calculate every time. + * @param child + * @param relativePosition + * @param edge + * @param surfaceLeft + * @param surfaceTop + * @param surfaceRight + * @param surfaceBottom + * @return + */ + protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft, int surfaceTop, int surfaceRight, int surfaceBottom){ + if(mShowEntirely.get(child)) + return false; + int childLeft = relativePosition.left; + int childRight = relativePosition.right; + int childTop = relativePosition.top; + int childBottom = relativePosition.bottom; + boolean r = false; + if(getShowMode() == ShowMode.LayDown) { + if((edge == DragEdge.Right && surfaceRight <= childLeft) + || (edge == DragEdge.Left && surfaceLeft >= childRight) + || (edge == DragEdge.Top && surfaceTop >= childBottom) + || (edge == DragEdge.Bottom && surfaceBottom <= childTop)) + r = true; + } + else if(getShowMode() == ShowMode.PullOut){ + if((edge == DragEdge.Right && childRight <= getWidth()) + || (edge == DragEdge.Left && childLeft >= getPaddingLeft()) + || (edge == DragEdge.Top && childTop >= getPaddingTop()) + || (edge == DragEdge.Bottom && childBottom <= getHeight())) + r = true; + } + return r; + } + + protected boolean isViewShowing(View child, Rect relativePosition, DragEdge availableEdge, int surfaceLeft, int surfaceTop, int surfaceRight, int surfaceBottom){ + int childLeft = relativePosition.left; + int childRight = relativePosition.right; + int childTop = relativePosition.top; + int childBottom = relativePosition.bottom; + if(getShowMode() == ShowMode.LayDown){ + switch (availableEdge){ + case Right: + if(surfaceRight > childLeft && surfaceRight <= childRight){ + return true; + } + break; + case Left: + if(surfaceLeft < childRight && surfaceLeft >= childLeft){ + return true; + } + break; + case Top: + if(surfaceTop >= childTop && surfaceTop < childBottom){ + return true; + } + break; + case Bottom: + if(surfaceBottom > childTop && surfaceBottom <= childBottom){ + return true; + } + break; + } + }else if(getShowMode() == ShowMode.PullOut){ + switch (availableEdge){ + case Right: + if(childLeft <= getWidth() && childRight > getWidth()) + return true; + break; + case Left: + if(childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) + return true; + break; + case Top: + if(childTop < getPaddingTop() && childBottom >= getPaddingTop()) + return true; + break; + case Bottom: + if(childTop < getHeight() && childTop >= getPaddingTop()) + return true; + break; + } + } + return false; + } + + + + protected Rect getRelativePosition(View child){ + View t = child; + Rect r = new Rect(t.getLeft(), t.getTop(), 0 , 0); + while(t.getParent() != null && t != getRootView()){ + t = (View)t.getParent(); + if(t == this) + break; + r.left += t.getLeft(); + r.top += t.getTop(); + } + r.right = r.left + child.getMeasuredWidth(); + r.bottom = r.top + child.getMeasuredHeight(); + return r; + } + + private int mEventCounter = 0; + + protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx, int dy){ + DragEdge edge = getDragEdge(); + boolean open = true; + if(edge == DragEdge.Left){ + if(dx < 0) open = false; + }else if(edge == DragEdge.Right){ + if(dx > 0) open = false; + }else if(edge == DragEdge.Top){ + if(dy < 0) open = false; + }else if(edge == DragEdge.Bottom){ + if(dy > 0) open = false; + } + + dispatchSwipeEvent(surfaceLeft, surfaceTop, open); + } + + protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open){ + safeBottomView(); + Status status = getOpenStatus(); + + if(!mSwipeListeners.isEmpty()){ + mEventCounter++; + for(SwipeListener l : mSwipeListeners){ + if(mEventCounter == 1){ + if(open){ + l.onStartOpen(this); + }else{ + l.onStartClose(this); + } + } + l.onUpdate(SwipeLayout.this, surfaceLeft - getPaddingLeft(), surfaceTop - getPaddingTop()); + } + + if(status == Status.Close){ + for(SwipeListener l : mSwipeListeners){ + l.onClose(SwipeLayout.this); + } + mEventCounter = 0; + } + + if(status == Status.Open){ + getBottomView().setEnabled(true); + for(SwipeListener l : mSwipeListeners){ + l.onOpen(SwipeLayout.this); + } + mEventCounter = 0; + } + } + } + + /** + * prevent bottom view get any touch event. Especially in LayDown mode. + */ + private void safeBottomView(){ + Status status = getOpenStatus(); + ViewGroup bottom = getBottomView(); + + if(status == Status.Close){ + if(bottom.getVisibility() != INVISIBLE) + bottom.setVisibility(INVISIBLE); + }else { + if(bottom.getVisibility() != VISIBLE) + bottom.setVisibility(VISIBLE); + } + } + + + protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight, final int surfaceBottom){ + if(mRevealListeners.isEmpty()) return; + for(Map.Entry> entry : mRevealListeners.entrySet()){ + View child = entry.getKey(); + Rect rect = getRelativePosition(child); + if(isViewShowing(child,rect, mDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)){ + mShowEntirely.put(child, false); + int distance = 0; + float fraction = 0f; + if(getShowMode() == ShowMode.LayDown){ + switch (mDragEdge){ + case Left: + distance = rect.left - surfaceLeft; + fraction = distance/(float)child.getWidth(); + break; + case Right: + distance = rect.right - surfaceRight; + fraction = distance/(float)child.getWidth(); + break; + case Top: + distance = rect.top - surfaceTop; + fraction = distance/(float)child.getHeight(); + break; + case Bottom: + distance = rect.bottom - surfaceBottom; + fraction = distance/(float)child.getHeight(); + break; + } + }else if(getShowMode() == ShowMode.PullOut){ + switch (mDragEdge){ + case Left: + distance = rect.right - getPaddingLeft(); + fraction = distance / (float)child.getWidth(); + break; + case Right: + distance = rect.left - getWidth(); + fraction = distance / (float)child.getWidth(); + break; + case Top: + distance = rect.bottom - getPaddingTop(); + fraction = distance/(float)child.getHeight(); + break; + case Bottom: + distance = rect.top - getHeight(); + fraction = distance/(float)child.getHeight(); + break; + } + } + + for(OnRevealListener l : entry.getValue()){ + l.onReveal(child, mDragEdge, Math.abs(fraction), distance); + if(Math.abs(fraction) == 1){ + mShowEntirely.put(child, true); + } + } + } + + if(isViewTotallyFirstShowed(child, rect, mDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)){ + mShowEntirely.put(child, true); + for(OnRevealListener l : entry.getValue()){ + if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) + l.onReveal(child, mDragEdge, 1, child.getWidth()); + else + l.onReveal(child, mDragEdge, 1, child.getHeight()); + } + } + + } + } + + @Override + public void computeScroll() { + super.computeScroll(); + if(mDragHelper.continueSettling(true)) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + /** + * {@link OnLayoutChangeListener} added in API 11. + * I need to support it from API 8. + */ + public interface OnLayout{ + public void onLayout(SwipeLayout v); + } + + private List mOnLayoutListeners; + + public void addOnLayoutListener(OnLayout l){ + if(mOnLayoutListeners == null) + mOnLayoutListeners = new ArrayList<>(); + mOnLayoutListeners.add(l); + } + + public void removeOnLayoutListener(OnLayout l){ + if(mOnLayoutListeners != null) + mOnLayoutListeners.remove(l); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int childCount = getChildCount(); + if(childCount != 2){ + throw new IllegalStateException("You need 2 views in SwipeLayout"); + } + if(!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)){ + throw new IllegalArgumentException("The 2 children in SwipeLayout must be an instance of ViewGroup"); + } + + if(mShowMode == ShowMode.PullOut) + layoutPullOut(); + else if(mShowMode == ShowMode.LayDown) + layoutLayDown(); + + safeBottomView(); + + if(mOnLayoutListeners != null) + for(int i = 0; i < mOnLayoutListeners.size(); i++){ + mOnLayoutListeners.get(i).onLayout(this); + } + + } + + void layoutPullOut(){ + Rect rect = computeSurfaceLayoutArea(false); + getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); + rect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect); + getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + bringChildToFront(getSurfaceView()); + } + + void layoutLayDown(){ + Rect rect = computeSurfaceLayoutArea(false); + getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); + rect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, rect); + getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + bringChildToFront(getSurfaceView()); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) + mDragDistance = getBottomView().getMeasuredWidth(); + else + mDragDistance = getBottomView().getMeasuredHeight(); + } + + private boolean mTouchConsumedByChild = false; + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + + if(!isEnabled() || !isEnabledInAdapterView()){ + return true; + } + + if(!isSwipeEnabled()){ + return false; + } + + for (SwipeDenier denier : mSwipeDeniers) { + if (denier != null && denier.shouldDenySwipe(ev)) { + return false; + } + } + // + //if a child wants to handle the touch event, + //then let it do it. + // + int action = ev.getActionMasked(); + switch (action){ + case MotionEvent.ACTION_DOWN: + Status status = getOpenStatus(); + if(status == Status.Close){ + mTouchConsumedByChild = childNeedHandleTouchEvent(getSurfaceView(), ev) != null; + }else if(status == Status.Open){ + mTouchConsumedByChild = childNeedHandleTouchEvent(getBottomView(), ev) != null; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mTouchConsumedByChild = false; + } + + if(mTouchConsumedByChild) return false; + return mDragHelper.shouldInterceptTouchEvent(ev); + } + + /** + * if the ViewGroup children want to handle this event. + * @param v + * @param event + * @return + */ + private View childNeedHandleTouchEvent(ViewGroup v, MotionEvent event){ + if(v == null) return null; + if(v.onTouchEvent(event)) + return v; + + int childCount = v.getChildCount(); + for(int i = childCount - 1; i >= 0; i--){ + View child = v.getChildAt(i); + if(child instanceof ViewGroup){ + View grandChild = childNeedHandleTouchEvent((ViewGroup) child, event); + if(grandChild != null) + return grandChild; + }else{ + if(childNeedHandleTouchEvent(v.getChildAt(i), event)) + return v.getChildAt(i); + } + } + return null; + } + + /** + * if the view (v) wants to handle this event. + * @param v + * @param event + * @return + */ + private boolean childNeedHandleTouchEvent(View v, MotionEvent event){ + if(v == null) return false; + + int[] loc = new int[2]; + v.getLocationOnScreen(loc); + int left = loc[0], top = loc[1]; + + if(event.getRawX() > left && event.getRawX() < left + v.getWidth() + && event.getRawY() > top && event.getRawY() < top + v.getHeight()){ + return v.onTouchEvent(event); + } + + return false; + } + + private float sX = -1 , sY = -1; + @Override + public boolean onTouchEvent(MotionEvent event) { + if(!isEnabledInAdapterView() || !isEnabled()) + return true; + + if(!isSwipeEnabled()) + return super.onTouchEvent(event); + + int action = event.getActionMasked(); + ViewParent parent = getParent(); + if(parent == null) + return true; + gestureDetector.onTouchEvent(event); + Status status = getOpenStatus(); + ViewGroup touching = null; + if(status == Status.Close){ + touching = getSurfaceView(); + }else if(status == Status.Open){ + touching = getBottomView(); + } + + switch (action){ + case MotionEvent.ACTION_DOWN: + mDragHelper.processTouchEvent(event); + parent.requestDisallowInterceptTouchEvent(true); + + sX = event.getRawX(); + sY = event.getRawY(); + + if(touching != null) + touching.setPressed(true); + + return true; + case MotionEvent.ACTION_MOVE:{ + if(sX == -1 || sY == -1){ + // Trick: + // When in nested mode, we need to send a constructed ACTION_DOWN MotionEvent to mDragHelper, to help + // it initialize itself. + event.setAction(MotionEvent.ACTION_DOWN); + mDragHelper.processTouchEvent(event); + parent.requestDisallowInterceptTouchEvent(true); + sX = event.getRawX(); + sY = event.getRawY(); + return true; + } + + float distanceX = event.getRawX() - sX; + float distanceY = event.getRawY() - sY; + float angle = Math.abs(distanceY / distanceX); + angle = (float)Math.toDegrees(Math.atan(angle)); + + boolean doNothing = false; + if(mDragEdge == DragEdge.Right){ + boolean suitable = (status == Status.Open && distanceX > 0) || (status == Status.Close && distanceX < 0); + suitable = suitable || (status == Status.Middle); + + if(angle > 20 || !suitable){ + doNothing = true; + } + } + + if(mDragEdge == DragEdge.Left){ + boolean suitable = (status == Status.Open && distanceX < 0 ) || (status == Status.Close && distanceX > 0); + suitable = suitable || status == Status.Middle; + + if(angle > 30 || ! suitable){ + doNothing = true; + } + } + + if(mDragEdge == DragEdge.Top){ + boolean suitable = (status == Status.Open && distanceY < 0 ) || (status == Status.Close && distanceY > 0); + suitable = suitable || status == Status.Middle; + + if(angle < 60 || ! suitable){ + doNothing = true; + } + } + + if(mDragEdge == DragEdge.Bottom){ + boolean suitable = (status == Status.Open && distanceY > 0 ) || (status == Status.Close && distanceY < 0); + suitable = suitable || status == Status.Middle; + + if(angle < 60 || ! suitable){ + doNothing = true; + } + } + + if(doNothing){ + parent.requestDisallowInterceptTouchEvent(false); + return false; + }else{ + if(touching != null){ + touching.setPressed(false); + } + parent.requestDisallowInterceptTouchEvent(true); + mDragHelper.processTouchEvent(event); + } + break; + } + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + sX = -1; + sY = -1; + if (touching != null) { + touching.setPressed(false); + } + + parent.requestDisallowInterceptTouchEvent(true); + mDragHelper.processTouchEvent(event); + break; + default: + parent.requestDisallowInterceptTouchEvent(true); + mDragHelper.processTouchEvent(event); + } + + return true; + } + + /** + * if working in {@link AdapterView}, we should response {@link Adapter} + * isEnable(int position). + * @return true when item is enabled, else disabled. + */ + private boolean isEnabledInAdapterView(){ + AdapterView adapterView = getAdapterView(); + boolean enable = true; + if(adapterView != null){ + Adapter adapter = adapterView.getAdapter(); + if(adapter != null){ + int p = adapterView.getPositionForView(SwipeLayout.this); + if(p >= 0){ + if(adapter instanceof BaseAdapter){ + enable = ((BaseAdapter) adapter).isEnabled(p); + }else if(adapter instanceof ListAdapter){ + enable = ((ListAdapter) adapter).isEnabled(p); + } + } + } + } + return enable; + } + + public void setSwipeEnabled(boolean enabled){ + mSwipeEnabled = enabled; + } + + public boolean isSwipeEnabled(){ + return mSwipeEnabled; + } + + private boolean insideAdapterView(){ + return getAdapterView() != null; + } + + private AdapterView getAdapterView(){ + ViewParent t = getParent(); + while(t != null){ + if(t instanceof AdapterView){ + return (AdapterView)t; + } + t = t.getParent(); + } + return null; + } + + private void performAdapterViewItemClick(MotionEvent e){ + ViewParent t = getParent(); + while(t != null) { + if(t instanceof AdapterView){ + AdapterView view = (AdapterView)t; + int p = view.getPositionForView(SwipeLayout.this); + if( p != AdapterView.INVALID_POSITION && + view.performItemClick(view.getChildAt(p), p, view.getAdapter().getItemId(p))) + return; + }else{ + if(t instanceof View && ((View) t).performClick()) + return; + } + t = t.getParent(); + } + } + + private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector()); + class SwipeDetector extends GestureDetector.SimpleOnGestureListener{ + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + /** + * Simulate the touch event lifecycle. If you use SwipeLayout in {@link AdapterView} + * ({@link android.widget.ListView}, {@link android.widget.GridView} etc.) It will manually call + * {@link AdapterView}.performItemClick, performItemLongClick. + * @param e + * @return + */ + @Override + public boolean onSingleTapUp(MotionEvent e) { + if(mDoubleClickListener == null){ + performAdapterViewItemClick(e); + } + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if(mDoubleClickListener != null){ + performAdapterViewItemClick(e); + } + return true; + } + + @Override + public void onLongPress(MotionEvent e) { + //fixme getparent == null 导致崩溃 +// performLongClick(); + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + if(mDoubleClickListener != null){ + View target; + ViewGroup bottom = getBottomView(); + ViewGroup surface = getSurfaceView(); + if(e.getX() > bottom.getLeft() && e.getX() < bottom.getRight() + && e.getY() > bottom.getTop() && e.getY() < bottom.getBottom()){ + target = bottom; + }else{ + target = surface; + } + mDoubleClickListener.onDoubleClick(SwipeLayout.this, target == surface); + } + return true; + } + } + + public void setDragEdge(DragEdge dragEdge){ + mDragEdge = dragEdge; + requestLayout(); + } + + /** + * set the drag distance, it will force set the bottom view's width or height via this value. + * @param max + */ + public void setDragDistance(int max){ + if(max < 0) + throw new IllegalArgumentException("Drag distance can not be < 0"); + mDragDistance = dp2px(max); + requestLayout(); + } + + /** + * There are 2 diffirent show mode. + * {@link ShowMode}.PullOut and {@link ShowMode}.LayDown. + * @param mode + */ + public void setShowMode(ShowMode mode){ + mShowMode = mode; + requestLayout(); + } + + public DragEdge getDragEdge(){ + return mDragEdge; + } + + public int getDragDistance(){ + return mDragDistance; + } + + public ShowMode getShowMode(){ + return mShowMode; + } + + public ViewGroup getSurfaceView(){ + return (ViewGroup)getChildAt(1); + } + + public ViewGroup getBottomView(){ + return (ViewGroup)getChildAt(0); + } + + public enum Status { + Middle , Open, Close + } + + /** + * get the open status. + * @return {@link Status} + * Open , Close or Middle. + */ + public Status getOpenStatus(){ + int surfaceLeft = getSurfaceView().getLeft(); + int surfaceTop = getSurfaceView().getTop(); + if(surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) + return Status.Close; + + if(surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance) + || surfaceTop == (getPaddingTop() - mDragDistance) || surfaceTop == (getPaddingTop() + mDragDistance)) + return Status.Open; + + return Status.Middle; + } + + /** + * Process the surface release event. + * @param xvel + * @param yvel + */ + private void processSurfaceRelease(float xvel, float yvel){ + if(xvel == 0 && getOpenStatus() == Status.Middle) + close(); + + if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right){ + if(xvel > 0){ + if(mDragEdge == DragEdge.Left) open(); + else close(); + } + if(xvel < 0){ + if(mDragEdge == DragEdge.Left) close(); + else open(); + } + }else{ + if(yvel > 0){ + if(mDragEdge == DragEdge.Top) open(); + else close(); + } + if(yvel < 0){ + if(mDragEdge == DragEdge.Top) close(); + else open(); + } + } + } + + /** + * process bottom (PullOut mode) hand release event. + * @param xvel + * @param yvel + */ + private void processBottomPullOutRelease(float xvel, float yvel){ + + if(xvel == 0 && getOpenStatus() == Status.Middle) + close(); + + if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right){ + if(xvel > 0){ + if(mDragEdge == DragEdge.Left) open(); + else close(); + } + if(xvel < 0){ + if(mDragEdge == DragEdge.Left) close(); + else open(); + } + }else{ + if(yvel > 0) { + if (mDragEdge == DragEdge.Top) open(); + else close(); + } + + if(yvel < 0){ + if(mDragEdge == DragEdge.Top) close(); + else open(); + } + } + } + + /** + * process bottom (LayDown mode) hand release event. + * @param xvel + * @param yvel + */ + private void processBottomLayDownMode(float xvel, float yvel){ + + if(xvel == 0 && getOpenStatus() == Status.Middle) + close(); + + int l = getPaddingLeft(), t = getPaddingTop(); + + if(xvel < 0 && mDragEdge == DragEdge.Right) l -= mDragDistance; + if(xvel > 0 && mDragEdge == DragEdge.Left) l += mDragDistance; + + if(yvel > 0 && mDragEdge == DragEdge.Top) t += mDragDistance; + if(yvel < 0 && mDragEdge == DragEdge.Bottom) t -= mDragDistance; + + mDragHelper.smoothSlideViewTo(getSurfaceView(), l, t); + invalidate(); + } + + /** + * smoothly open surface. + */ + public void open(){ + open(true, true); + } + + public void open(boolean smooth){ + open(smooth, true); + } + + public void open(boolean smooth, boolean notify){ + ViewGroup surface = getSurfaceView(), bottom = getBottomView(); + int dx,dy; + Rect rect = computeSurfaceLayoutArea(true); + if(smooth) { + mDragHelper.smoothSlideViewTo(getSurfaceView(), rect.left, rect.top); + } + else{ + dx = rect.left - surface.getLeft(); + dy = rect.top - surface.getTop(); + surface.layout(rect.left, rect.top, rect.right, rect.bottom); + if(getShowMode() == ShowMode.PullOut){ + Rect bRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect); + bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom); + } + if(notify) { + dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom); + dispatchSwipeEvent(rect.left, rect.top, dx, dy); + }else{ + safeBottomView(); + } + } + invalidate(); + } + + /** + * smoothly close surface. + */ + public void close(){ + close(true, true); + } + + public void close(boolean smooth){ + close(smooth, true); + } + + /** + * close surface + * @param smooth smoothly or not. + * @param notify if notify all the listeners. + */ + public void close(boolean smooth, boolean notify){ + ViewGroup surface = getSurfaceView(); + int dx, dy; + if(smooth) + mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(), getPaddingTop()); + else { + Rect rect = computeSurfaceLayoutArea(false); + dx = rect.left - surface.getLeft(); + dy = rect.top - surface.getTop(); + surface.layout(rect.left, rect.top, rect.right, rect.bottom); + if(notify) { + dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom); + dispatchSwipeEvent(rect.left, rect.top, dx, dy); + }else{ + safeBottomView(); + } + } + invalidate(); + } + + public void toggle(){ + toggle(true); + } + + public void toggle(boolean smooth){ + if(getOpenStatus() == Status.Open) + close(smooth); + else if(getOpenStatus() == Status.Close) + open(smooth); + } + + /** + * a helper function to compute the Rect area that surface will hold in. + * @param open open status or close status. + * @return + */ + private Rect computeSurfaceLayoutArea(boolean open){ + int l = getPaddingLeft(), t = getPaddingTop(); + if(open){ + if(mDragEdge == DragEdge.Left) l = getPaddingLeft() + mDragDistance; + else if(mDragEdge == DragEdge.Right) l = getPaddingLeft() - mDragDistance; + else if(mDragEdge == DragEdge.Top) t = getPaddingTop() + mDragDistance; + else t = getPaddingTop() - mDragDistance; + } + return new Rect(l, t, l + getMeasuredWidth(), t + getMeasuredHeight()); + } + + + private Rect computeBottomLayoutAreaViaSurface(ShowMode mode, Rect surfaceArea){ + Rect rect = surfaceArea; + + int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom; + if(mode == ShowMode.PullOut){ + if (mDragEdge == DragEdge.Left) bl = rect.left - mDragDistance; + else if (mDragEdge == DragEdge.Right) bl = rect.right; + else if (mDragEdge == DragEdge.Top) bt = rect.top - mDragDistance; + else bt = rect.bottom; + + if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) { + bb = rect.bottom; + br = bl + getBottomView().getMeasuredWidth(); + } else { + bb = bt + getBottomView().getMeasuredHeight(); + br = rect.right; + } + }else if(mode == ShowMode.LayDown){ + if(mDragEdge == DragEdge.Left) br = bl + mDragDistance; + else if(mDragEdge == DragEdge.Right) bl = br - mDragDistance; + else if(mDragEdge == DragEdge.Top) bb = bt + mDragDistance; + else bt = bb - mDragDistance; + + } + return new Rect(bl, bt, br, bb); + + + } + + private Rect computeBottomLayDown(DragEdge dragEdge){ + int bl = getPaddingLeft(), bt = getPaddingTop(); + int br, bb; + if(dragEdge == DragEdge.Right){ + bl = getMeasuredWidth() - mDragDistance; + }else if(dragEdge == DragEdge.Bottom){ + bt = getMeasuredHeight() - mDragDistance; + } + if(dragEdge == DragEdge.Left || dragEdge == DragEdge.Right){ + br = bl + mDragDistance; + bb = bt + getMeasuredHeight(); + }else{ + br = bl + getMeasuredWidth(); + bb = bt + mDragDistance; + } + return new Rect(bl, bt, br, bb); + } + + public void setOnDoubleClickListener(DoubleClickListener doubleClickListener){ + mDoubleClickListener = doubleClickListener; + } + + public interface DoubleClickListener { + public void onDoubleClick(SwipeLayout layout, boolean surface); + } + + private int dp2px(float dp){ + return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/implments/SwipeItemMangerImpl.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/implments/SwipeItemMangerImpl.java new file mode 100644 index 0000000..652c2af --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/implments/SwipeItemMangerImpl.java @@ -0,0 +1,252 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.implments; + +import android.view.View; +import android.widget.BaseAdapter; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.SimpleSwipeListener; +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.SwipeLayout; +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.interfaces.SwipeAdapterInterface; +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.interfaces.SwipeItemMangerInterface; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * SwipeItemMangerImpl is a helper class to help all the adapters to maintain open status. + */ +public class +SwipeItemMangerImpl implements SwipeItemMangerInterface { + + private Mode mode = Mode.Single; + public final static int INVALID_POSITION = -1; + + protected int mOpenPosition = INVALID_POSITION; + + protected Set mOpenPositions = new HashSet<>(); + protected Set mShownLayouts = new HashSet<>(); + + protected BaseAdapter mAdapter; + + private SwipeItemListener mSwipeItemListener; + + public interface SwipeItemListener{ + public void swipeCloseListner(int position, SwipeLayout layout); + public void swipeOpenListener(int position, SwipeLayout layout); + } + + public SwipeItemMangerImpl(BaseAdapter adapter) { + if(adapter == null) + throw new IllegalArgumentException("Adapter can not be null"); + + if(!(adapter instanceof SwipeItemMangerInterface)) + throw new IllegalArgumentException("adapter should implement the SwipeAdapterInterface"); + + this.mAdapter = adapter; + + if(adapter instanceof SwipeItemListener){ + this.mSwipeItemListener = (SwipeItemListener) adapter; + } + } + + public enum Mode{ + Single, Multiple + }; + + public Mode getMode(){ + return mode; + } + + public void setMode(Mode mode){ + this.mode = mode; + mOpenPositions.clear(); + mShownLayouts.clear(); + mOpenPosition = INVALID_POSITION; + } + + public void initialize(View target, int position) { + int resId = getSwipeLayoutId(position); + + OnLayoutListener onLayoutListener = new OnLayoutListener(position); + SwipeLayout swipeLayout = target.findViewById(resId); + if(swipeLayout == null) + throw new IllegalStateException("can not find SwipeLayout in target view"); + + SwipeMemory swipeMemory = new SwipeMemory(position); + swipeLayout.addSwipeListener(swipeMemory); + swipeLayout.addOnLayoutListener(onLayoutListener); + swipeLayout.setTag(resId, new ValueBox(position, swipeMemory, onLayoutListener)); + + mShownLayouts.add(swipeLayout); + } + + public void updateConvertView(View target, int position) { + int resId = getSwipeLayoutId(position); + + SwipeLayout swipeLayout = target.findViewById(resId); + if(swipeLayout == null) + throw new IllegalStateException("can not find SwipeLayout in target view"); + + ValueBox valueBox = (ValueBox)swipeLayout.getTag(resId); + if(valueBox != null) { + valueBox.swipeMemory.setPosition(position); + valueBox.onLayoutListener.setPosition(position); + valueBox.position = position; + } + } + + private int getSwipeLayoutId(int position){ + return ((SwipeAdapterInterface)(mAdapter)).getSwipeLayoutResourceId(position); + } + + @Override + public void openItem(int position) { + if(mode == Mode.Multiple){ + if(!mOpenPositions.contains(position)) + mOpenPositions.add(position); + }else{ + mOpenPosition = position; + } + mAdapter.notifyDataSetChanged(); + } + + @Override + public void closeItem(int position) { + if(mode == Mode.Multiple){ + mOpenPositions.remove(position); + }else{ + if(mOpenPosition == position) + mOpenPosition = INVALID_POSITION; + } + mAdapter.notifyDataSetChanged(); + } + + @Override + public void colseItemNoDataChange(int position) { + if (mode == Mode.Multiple) { + mOpenPositions.remove(position); + } else { + if (mOpenPosition == position) + mOpenPosition = INVALID_POSITION; + } + } + + @Override + public void closeAllExcept(SwipeLayout layout) { + for(SwipeLayout s : mShownLayouts){ + if(s != layout) + s.close(); + } + } + + @Override + public void removeShownLayouts(SwipeLayout layout) { + mShownLayouts.remove(layout); + } + + @Override + public List getOpenItems() { + if(mode == Mode.Multiple){ + return new ArrayList<>(mOpenPositions); + }else{ + return Collections.singletonList(mOpenPosition); + } + } + + @Override + public List getOpenLayouts() { + return new ArrayList<>(mShownLayouts); + } + + @Override + public boolean isOpen(int position) { + if(mode == Mode.Multiple){ + return mOpenPositions.contains(position); + }else{ + return mOpenPosition == position; + } + } + + static class ValueBox { + OnLayoutListener onLayoutListener; + SwipeMemory swipeMemory; + int position; + + ValueBox(int position, SwipeMemory swipeMemory, OnLayoutListener onLayoutListener) { + this.swipeMemory = swipeMemory; + this.onLayoutListener = onLayoutListener; + this.position = position; + } + } + + class OnLayoutListener implements SwipeLayout.OnLayout{ + + private int position; + + OnLayoutListener(int position) { + this.position = position; + } + + public void setPosition(int position){ + this.position = position; + } + + @Override + public void onLayout(SwipeLayout v) { + if(isOpen(position)){ + v.open(false, false); + }else{ + v.close(false, false); + } + } + + } + + class SwipeMemory extends SimpleSwipeListener { + + private int position; + + SwipeMemory(int position) { + this.position = position; + } + + @Override + public void onClose(SwipeLayout layout) { + if(mSwipeItemListener != null){ + mSwipeItemListener.swipeCloseListner(position , layout); + } + if(mode == Mode.Multiple){ + mOpenPositions.remove(position); + }else{ + mOpenPosition = INVALID_POSITION; + } + } + + @Override + public void onStartOpen(SwipeLayout layout) { + if(mode == Mode.Single) { + closeAllExcept(layout); + } + } + + @Override + public void onOpen(SwipeLayout layout) { + if(mSwipeItemListener != null){ + mSwipeItemListener.swipeOpenListener(position, layout); + } + if (mode == Mode.Multiple) + mOpenPositions.add(position); + else { + closeAllExcept(layout); + mOpenPosition = position; + } + } + + public void setPosition(int position){ + this.position = position; + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeAdapterInterface.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeAdapterInterface.java new file mode 100644 index 0000000..dd8fe84 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeAdapterInterface.java @@ -0,0 +1,5 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.interfaces; + +public interface SwipeAdapterInterface { + public int getSwipeLayoutResourceId(int position); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeItemMangerInterface.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeItemMangerInterface.java new file mode 100644 index 0000000..999fb65 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/mobilecommon/widget/swipe/interfaces/SwipeItemMangerInterface.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.interfaces; + +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.SwipeLayout; +import com.mm.android.deviceaddmodule.mobilecommon.widget.swipe.implments.SwipeItemMangerImpl; + +import java.util.List; + +public interface SwipeItemMangerInterface { + + public void openItem(int position); + + public void closeItem(int position); + + public void colseItemNoDataChange(int position); + + public void closeAllExcept(SwipeLayout layout); + + public List getOpenItems(); + + public List getOpenLayouts(); + + public void removeShownLayouts(SwipeLayout layout); + + public boolean isOpen(int position); + + public SwipeItemMangerImpl.Mode getMode(); + + public void setMode(SwipeItemMangerImpl.Mode mode); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/DeviceAddModel.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/DeviceAddModel.java new file mode 100644 index 0000000..eaf8b0a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/DeviceAddModel.java @@ -0,0 +1,864 @@ +package com.mm.android.deviceaddmodule.model; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.text.TextUtils; + +import com.company.NetSDK.CFG_NETAPP_WLAN; +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.company.NetSDK.EM_LOGIN_SPAC_CAP_TYPE; +import com.company.NetSDK.EM_WLAN_SCAN_AND_CONFIG_TYPE; +import com.company.NetSDK.FinalVar; +import com.company.NetSDK.INetSDK; +import com.company.NetSDK.NET_DEVICEINFO_Ex; +import com.company.NetSDK.NET_IN_GET_DEV_WIFI_LIST; +import com.company.NetSDK.NET_IN_INIT_DEVICE_ACCOUNT; +import com.company.NetSDK.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY; +import com.company.NetSDK.NET_IN_SET_DEV_WIFI; +import com.company.NetSDK.NET_IN_WLAN_ACCESSPOINT; +import com.company.NetSDK.NET_OUT_GET_DEV_WIFI_LIST; +import com.company.NetSDK.NET_OUT_INIT_DEVICE_ACCOUNT; +import com.company.NetSDK.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY; +import com.company.NetSDK.NET_OUT_SET_DEV_WIFI; +import com.company.NetSDK.NET_OUT_WLAN_ACCESSPOINT; +import com.company.NetSDK.NET_WLAN_ACCESSPOINT_INFO; +import com.company.NetSDK.SDKDEV_NETINTERFACE_INFO; +import com.company.NetSDK.SDKDEV_WLAN_DEVICE_LIST_EX; +import com.company.NetSDK.SDK_PRODUCTION_DEFNITION; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceBindResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.service.DeviceAddService; + +import org.greenrobot.eventbus.EventBus; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import static com.mm.android.deviceaddmodule.helper.DeviceAddHelper.printError; + +/** + * 设备添加数据请求类,由于设备添加页面流程单一,这里设计为单例 + **/ +public class DeviceAddModel implements IDeviceAddModel { + private static final int NET_ERROR_DEVICE_ALREADY_INIT = 1017; // 设备已经初始化 + private volatile static DeviceAddModel deviceAddModel; + DeviceAddInfo mDeviceAddInfo; + final int DMS_TIMEOUT = 45 * 1000; + int TIME_OUT = 10 * 1000; + boolean loop = true; //获取设备信息轮询标志变量 + boolean middleTimeUp = false; //设定的中间时间时间到,此时间之后如设备还是已在服务注册,且不在线以及仍为P2P类型,走绑定流程 + int LOOP_ONCE_TIME = 3 * 1000; //轮询间隔时间3S + + DeviceAddService deviceAddService; + + private DeviceAddModel() { + deviceAddService = new DeviceAddService(); + } + + public static DeviceAddModel newInstance() { + if (deviceAddModel == null) { + synchronized (DeviceAddModel.class) { + if (deviceAddModel == null) { + deviceAddModel = new DeviceAddModel(); + } + } + } + return deviceAddModel; + } + + public void updateDeviceCache(DeviceAddInfo deviceAddInfo) { + mDeviceAddInfo.setDeviceExist(deviceAddInfo.getDeviceExist()); + mDeviceAddInfo.setBindStatus(deviceAddInfo.getBindStatus()); + mDeviceAddInfo.setBindAcount(deviceAddInfo.getBindAcount()); + mDeviceAddInfo.setAccessType(deviceAddInfo.getAccessType()); + mDeviceAddInfo.setStatus(deviceAddInfo.getStatus()); + mDeviceAddInfo.setConfigMode(deviceAddInfo.getConfigMode()); + mDeviceAddInfo.setBrand(deviceAddInfo.getBrand()); + mDeviceAddInfo.setFamily(deviceAddInfo.getFamily()); + mDeviceAddInfo.setDeviceModel(deviceAddInfo.getDeviceModel()); + mDeviceAddInfo.setModelName(deviceAddInfo.getModelName()); + mDeviceAddInfo.setCatalog(deviceAddInfo.getCatalog()); + mDeviceAddInfo.setAbility(deviceAddInfo.getAbility()); + mDeviceAddInfo.setType(deviceAddInfo.getType()); + mDeviceAddInfo.setWifiTransferMode(deviceAddInfo.getWifiTransferMode()); + mDeviceAddInfo.setChannelNum(deviceAddInfo.getChannelNum()); + mDeviceAddInfo.setWifiConfigModeOptional(deviceAddInfo.isWifiConfigModeOptional()); + mDeviceAddInfo.setSupport(deviceAddInfo.isSupport()); + } + + public void updateDeviceAllCache(DeviceAddInfo deviceAddInfo) { + mDeviceAddInfo.setDeviceExist(deviceAddInfo.getDeviceExist()); + mDeviceAddInfo.setBindStatus(deviceAddInfo.getBindStatus()); + mDeviceAddInfo.setBindAcount(deviceAddInfo.getBindAcount()); + mDeviceAddInfo.setAccessType(deviceAddInfo.getAccessType()); + mDeviceAddInfo.setStatus(deviceAddInfo.getStatus()); + mDeviceAddInfo.setConfigMode(deviceAddInfo.getConfigMode()); + mDeviceAddInfo.setBrand(deviceAddInfo.getBrand()); + mDeviceAddInfo.setFamily(deviceAddInfo.getFamily()); + mDeviceAddInfo.setDeviceModel(deviceAddInfo.getDeviceModel()); + mDeviceAddInfo.setModelName(deviceAddInfo.getModelName()); + mDeviceAddInfo.setCatalog(deviceAddInfo.getCatalog()); + mDeviceAddInfo.setAbility(deviceAddInfo.getAbility()); + mDeviceAddInfo.setType(deviceAddInfo.getType()); + mDeviceAddInfo.setWifiTransferMode(deviceAddInfo.getWifiTransferMode()); + mDeviceAddInfo.setChannelNum(deviceAddInfo.getChannelNum()); + mDeviceAddInfo.setWifiConfigModeOptional(deviceAddInfo.isWifiConfigModeOptional()); + mDeviceAddInfo.setSupport(deviceAddInfo.isSupport()); + + mDeviceAddInfo.setDeviceSn(deviceAddInfo.getDeviceSn()); + mDeviceAddInfo.setDeviceCodeModel(deviceAddInfo.getDeviceCodeModel()); + mDeviceAddInfo.setRegCode(deviceAddInfo.getRegCode()); + mDeviceAddInfo.setSc(deviceAddInfo.getSc()); + mDeviceAddInfo.setNc(deviceAddInfo.getNc()); // 将16进制的字符串转换为数字 + // 支持SC码的设备,使用SC码作为设备密码 + mDeviceAddInfo.setDevicePwd(deviceAddInfo.getSc()); + mDeviceAddInfo.setImeiCode(deviceAddInfo.getImeiCode()); + String wifiConfigMode; + if (TextUtils.isEmpty(deviceAddInfo.getConfigMode())) { // 若配网模式未返回,默认可进行有线无线切换 V5.1默认增加软AP + wifiConfigMode = DeviceAddInfo.ConfigMode.SmartConfig.name() + "," + + DeviceAddInfo.ConfigMode.LAN.name() + "," + + DeviceAddInfo.ConfigMode.SoundWave.name() + "," + + DeviceAddInfo.ConfigMode.SoftAP.name(); + } else { + wifiConfigMode = deviceAddInfo.getConfigMode(); + } + mDeviceAddInfo.setConfigMode(wifiConfigMode); + } + + @Override + public void getDeviceInfo(final String sn, final String deviceCodeModel, final String deviceModelName, final String imeiCode, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + try { + DeviceAddInfo deviceAddInfo = deviceAddService.deviceInfoBeforeBind(sn, deviceCodeModel, deviceModelName, mDeviceAddInfo.getNc(), TIME_OUT); + updateDeviceCache(deviceAddInfo); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, mDeviceAddInfo).sendToTarget(); + } catch (BusinessException e) { + throw e; + } + } + }; + } + + @Override + public void getDeviceInfoLoop(final String sn, final String model, final String imeiCode, final int timeout, final Handler handler) { + loop = true; + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + while (loop) { + if (canInterruptLoop()) { + break; + } + + DeviceAddInfo deviceAddInfo = deviceAddService.deviceInfoBeforeBind(sn, mDeviceAddInfo.getDeviceCodeModel(), model, mDeviceAddInfo.getNc(), TIME_OUT); + updateDeviceCache(deviceAddInfo); + if (canInterruptLoop()) { + break; + } + try {//间隔3S查询一次 + Thread.sleep(LOOP_ONCE_TIME); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (loop) + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS).sendToTarget(); + } + }; + } + + /** + * 是否满足中断轮询的条件,可以走绑定流程 + * + * @return + */ + private boolean canInterruptLoop() { + String status = mDeviceAddInfo.getStatus(); + if (TextUtils.isEmpty(status)) { + status = DeviceAddInfo.Status.offline.name(); + } + if (mDeviceAddInfo.isDeviceInServer() && + (DeviceAddInfo.Status.online.name().equals(status) + || (DeviceAddInfo.Status.offline.name().equals(status) && mDeviceAddInfo.isP2PDev() && middleTimeUp))) { + //以下两种情况走绑定流程: + // 1.已注册上服务并且设备DMS在线 + // 2.已注册上服务,设备DMS不在线,设备类型为P2P(此时无法区分设备到底是P2P设备还是PAAS设备),并且设定的最大等待时间已到) + return true; + } + return false; + } + + @Override + public void setLoop(boolean loop) { + this.loop = loop; + } + + @Override + public void setMiddleTimeUp(boolean middleTimeUp) { + this.middleTimeUp = middleTimeUp; + } + + @Override + public DeviceAddInfo getDeviceInfoCache() { + if (mDeviceAddInfo == null) { + mDeviceAddInfo = new DeviceAddInfo(); + LogUtil.debugLog("DeviceAddModel", "getDeviceInfoCache"); + } + return mDeviceAddInfo; + } + + @Override + public void checkDevIntroductionInfo(final String deviceModelName, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + String lan = ProviderManager.getAppProvider().getAppLanguage(); + DeviceIntroductionInfo deviceIntroductionInfo = deviceAddService.introductionInfosGetCache(deviceModelName); + boolean result = true; + if (deviceIntroductionInfo != null) { + mDeviceAddInfo.setDevIntroductionInfos(deviceIntroductionInfo); + if (!TextUtils.isEmpty(deviceIntroductionInfo.getUpdateTime())) { + String resultStr = deviceAddService.deviceModelOrLeadingInfoCheck("DEVICE_LEADING_INFO", deviceModelName, deviceIntroductionInfo.getUpdateTime(), TIME_OUT); + result = resultStr.equalsIgnoreCase("true"); + } + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, result ? null : deviceIntroductionInfo).sendToTarget(); + } + }; + } + + @Override + public void getDevIntroductionInfo(final String deviceModelName, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + String lan = ProviderManager.getAppProvider().getAppLanguage(); + String modelName = mDeviceAddInfo.getModelName(); + if (TextUtils.isEmpty(modelName)) { + modelName = deviceModelName; + } + DeviceIntroductionInfo introductionInfos = deviceAddService.deviceLeadingInfo(modelName, TIME_OUT); + mDeviceAddInfo.setDevIntroductionInfos(introductionInfos); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS).sendToTarget(); + } + }; + } + + @Override + public void getDevIntroductionInfoCache(final String deviceModelName, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + String lan = ProviderManager.getAppProvider().getAppLanguage(); + String modelName = mDeviceAddInfo.getModelName(); + if (TextUtils.isEmpty(modelName)) { + modelName = deviceModelName; + } + DeviceIntroductionInfo introductionInfos = deviceAddService.introductionInfosGetCache(modelName); + mDeviceAddInfo.setDevIntroductionInfos(introductionInfos); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS).sendToTarget(); + } + }; + } + + @Override + public void initDev(final DEVICE_NET_INFO_EX device_net_info_ex, final String pwd, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + if (device_net_info_ex != null) { + final NET_IN_INIT_DEVICE_ACCOUNT in = new NET_IN_INIT_DEVICE_ACCOUNT(); + in.byPwdResetWay = device_net_info_ex.byPwdResetWay; + in.byInitStatus = device_net_info_ex.byInitStatus; + System.arraycopy(device_net_info_ex.szMac, 0, in.szMac, 0, device_net_info_ex.szMac.length); + System.arraycopy(pwd.getBytes(), 0, in.szPwd, 0, pwd.getBytes().length); + System.arraycopy("admin".getBytes(), 0, in.szUserName, 0, "admin".getBytes().length); + NET_OUT_INIT_DEVICE_ACCOUNT out = new NET_OUT_INIT_DEVICE_ACCOUNT(); + + //5秒请求一次,请求3次 + boolean init = false; + for (int i = 0; i < 3; i++) { + init = INetSDK.InitDevAccount(in, out, 5 * 1000, null); + int error = (INetSDK.GetLastError() & 0x7fffffff); + + if (init) { + break; + } else { + LogUtil.debugLog("InitPresenter", "initDev:error:" + error); + if (error == NET_ERROR_DEVICE_ALREADY_INIT) { // 设备已初始化 + init = true; + break; + } + } + } + LogUtil.debugLog("InitPresenter", "init : " + init); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, init).sendToTarget(); + } + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION).sendToTarget(); + } + }; + } + + @Override + public void initDevByIp(final DEVICE_NET_INFO_EX device_net_info_ex, final String pwd, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + NET_IN_INIT_DEVICE_ACCOUNT inInit = new NET_IN_INIT_DEVICE_ACCOUNT(); + String username = "admin"; + String deviceMacAdd = new String(device_net_info_ex.szMac).trim(); + byte pwdResetWay = device_net_info_ex.byPwdResetWay; + String deviceIp = new String(device_net_info_ex.szIP).trim(); + String cellphone = ""; + String mail = ""; + + System.arraycopy(deviceMacAdd.getBytes(), 0, inInit.szMac, 0, deviceMacAdd.getBytes().length); + System.arraycopy(username.getBytes(), 0, inInit.szUserName, 0, username.getBytes().length); + System.arraycopy(pwd.getBytes(), 0, inInit.szPwd, 0, pwd.getBytes().length); + System.arraycopy(cellphone.getBytes(), 0, inInit.szCellPhone, 0, cellphone.getBytes().length); + System.arraycopy(mail.getBytes(), 0, inInit.szMail, 0, mail.getBytes().length); + + inInit.byPwdResetWay = pwdResetWay; //设备搜索到的,必须与搜索到的一致 + + NET_OUT_INIT_DEVICE_ACCOUNT outInit = new NET_OUT_INIT_DEVICE_ACCOUNT(); + boolean init = false; + for (int i = 0; i < 2; i++) { + init = INetSDK.InitDevAccountByIP(inInit, outInit, 5000, null, deviceIp); + int error = (INetSDK.GetLastError() & 0x7fffffff); + + if (init) { + break; + } else { + LogUtil.debugLog("InitPresenter", "initDev:error:" + error); + if (error == NET_ERROR_DEVICE_ALREADY_INIT) { // 设备已初始化 + init = true; + break; + } + } + } + LogUtil.debugLog("InitPresenter", "init : " + init); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, init).sendToTarget(); + + } + }; + } + + @Override + public void deviceIPLogin(final String ip, final String devPwd, /*final boolean useSafeModeLogin, */final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + long handle; + handle = loginWithHighLevelSecurity(ip, devPwd); + int ret = 0; + if (handle == 0) { + ret = INetSDK.GetLastError(); + } else { + ret = FinalVar.NET_NOERROR; + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, ret).sendToTarget(); + if (handle != 0) { + INetSDK.Logout(handle); + } + } + }; + } + + private long ipLogin(String ip, String devPwd) { + NET_DEVICEINFO_Ex net_deviceinfo_ex = new NET_DEVICEINFO_Ex(); + int cap = 20; + //netsdk 使用局限,只能使用 类对象传递参数。 + Integer errorCode = new Integer(0); + long handle = INetSDK.LoginEx2(ip, 37777, "admin", devPwd, cap, null, net_deviceinfo_ex, errorCode); + return handle; + } + + // 安全模式登陆 + private long loginWithHighLevelSecurity(String ip, String devPwd) { + NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stuIn = new NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY(); + System.arraycopy(ip.getBytes(), 0, stuIn.szIP, 0, ip.getBytes().length); + stuIn.nPort = 37777; + System.arraycopy("admin".getBytes(), 0, stuIn.szUserName, 0, "admin".getBytes().length); + System.arraycopy(devPwd.getBytes(), 0, stuIn.szPassword, 0, devPwd.getBytes().length); + stuIn.emSpecCap = EM_LOGIN_SPAC_CAP_TYPE.EM_LOGIN_SPEC_CAP_TCP; + NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stuOut = new NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY(); + long handle = INetSDK.LoginWithHighLevelSecurity(stuIn, stuOut); + return handle; + } + + @Override + public void connectWifi4Sc(final String ip, final WlanInfo wlanInfo, final String wifiPwd, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + NET_IN_SET_DEV_WIFI stIn = new NET_IN_SET_DEV_WIFI(); + NET_OUT_SET_DEV_WIFI stOu = new NET_OUT_SET_DEV_WIFI(); + + if (ip != null) { + System.arraycopy(ip.getBytes(), 0, stIn.szDevIP, 0, ip.getBytes().length); + } + stIn.nPort = 37777; + + String SSID = wlanInfo.getWlanSSID(); + System.arraycopy(SSID.getBytes(), 0, stIn.szSSID, 0, SSID.getBytes().length); + + int encryption = wlanInfo.getWlanEncry(); + stIn.nEncryption = encryption; + LogUtil.debugLog("DeviceAddModel", "nEncryption : " + stIn.nEncryption); + + String szWPAKeys = wifiPwd; + if (encryption >= 4 && encryption <= 12) { + System.arraycopy(szWPAKeys.getBytes(), 0, stIn.szWPAKeys, 0, szWPAKeys.getBytes().length); + } else { + System.arraycopy(szWPAKeys.getBytes(), 0, stIn.szKeys[0], 0, szWPAKeys.getBytes().length); + } + + stIn.nConnectedFlag = 1; + boolean bRet = INetSDK.SetDevWifiInfo(stIn, stOu, 20000); + if (bRet) { + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, true).sendToTarget(); + } else { + printError(); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, false).sendToTarget(); + } + } + }; + + } + + @Override + public void getSoftApWifiList4Sc(final String ip, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + NET_IN_GET_DEV_WIFI_LIST stIn = new NET_IN_GET_DEV_WIFI_LIST(); + NET_OUT_GET_DEV_WIFI_LIST stOut = new NET_OUT_GET_DEV_WIFI_LIST(); + + stIn.nPort = 37777; + if (ip != null) { + System.arraycopy(ip.getBytes(), 0, stIn.szDevIP, 0, ip.getBytes().length); + } + LogUtil.debugLog("DeviceAddModel", "ip : " + ip); + boolean bRet = INetSDK.GetDevWifiListInfo(stIn, stOut, 20000); + // 若失败则再请求一次 + if (!bRet) { + bRet = INetSDK.GetDevWifiListInfo(stIn, stOut, 10000); + } + + if (bRet) { + int wlanNum = stOut.nWlanDevCount; + List listData = new ArrayList<>(); + for (int i = 0; i < wlanNum; i++) { + int encry = UIUtils.getEncry4Sc(stOut.stuWlanDev[i].byAuthMode, stOut.stuWlanDev[i].byEncrAlgr); + String ssid = new String(stOut.stuWlanDev[i].szSSID).trim(); + LogUtil.debugLog("DeviceAddModel", "ssid :" + ssid + " byAuthMode : " + stOut.stuWlanDev[i].byAuthMode + " byEncrAlgr : " + stOut.stuWlanDev[i].byEncrAlgr + " encry : " + encry); + if (TextUtils.isEmpty(ssid)) { + continue; + } + WlanInfo info = new WlanInfo(); + info.setWlanQuality(stOut.stuWlanDev[i].nRSSIQuality + 100);//nRSSIQuality的范围[-100,0] + info.setWlanSSID(ssid); + info.setWlanEncry(encry); + info.setWlanAuthMode(stOut.stuWlanDev[i].byAuthMode); + info.setWlanEncrAlgr(stOut.stuWlanDev[i].byEncrAlgr); + listData.add(info); + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, listData).sendToTarget(); + } else { + printError(); + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION).sendToTarget(); + } + } + }; + + } + + @Override + public void getSoftApWifiList(final String ip, final String devPwd, /*final boolean useSafeModeLogin, */final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + long loginHandle; + loginHandle = loginWithHighLevelSecurity(ip, devPwd); + if (loginHandle == 0) { + handler.obtainMessage(HandleMessageCode.HMC_BATCH_MIDDLE_RESULT/*, ret*/).sendToTarget(); + return; + } + + // 获取是否支持三代扫描能力 + SDK_PRODUCTION_DEFNITION sdk_production_defnition = new SDK_PRODUCTION_DEFNITION(); + boolean result = INetSDK.QueryProductionDefinition(loginHandle, sdk_production_defnition, 5000); + LogUtil.debugLog("DeviceAddModel", "result : " + result); + + boolean isV3 = false; + if (result) { + isV3 = sdk_production_defnition.emWlanScanAndConfig == EM_WLAN_SCAN_AND_CONFIG_TYPE.EM_WLAN_SCAN_AND_CONFIG_V3; + } + LogUtil.debugLog("DeviceAddModel", "isV3 : " + isV3); + if (isV3) { + thirdScan(loginHandle, handler); + } else { + secondScan(loginHandle, handler); + } + //使用结束登出,以防超出最大登录数 + if (loginHandle != 0) { + INetSDK.Logout(loginHandle); + } + } + }; + + } + + // 二代协议搜索 + private void secondScan(long handle, final Handler handler) { + SDKDEV_WLAN_DEVICE_LIST_EX wlanList = new SDKDEV_WLAN_DEVICE_LIST_EX(); + Object[] outData = new Object[1]; + outData[0] = wlanList; + //netsdk 使用局限,只能使用 类对象传递参数。 + Integer in = new Integer(-1); + boolean ret = INetSDK.GetDevConfig(handle, FinalVar.SDK_DEV_WLAN_DEVICE_CFG_EX, 0, outData, in, 20 * 1000); + + if (ret) { + int wlanNum = wlanList.bWlanDevCount; + List listData = new ArrayList<>(); + for (int i = 0; i < wlanNum; i++) { + int encry = UIUtils.getEncryV2(wlanList.lstWlanDev[i].byAuthMode, wlanList.lstWlanDev[i].byEncrAlgr); + LogUtil.debugLog("DeviceAddModel", "byAuthMode : " + wlanList.lstWlanDev[i].byAuthMode + " byEncrAlgr : " + wlanList.lstWlanDev[i].byEncrAlgr + " encry : " + encry); + String ssid = new String(wlanList.lstWlanDev[i].szSSID).trim(); + if (TextUtils.isEmpty(ssid)) { + continue; + } + WlanInfo info = new WlanInfo(); + info.setWlanQuality(wlanList.lstWlanDev[i].nRSSIQuality + 100);//nRSSIQuality的范围[-100,0] + info.setWlanSSID(ssid); + info.setWlanEncry(encry); + info.setWlanAuthMode(wlanList.lstWlanDev[i].byAuthMode); + info.setWlanEncrAlgr(wlanList.lstWlanDev[i].byEncrAlgr); + listData.add(info); + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, listData).sendToTarget(); + } else { + + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION).sendToTarget(); + } + } + + // 三代扫描 + private void thirdScan(long handle, final Handler handler) { + // 查询网络接口信息 + SDKDEV_NETINTERFACE_INFO[] stuNetInterface = new SDKDEV_NETINTERFACE_INFO[FinalVar.SDK_MAX_NETINTERFACE_NUM]; + for (int i = 0; i < stuNetInterface.length; ++i) { + stuNetInterface[i] = new SDKDEV_NETINTERFACE_INFO(); + } + Integer validCount = new Integer(0); + boolean bRet = INetSDK.QueryDevStateEx(handle, FinalVar.SDK_DEVSTATE_NETINTERFACE, stuNetInterface, 5000, validCount); + + + boolean hasWlan0 = false; + if (bRet) { + for (int i = 0; i < validCount.intValue(); i++) { + String name = new String(stuNetInterface[i].szName).trim(); + LogUtil.debugLog("DeviceAddModel", "name:" + name); + if ("wlan0".equalsIgnoreCase(name)) { + hasWlan0 = true; + break; + } + } + } + + // 查询无线网络接入点信息, 目前支持的无线个数增加到128 + // 入参 + NET_IN_WLAN_ACCESSPOINT stIn = new NET_IN_WLAN_ACCESSPOINT(); + // 需要获取信息的无线网络名称,为空时搜索所有网络 + String ssid = ""; + System.arraycopy(ssid.getBytes(), 0, stIn.szSSID, 0, ssid.getBytes().length); + + // 网卡名称, 为空时, 默认为eth2 + String name = ""; + if (hasWlan0) { + name = "wlan0"; + } + System.arraycopy(name.getBytes(), 0, stIn.szName, 0, name.getBytes().length); + + // 出参 + NET_OUT_WLAN_ACCESSPOINT stOut = new NET_OUT_WLAN_ACCESSPOINT(); + + boolean ret = INetSDK.QueryDevInfo(handle, FinalVar.NET_QUERY_WLAN_ACCESSPOINT, stIn, stOut, null, 20000); + + if (ret) { + int wlanNum = stOut.nCount; + List listData = new ArrayList<>(); + for (int i = 0; i < wlanNum; i++) { + int encry = UIUtils.getEncry(stOut.stuInfo[i].nAuthMode, stOut.stuInfo[i].nEncrAlgr); + String ssidName = new String(stOut.stuInfo[i].szSSID).trim(); // 无线网络名称 + LogUtil.debugLog("DeviceAddModel", "ssidName : " + ssidName + " nAuthMode : " + stOut.stuInfo[i].nAuthMode + " nEncrAlgr : " + stOut.stuInfo[i].nEncrAlgr + " encry : " + encry); + if (TextUtils.isEmpty(ssidName)) { + continue; + } + WlanInfo info = new WlanInfo(); + info.setWlanQuality(stOut.stuInfo[i].nStrength); // 信号强度(范围0-100) + info.setWlanSSID(ssidName); + info.setWlanEncry(encry); + info.setWlanAuthMode(stOut.stuInfo[i].nAuthMode); // 认证模式 + info.setWlanEncrAlgr(stOut.stuInfo[i].nEncrAlgr); // 加密模式 + listData.add(info); + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, listData).sendToTarget(); + } else { + handler.obtainMessage(HandleMessageCode.HMC_EXCEPTION).sendToTarget(); + } + } + + @Override + public void connectWifi(final String ip, final String devPwd, final WlanInfo wlanInfo, + final String wifiPwd, /*final boolean useSafeModeLogin, */final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + boolean connectResult = false; + final int BUFFERLEN = 1024 * 1024; //获取配置用到的缓冲区长度 + final int channelID = -1; + final String strCommand = FinalVar.CFG_CMD_WLAN; + CFG_NETAPP_WLAN stCfg = new CFG_NETAPP_WLAN(); + + long handle; + handle = loginWithHighLevelSecurity(ip, devPwd); + if (DeviceAddHelper.getNewDevConfig(handle, channelID, strCommand, BUFFERLEN, stCfg, mDeviceAddInfo.getRequestId())) { + stCfg.stuWlanInfo[0].szSSID = new byte[FinalVar.CFG_MAX_SSID_LEN]; + stCfg.stuWlanInfo[0].szKeys[0] = new byte[32]; + //设置wifi名称 + System.arraycopy(wlanInfo.getWlanSSID().getBytes(), 0, stCfg.stuWlanInfo[0].szSSID, 0, wlanInfo.getWlanSSID().getBytes().length); + //设置wifi密码 + System.arraycopy(wifiPwd.getBytes(), 0, stCfg.stuWlanInfo[0].szKeys[0], 0, wifiPwd.getBytes().length); + //设置wlan加密方式 + stCfg.stuWlanInfo[0].nEncryption = wlanInfo.getWlanEncry(); + stCfg.stuWlanInfo[0].bEnable = true; + stCfg.stuWlanInfo[0].bConnectEnable = true; + stCfg.stuWlanInfo[0].nKeyID = 0; + stCfg.stuWlanInfo[0].bKeyFlag = false; + // 国内该字段需要使用true,注意不要合并进国内(凯波说的有一个设备必须用true) + stCfg.stuWlanInfo[0].bLinkEnable = false; + + for (int i = 0; i < stCfg.stuWlanInfo.length; i++) { + LogUtil.debugLog("DeviceAddModel", "szWlanName : " + new String(stCfg.stuWlanInfo[i].szWlanName).trim()); + } + + //设置DNS + stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[0] = new byte[FinalVar.AV_CFG_IP_Address_Len_EX]; + stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[1] = new byte[FinalVar.AV_CFG_IP_Address_Len_EX]; + System.arraycopy("8.8.8.8".getBytes(), 0, stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[0], 0, "8.8.8.8".getBytes().length); + System.arraycopy("8.8.4.4".getBytes(), 0, stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[1], 0, "8.8.4.4".getBytes().length); + //netsdk 使用局限,只能使用 类对象传递参数。 + Integer error = new Integer(0); + Integer restart = new Integer(0); + char szBuffer[] = new char[BUFFERLEN]; + for (int i = 0; i < BUFFERLEN; i++) szBuffer[i] = 0; + + boolean ret = INetSDK.PacketData(FinalVar.CFG_CMD_WLAN, stCfg, szBuffer, BUFFERLEN); + + if (!ret) { + connectResult = false; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + return; + } + + ret = INetSDK.SetNewDevConfig(handle, FinalVar.CFG_CMD_WLAN, -1, szBuffer, BUFFERLEN, error, restart, 10 * 1000); + + if (!ret) { + connectResult = false; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + return; + } + connectResult = true; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + return; + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + } + }; + } + + @Override + public void connectWifi4Hidden(final String ip, final String devPwd, final WlanInfo wlanInfo, + final String wifiPwd, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + boolean connectResult = false; + final int BUFFERLEN = 1024 * 1024; //获取配置用到的缓冲区长度 + final int channelID = -1; + final String strCommand = FinalVar.CFG_CMD_WLAN; + CFG_NETAPP_WLAN stCfg = new CFG_NETAPP_WLAN(); + + long handle = loginWithHighLevelSecurity(ip, devPwd); + + // 获取是否支持三代扫描能力 + int wlanEncry = 12; + SDK_PRODUCTION_DEFNITION sdk_production_defnition = new SDK_PRODUCTION_DEFNITION(); + boolean result = INetSDK.QueryProductionDefinition(handle, sdk_production_defnition, 5000); + LogUtil.debugLog("DeviceAddModel", "result : " + result); + + boolean isV3 = false; + if (result) { + isV3 = sdk_production_defnition.emWlanScanAndConfig == EM_WLAN_SCAN_AND_CONFIG_TYPE.EM_WLAN_SCAN_AND_CONFIG_V3; + } + LogUtil.debugLog("DeviceAddModel", "isV3 : " + isV3); + if (isV3) { + // 支持三代 + NET_IN_WLAN_ACCESSPOINT in = new NET_IN_WLAN_ACCESSPOINT(); + System.arraycopy(wlanInfo.getWlanSSID().getBytes(), 0, in.szSSID, 0, wlanInfo.getWlanSSID().getBytes().length); + + NET_OUT_WLAN_ACCESSPOINT out = new NET_OUT_WLAN_ACCESSPOINT(); + Integer validCount = new Integer(0); + boolean isSucces = INetSDK.QueryDevInfo(handle, FinalVar.NET_QUERY_WLAN_ACCESSPOINT, in, out, validCount, 5000); + if (isSucces) { + LogUtil.debugLog("DeviceAddModel", "out.stuInfo : " + out.stuInfo); + if (out != null && out.stuInfo != null && out.stuInfo.length > 0) { + NET_WLAN_ACCESSPOINT_INFO stuInfo = out.stuInfo[0]; + wlanEncry = UIUtils.getEncry(stuInfo.nAuthMode, stuInfo.nEncrAlgr); + LogUtil.debugLog("DeviceAddModel", "nAuthMode : " + stuInfo.nAuthMode + " nEncrAlgr: " + stuInfo.nEncrAlgr); + } + } + } + + LogUtil.debugLog("DeviceAddModel", "wlanEncry : " + wlanEncry); + if (DeviceAddHelper.getNewDevConfig(handle, channelID, strCommand, BUFFERLEN, stCfg, mDeviceAddInfo.getRequestId())) { + stCfg.stuWlanInfo[0].szSSID = new byte[FinalVar.CFG_MAX_SSID_LEN]; + stCfg.stuWlanInfo[0].szKeys[0] = new byte[32]; + //设置wifi名称 + System.arraycopy(wlanInfo.getWlanSSID().getBytes(), 0, stCfg.stuWlanInfo[0].szSSID, 0, wlanInfo.getWlanSSID().getBytes().length); + //设置wifi密码 + System.arraycopy(wifiPwd.getBytes(), 0, stCfg.stuWlanInfo[0].szKeys[0], 0, wifiPwd.getBytes().length); + //设置wlan加密方式 + stCfg.stuWlanInfo[0].nEncryption = wlanEncry; + stCfg.stuWlanInfo[0].bEnable = true; + stCfg.stuWlanInfo[0].bConnectEnable = true; + stCfg.stuWlanInfo[0].nKeyID = 0; + stCfg.stuWlanInfo[0].bKeyFlag = false; + // 国内该字段需要使用true,注意不要合并进国内(凯波说的有一个设备必须用true) + stCfg.stuWlanInfo[0].bLinkEnable = false; + + for (int i = 0; i < stCfg.stuWlanInfo.length; i++) { + LogUtil.debugLog("DeviceAddModel", "szWlanName : " + new String(stCfg.stuWlanInfo[i].szWlanName).trim()); + } + + //设置DNS + stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[0] = new byte[FinalVar.AV_CFG_IP_Address_Len_EX]; + stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[1] = new byte[FinalVar.AV_CFG_IP_Address_Len_EX]; + System.arraycopy("8.8.8.8".getBytes(), 0, stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[0], 0, "8.8.8.8".getBytes().length); + System.arraycopy("8.8.4.4".getBytes(), 0, stCfg.stuWlanInfo[0].stuNetwork.szDnsServers[1], 0, "8.8.4.4".getBytes().length); + //netsdk 使用局限,只能使用 类对象传递参数。 + Integer error = new Integer(0); + Integer restart = new Integer(0); + char szBuffer[] = new char[BUFFERLEN]; + for (int i = 0; i < BUFFERLEN; i++) szBuffer[i] = 0; + boolean ret = INetSDK.PacketData(FinalVar.CFG_CMD_WLAN, stCfg, szBuffer, BUFFERLEN); + if (!ret) { + connectResult = false; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + //使用结束登出,以防超出最大登录数 + return; + } + + ret = INetSDK.SetNewDevConfig(handle, FinalVar.CFG_CMD_WLAN, -1, szBuffer, BUFFERLEN, error, restart, 10 * 1000); + if (!ret) { + connectResult = false; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + return; + } + connectResult = true; + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + return; + } + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, connectResult).sendToTarget(); + } + }; + } + + @Override + public void modifyDeviceName(final String deviceId, final String channelId, final String name, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + boolean isSucceed = deviceAddService.modifyDeviceName(deviceId, channelId, name, TIME_OUT); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, isSucceed).sendToTarget(); + } + }; + } + + @Override + public void addApDevice(final String deviceId, final String apId, final String apType, final String apModel, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + //TODO 配件绑定需要实现接口,当前版本不支持 + + } + }; + } + + @Override + public void modifyAPDevice(final String deviceId, final String apId, final String apName, final boolean toDevice, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + //TODO 配件绑定需要实现接口 + + } + }; + } + + @Override + public void getAddApResultAsync(final String deviceId, final String apId, final Handler handler) { + loop = true; + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + //TODO 配件绑定需要实现接口 + + } + }; + } + + + //怎么把这个方法转成我们自己的添加 + @Override + public void bindDevice(final String sn, final String code, final String deviceKey, final String imeiCode, + final String longitude, final String latitude, final String devUserName, + final String devPwd, final Handler handler) { + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + DeviceBindResult deviceBindResult = deviceAddService.userDeviceBind(sn, devPwd, DMS_TIMEOUT); + mDeviceAddInfo.setDeviceDefaultName(deviceBindResult.getDeviceName()); + mDeviceAddInfo.setBindStatus(deviceBindResult.getBindStatus()); + mDeviceAddInfo.setBindAcount(deviceBindResult.getUserAccount()); + mDeviceAddInfo.setRecordSaveDays(deviceBindResult.getRecordSaveDays()); + mDeviceAddInfo.setStreamType(deviceBindResult.getStreamType()); + mDeviceAddInfo.setServiceTime(deviceBindResult.getServiceTime()); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS).sendToTarget(); + } + }; + } + + //添加流程完成,需调用此方法,以释放相关资源 + public void recyle() { + deviceAddModel.setLoop(false); + mDeviceAddInfo = null; + deviceAddModel = null; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/IDeviceAddModel.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/IDeviceAddModel.java new file mode 100644 index 0000000..1ea9991 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/model/IDeviceAddModel.java @@ -0,0 +1,69 @@ +package com.mm.android.deviceaddmodule.model; + +import android.os.Handler; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; + +/** + * 设备添加数据请求接口类 + **/ +public interface IDeviceAddModel { + void getDeviceInfo(String sn, String deviceCodeModel,String deviceModelName, String imeiCode, Handler handler); //从服务请求设备相关信息 + + void getDeviceInfoLoop(String sn, String model, String imeiCode, int timeout, Handler handler); //从服务请求设备相关信息,轮询设备是否已上线 + + void setLoop(boolean loop); + + void setMiddleTimeUp(boolean middleTimeUp); + + DeviceAddInfo getDeviceInfoCache(); //获取本地缓存设备信息 + + + void checkDevIntroductionInfo(String deviceModelName,Handler handler); //检查设备引导信息是否有更新 + + void getDevIntroductionInfo(String deviceModelName,Handler handler); //获取设备添加引导信息 + + void getDevIntroductionInfoCache(String deviceModelName,Handler handler); //获取设备添加引导信息本地缓存 + + void initDev(DEVICE_NET_INFO_EX device_net_info_ex, String pwd, Handler handler); //初始化设备 + + void initDevByIp(DEVICE_NET_INFO_EX device_net_info_ex, String pwd, Handler handler); //单播初始化设备 + + void deviceIPLogin(String ip, String devPwd, Handler handler); //设备IP登录 + + void getSoftApWifiList(String ip, String devPwd, Handler handler); //获取wifi列表 + + void getSoftApWifiList4Sc(final String ip, final Handler handler); //获取wifi列表 SC码设备 + + void connectWifi4Sc(final String ip, final WlanInfo wlanInfo, final String wifiPwd, final Handler handler); //连接wifi SC码设备 + + void connectWifi(String ip, String devPwd, WlanInfo wlanInfo, String wifiPwd, Handler handler); //连接wifi + + void connectWifi4Hidden(final String ip, final String devPwd, final WlanInfo wlanInfo, final String wifiPwd, final Handler handler); + + void modifyDeviceName(String deviceId, String channelId, String name, Handler handler); //修改设备名 + + //配件 + void addApDevice(String deviceId, String apId, String apType, String apModel, Handler handle); //添加配件 + + void modifyAPDevice(String deviceId, String apId, String apName, boolean toDevice, Handler handle); //修改配件名 + + void getAddApResultAsync(String deviceId, String apId, Handler handle); //同步添加结果 + + /** + * 绑定设备 + * + * @param sn 设备序列号 + * @param code 设备验证码,在设备能力集支持时填写 + * @param deviceKey 从设备拿到的一串随机字符串(随机密码),用于后续平台对设备的认证,国内使用 + * @param longitude 经度 + * @param latitude 纬度 + * @param devUserName 设备用户名 + * @param devPwd 设备密码 + * @param handler + */ + void bindDevice(String sn, String code, String deviceKey, String imeiCode, String longitude, + String latitude, String devUserName, String devPwd, Handler handler); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/CONST.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/CONST.java new file mode 100644 index 0000000..cea2307 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/CONST.java @@ -0,0 +1,48 @@ +package com.mm.android.deviceaddmodule.openapi; + +public class CONST { + //获取token + public static String METHOD_ACCESSTOKEN="accessToken"; + //未绑定设备信息获取 + public static String METHOD_UNBINDDEVICEINFO="unBindDeviceInfo"; + //获取设备添加流程引导页配置信息 + public static String METHOD_GUIDEINFOGET="deviceAddingProcessGuideInfoGet"; + //校验设备添加流程引导页配置信息 + public static String METHOD_GUIDEINFOCHECK="deviceAddingProcessGuideInfoCheck"; + //绑定设备 + public static String METHOD_BINDDEVICE="bindDevice"; + //修改设备或通道名称 + public static String METHOD_MODIFYDEVICENAME="modifyDeviceName"; + //设备当前连接热点信息 + public static String METHOD_CURRENT_DEVICE_WIFI="currentDeviceWifi"; + //设备周边WIFI信息 + public static String METHOD_WIFI_AROUND="wifiAround"; + //控制设备连接热点 + public static String METHOD_CONTROL_DEVICE_WIFI="controlDeviceWifi"; + //批量根据设备序列号、通道号列表和配件号列表,获取设备的详细信息 + public static String METHOD_DEVICE_OPEN_DETAIL_LIST = "deviceOpenDetailList"; + // URL地址 + public static String HOST = ""; + // 如果不知道appid,请登录open.lechange.com,开发者服务模块中创建应用 + public static String APPID = ""; + // 如果不知道appsecret,请登录open.lechange.com,开发者服务模块中创建应用 + public static String SECRET = ""; + + public enum Envirment { + CHINA_TEST("https://funcopenapi.lechange.cn:443"), + CHINA_PRO("https://openapi.lechange.cn:443"), + OVERSEAS_TEST("https://openapifunc.easy4ip.com:443"), + OVERSEAS_PRO("https://openapi.easy4ip.com:443"); + public String url; + + Envirment(String url) { + this.url = url; + } + } + + public static void makeEnv(String url,String appId,String secretKey) { + APPID = appId; + SECRET = secretKey; + HOST = url; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/DeviceAddOpenApiManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/DeviceAddOpenApiManager.java new file mode 100644 index 0000000..ec4a943 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/DeviceAddOpenApiManager.java @@ -0,0 +1,200 @@ +package com.mm.android.deviceaddmodule.openapi; + +import com.google.gson.JsonObject; +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.device_wifi.CurWifiInfo; +import com.mm.android.deviceaddmodule.device_wifi.WifiConfig; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.openapi.data.BindDeviceData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceDetailListData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceInfoBeforeBindData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceLeadingInfoData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceModelOrLeadingInfoCheckData; +import com.mm.android.deviceaddmodule.openapi.data.ModifyDeviceNameData; + +import java.util.HashMap; + +public class DeviceAddOpenApiManager { + private static int TIME_OUT = 10 * 1000; + private static int TOKEN_TIME_OUT = 4 * 1000; + private static int DMS_TIME_OUT = 45 * 1000; + + /** + * 获取token + * + * @return + * @throws BusinessException + */ + public static String getToken() throws BusinessException { + // 获取管理员token + HashMap paramsMap = new HashMap(); + JsonObject jsonData = HttpSend.execute(paramsMap, CONST.METHOD_ACCESSTOKEN, TOKEN_TIME_OUT); + String token = jsonData.get("accessToken").getAsString(); + return token; + } + + /** + * 设备未绑定状态 + * + * @param deviceInfoBeforeBindData + * @return + * @throws BusinessException + */ + public static DeviceInfoBeforeBindData.Response deviceInfoBeforeBind(DeviceInfoBeforeBindData deviceInfoBeforeBindData) throws BusinessException { + // 未绑定设备信息获取 + HashMap paramsMap = new HashMap(); + paramsMap.put("token", deviceInfoBeforeBindData.data.token); + paramsMap.put("deviceId", deviceInfoBeforeBindData.data.deviceId); + paramsMap.put("deviceCodeModel", deviceInfoBeforeBindData.data.deviceCodeModel); + paramsMap.put("deviceModelName", deviceInfoBeforeBindData.data.deviceModelName); + paramsMap.put("ncCode", deviceInfoBeforeBindData.data.ncCode); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_UNBINDDEVICEINFO, TIME_OUT); + DeviceInfoBeforeBindData.Response response = new DeviceInfoBeforeBindData.Response(); + response.parseData(json); + return response; + } + + /** + * 根据设备市场型号获取设备添加流程引导页配置信息 + * + * @param deviceLeadingInfoData + * @return + * @throws BusinessException + */ + public static DeviceLeadingInfoData.Response deviceLeadingInfo(DeviceLeadingInfoData deviceLeadingInfoData) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", deviceLeadingInfoData.data.token); + paramsMap.put("deviceModelName", deviceLeadingInfoData.data.deviceModelName); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_GUIDEINFOGET, TIME_OUT); + DeviceLeadingInfoData.Response response = new DeviceLeadingInfoData.Response(); + response.parseData(json); + return response; + } + + /** + * 校验设备添加流程引导页配置信息是否需更新 + * + * @param deviceModelOrLeadingInfoCheckData + * @return + * @throws BusinessException + */ + public static DeviceModelOrLeadingInfoCheckData.Response deviceModelOrLeadingInfoCheck(DeviceModelOrLeadingInfoCheckData deviceModelOrLeadingInfoCheckData) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", deviceModelOrLeadingInfoCheckData.data.token); + paramsMap.put("deviceModelName", deviceModelOrLeadingInfoCheckData.data.deviceModelName); + paramsMap.put("updateTime", deviceModelOrLeadingInfoCheckData.data.updateTime); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_GUIDEINFOCHECK, TIME_OUT); + DeviceModelOrLeadingInfoCheckData.Response response = new DeviceModelOrLeadingInfoCheckData.Response(); + response.parseData(json); + return response; + } + + /** + * 绑定设备 + * + * @param bindDeviceData + * @return + * @throws BusinessException + */ + public static BindDeviceData.Response userDeviceBind(BindDeviceData bindDeviceData) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", bindDeviceData.data.token); + paramsMap.put("deviceId", bindDeviceData.data.deviceId); + paramsMap.put("code", bindDeviceData.data.code); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_BINDDEVICE, DMS_TIME_OUT); + BindDeviceData.Response response = new BindDeviceData.Response(); + response.parseData(json); + return response; + } + + /** + * 修改设备或通道名称 + * + * @param bindDeviceData + * @return + * @throws BusinessException + */ + public static ModifyDeviceNameData.Response modifyDeviceName(ModifyDeviceNameData bindDeviceData) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", bindDeviceData.data.token); + paramsMap.put("deviceId", bindDeviceData.data.deviceId); + paramsMap.put("channelId", bindDeviceData.data.channelId); + paramsMap.put("name", bindDeviceData.data.name); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_MODIFYDEVICENAME, TIME_OUT); + ModifyDeviceNameData.Response response = new ModifyDeviceNameData.Response(); + response.parseData(json); + return response; + } + + /** + * 设备当前连接热点信息 + * + * @param deviceId + * @return + * @throws BusinessException + */ + public static CurWifiInfo currentDeviceWifi(String deviceId) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", LCDeviceEngine.newInstance().accessToken); + paramsMap.put("deviceId", deviceId); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_CURRENT_DEVICE_WIFI, DMS_TIME_OUT); + CurWifiInfo.Response response = new CurWifiInfo.Response(); + response.parseData(json); + return response.data; + } + + /** + * 设备周边WIFI信息 + * + * @param token + * @param deviceId + * @return + * @throws BusinessException + */ + public static WifiConfig wifiAround(String token, String deviceId) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", token); + paramsMap.put("deviceId", deviceId); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_WIFI_AROUND, DMS_TIME_OUT); + WifiConfig.Response response = new WifiConfig.Response(); + response.parseData(json); + return response.data; + } + + /** + * 控制设备连接热点 + * + * @param token + * @param deviceId + * @return + * @throws BusinessException + */ + public static boolean controlDeviceWifi(String token, String deviceId, String ssid, String bssid, boolean linkEnable, String password) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", token); + paramsMap.put("deviceId", deviceId); + paramsMap.put("ssid", ssid); + paramsMap.put("bssid", bssid); + paramsMap.put("linkEnable", linkEnable); + paramsMap.put("password", password); + HttpSend.execute(paramsMap, CONST.METHOD_CONTROL_DEVICE_WIFI, DMS_TIME_OUT); + return true; + } + + /** + * 批量根据设备序列号、通道号列表和配件号列表,获取设备的详细信息 + * + * @param deviceDetailListData + * @return + * @throws BusinessException + */ + public static DeviceDetailListData.Response deviceOpenDetailList(DeviceDetailListData deviceDetailListData) throws BusinessException { + HashMap paramsMap = new HashMap(); + paramsMap.put("token", LCDeviceEngine.newInstance().accessToken); + paramsMap.put("deviceList", deviceDetailListData.data.deviceList); + JsonObject json = HttpSend.execute(paramsMap, CONST.METHOD_DEVICE_OPEN_DETAIL_LIST, TIME_OUT); + DeviceDetailListData.Response response = new DeviceDetailListData.Response(); + response.parseData(json); + return response; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpClient.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpClient.java new file mode 100644 index 0000000..1a698f3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpClient.java @@ -0,0 +1,88 @@ +package com.mm.android.deviceaddmodule.openapi; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import javax.net.ssl.HttpsURLConnection; + +public class HttpClient { + private static final String TAG=HttpClient.class.getSimpleName(); + /** + * post + * + * @param urlStr + * @param paramStr + * @param contentType + * @param debugTag + * @return + */ + public static String post(String urlStr, String paramStr, String contentType, String debugTag,int timeOut) throws IOException { + LogUtil.debugLog(TAG,urlStr+"..."+paramStr); + HttpsURLConnection conn = null; + String resultData = ""; + OutputStream outputStream = null; + InputStream inputStream = null; + ByteArrayOutputStream baos = null; + try { + URL url = new URL(urlStr); + conn = (HttpsURLConnection) url.openConnection(); + conn.setHostnameVerifier(SSLSocketClient.getHostnameVerifier()); + conn.setConnectTimeout(timeOut); + conn.setReadTimeout(timeOut); + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setRequestMethod("POST"); + conn.setUseCaches(false); + conn.setInstanceFollowRedirects(true); + conn.setRequestProperty("Content-Type", contentType); + conn.connect(); + outputStream = conn.getOutputStream(); + outputStream.write(paramStr.getBytes()); + outputStream.flush(); + outputStream.close(); + int responseCode = conn.getResponseCode(); + if (debugTag != null) + LogUtil.debugLog(debugTag, "response code " + responseCode); + if (200 == responseCode) { + inputStream = conn.getInputStream(); + byte[] buffer = new byte[1024]; + baos = new ByteArrayOutputStream(); + boolean var13 = true; + int len; + while ((len = inputStream.read(buffer)) != -1) { + baos.write(buffer, 0, len); + } + byte[] b = baos.toByteArray(); + resultData = new String(b, "utf-8"); + baos.flush(); + if (debugTag != null) + LogUtil.debugLog(debugTag, "request data " + resultData); + } else + throw new IOException(String.format("http_get failed: status=%d", responseCode)); + } catch (IOException e) { + throw e; + } catch (Throwable e) { + throw new IOException(e); + } finally { + try { + if (outputStream != null) { + outputStream.close(); + } + if (baos != null) { + baos.close(); + } + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + } + if (conn != null) { + conn.disconnect(); + } + } + return resultData; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpSend.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpSend.java new file mode 100644 index 0000000..b4251a5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/HttpSend.java @@ -0,0 +1,103 @@ +package com.mm.android.deviceaddmodule.openapi; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.MD5Helper; + +import org.apache.http.conn.ConnectTimeoutException; + +import java.io.IOException; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.net.UnknownServiceException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.net.ssl.SSLException; + +public class HttpSend { + + private static final String TAG = HttpSend.class.getSimpleName(); + + public static JsonObject execute(Map paramsMap, String method,int timeOut) throws BusinessException { + Map map = paramsInit(paramsMap); + // 返回json + JsonObject jsonObj = doPost(CONST.HOST + "/openapi/" + method, map,timeOut); + LogUtil.debugLog(TAG, "response result:" + jsonObj.toString()); + if (jsonObj == null) { + throw new BusinessException("openApi response is null"); + } + JsonObject jsonResult = jsonObj.getAsJsonObject("result"); + if (jsonResult == null) { + throw new BusinessException("openApi response is null"); + } + String code = jsonResult.get("code").getAsString(); + if (!"0".equals(code)) { + String msg = jsonResult.get("msg").getAsString(); + throw new BusinessException(code + msg); + } + try { + JsonObject jsonData = jsonResult.getAsJsonObject("data"); + if (jsonData ==null){ + jsonData=new JsonObject(); + } + return jsonData; + } catch (Throwable e) { + BusinessException businessException = new BusinessException(e); + throw businessException; + } + } + + private static JsonObject doPost(String url, Map map, int timeOut) throws BusinessException { + Gson gson = new Gson(); + String json = gson.toJson(map); + JsonObject jsonObject = new JsonObject(); + try { + LogUtil.debugLog(TAG, "reqest: " + url + " data:" + json.toString()); + String openApi = HttpClient.post(url, json, "application/json", "OpenApi",timeOut); + jsonObject = new JsonParser().parse(openApi).getAsJsonObject(); + } catch (IOException e) { + BusinessException b = new BusinessException(e); + if (e instanceof ConnectTimeoutException || e instanceof SocketTimeoutException + || e instanceof UnknownHostException + || e instanceof UnknownServiceException || e instanceof SSLException + || e instanceof SocketException) { + b.errorDescription = "操作失败,请检查网络"; + } + throw b; + } catch (Throwable e) { + BusinessException b = new BusinessException(e); + throw b; + } + return jsonObject; + } + + private static Map paramsInit(Map paramsMap) { + long time = System.currentTimeMillis() / 1000; + String nonce = UUID.randomUUID().toString(); + String id = UUID.randomUUID().toString(); + StringBuilder paramString = new StringBuilder(); + paramString.append("time:").append(time).append(","); + paramString.append("nonce:").append(nonce).append(","); + paramString.append("appSecret:").append(CONST.SECRET); + String sign = ""; + // 计算MD5得值 + sign = MD5Helper.encodeToLowerCase(paramString.toString().trim()); + Map systemMap = new HashMap(); + systemMap.put("ver", "1.0"); + systemMap.put("sign", sign); + systemMap.put("appId", CONST.APPID); + systemMap.put("nonce", nonce); + systemMap.put("time", time); + Map map = new HashMap(); + map.put("system", systemMap); + map.put("params", paramsMap); + map.put("id", id); + return map; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/SSLSocketClient.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/SSLSocketClient.java new file mode 100644 index 0000000..32c596a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/SSLSocketClient.java @@ -0,0 +1,68 @@ +package com.mm.android.deviceaddmodule.openapi; + +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +class SSLSocketClient { + + static SSLSocketFactory getSSLSocketFactory() { + try { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, getTrustManager(), new SecureRandom()); + return sslContext.getSocketFactory(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static TrustManager[] getTrustManager() throws CertificateException { + return new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + }; + } + + static HostnameVerifier getHostnameVerifier() { + return new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession sslSession) { + boolean flag = false; + try { + X509Certificate[] certs = (X509Certificate[]) sslSession.getPeerCertificates(); + for (X509Certificate cert : certs) { + String cname = cert.getSubjectDN().getName().split(",")[0]; + if (hostname.endsWith(cname.substring(4))) { + flag = true; + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return flag; + } + }; + } +} + diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/BindDeviceData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/BindDeviceData.java new file mode 100644 index 0000000..be671f6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/BindDeviceData.java @@ -0,0 +1,48 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; + +public class BindDeviceData implements Serializable { + public BindDeviceData.RequestData data = new BindDeviceData.RequestData(); + + public static class ResponseData implements Serializable{ + public String deviceName; + public String userAccount; + public String bindStatus; + + @Override + public String toString() { + return "ResponseData{" + + "deviceName='" + deviceName + '\'' + + ", userAccount='" + userAccount + '\'' + + ", bindStatus='" + bindStatus + '\'' + + '}'; + } + } + + public static class Response { + public BindDeviceData.ResponseData data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), BindDeviceData.ResponseData.class); + } + } + + public static class RequestData implements Serializable{ + public String code; + public String token; + public String deviceId; + + @Override + public String toString() { + return "RequestData{" + + "code='" + code + '\'' + + ", token='" + token + '\'' + + ", deviceId='" + deviceId + '\'' + + '}'; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceDetailListData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceDetailListData.java new file mode 100644 index 0000000..2f03df1 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceDetailListData.java @@ -0,0 +1,160 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import java.io.Serializable; +import java.util.List; + +public class DeviceDetailListData implements Serializable { + public DeviceDetailListData.RequestData data = new DeviceDetailListData.RequestData(); + + public static class RequestData implements Serializable { + public String token; + public List deviceList; + + @Override + public String toString() { + return "RequestData{" + + "token='" + token + '\'' + + ", deviceList=" + deviceList + + '}'; + } + + public static class DeviceListBean implements Serializable { + public String deviceId; + public String channelList; + public String apList; + + @Override + public String toString() { + return "DeviceListBean{" + + "deviceId='" + deviceId + '\'' + + ", channelList='" + channelList + '\'' + + ", apList='" + apList + '\'' + + '}'; + } + } + } + + public static class Response { + public DeviceDetailListData.ResponseData data; + public long baseBindId=-1; + public long openBindId=-1; + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), DeviceDetailListData.ResponseData.class); + } + } + + public static class ResponseData implements Serializable { + public int count; + + public List deviceList; + + @Override + public String toString() { + return "ResponseData{" + + "count=" + count + + ", deviceList=" + deviceList + + '}'; + } + + public static class DeviceListBean implements Serializable { + public String deviceId; + public String status; + public String deviceModel; + public String catalog; + public String brand; + public String version; + public String name; + public String ability; + public String accessType; + public int checkedChannel; + public String playToken; + //1:开放平台添加 2:乐橙App添加 + public int deviceSource; + public List channels; + public List aplist; + + @Override + public String toString() { + return "DeviceListBean{" + + "deviceId='" + deviceId + '\'' + + ", status='" + status + '\'' + + ", deviceModel='" + deviceModel + '\'' + + ", catalog='" + catalog + '\'' + + ", brand='" + brand + '\'' + + ", version='" + version + '\'' + + ", name='" + name + '\'' + + ", ability='" + ability + '\'' + + ", accessType='" + accessType + '\'' + + ", checkedChannel=" + checkedChannel + + ", playToken='" + playToken + '\'' + + ", deviceSource=" + deviceSource + + ", channels=" + channels + + ", aplist=" + aplist + + '}'; + } + + public static class ChannelsBean implements Serializable { + public String channelId; + public String deviceId; + public String channelName; + public String ability; + public String status; + public String picUrl; + public String remindStatus; + public String cameraStatus; + public String storageStrategyStatus; + public String shareStatus; + public String shareFunctions; + + @Override + public String toString() { + return "ChannelsBean{" + + "channelId='" + channelId + '\'' + + ", deviceId='" + deviceId + '\'' + + ", channelName='" + channelName + '\'' + + ", ability='" + ability + '\'' + + ", status='" + status + '\'' + + ", picUrl='" + picUrl + '\'' + + ", remindStatus='" + remindStatus + '\'' + + ", cameraStatus='" + cameraStatus + '\'' + + ", storageStrategyStatus='" + storageStrategyStatus + '\'' + + ", shareStatus='" + shareStatus + '\'' + + ", shareFunctions='" + shareFunctions + '\'' + + '}'; + } + } + + public static class AplistBean implements Serializable { + public String apId; + public String apName; + public String apType; + public String apModel; + public String ioType; + public String apVersion; + public String apStatus; + public String apEnable; + public String apCapacity; + + @Override + public String toString() { + return "AplistBean{" + + "apId='" + apId + '\'' + + ", apName='" + apName + '\'' + + ", apType='" + apType + '\'' + + ", apModel='" + apModel + '\'' + + ", ioType='" + ioType + '\'' + + ", apVersion='" + apVersion + '\'' + + ", apStatus='" + apStatus + '\'' + + ", apEnable='" + apEnable + '\'' + + ", apCapacity='" + apCapacity + '\'' + + '}'; + } + } + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceInfoBeforeBindData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceInfoBeforeBindData.java new file mode 100644 index 0000000..7202225 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceInfoBeforeBindData.java @@ -0,0 +1,74 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; + +public class DeviceInfoBeforeBindData implements Serializable { + public DeviceInfoBeforeBindData.RequestData data = new DeviceInfoBeforeBindData.RequestData(); + + public static class RequestData implements Serializable { + public String token; + public String deviceId; + public String deviceCodeModel; + public String deviceModelName; + public String ncCode; + + @Override + public String toString() { + return "RequestData{" + + "token='" + token + '\'' + + ", deviceId='" + deviceId + '\'' + + ", deviceCodeModel='" + deviceCodeModel + '\'' + + ", deviceModelName='" + deviceModelName + '\'' + + ", ncCode='" + ncCode + '\'' + + '}'; + } + } + + public static class Response { + public DeviceInfoBeforeBindData.ResponseData data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(),DeviceInfoBeforeBindData.ResponseData.class); + } + } + + public static class ResponseData implements Serializable { + public String ability; + public String bindStatus; + public String catalog; + public String deviceCodeModel; + public String deviceExist; + public String deviceModelName; + public String status; + public boolean support; + public String wifiConfigMode; + public boolean wifiConfigModeOptional; + public String wifiTransferMode; + public String type; + public String userAccount; + public String deviceImageURI; + + @Override + public String toString() { + return "ResponseData{" + + "ability='" + ability + '\'' + + ", bindStatus='" + bindStatus + '\'' + + ", catalog='" + catalog + '\'' + + ", deviceCodeModel='" + deviceCodeModel + '\'' + + ", deviceExist='" + deviceExist + '\'' + + ", deviceModelName='" + deviceModelName + '\'' + + ", status='" + status + '\'' + + ", support=" + support + + ", wifiConfigMode='" + wifiConfigMode + '\'' + + ", wifiConfigModeOptional='" + wifiConfigModeOptional + '\'' + + ", wifiTransferMode='" + wifiTransferMode + '\'' + + ", type='" + type + '\'' + + ", userAccount='" + userAccount + '\'' + + ", deviceImageURI='" + deviceImageURI + '\'' + + '}'; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceLeadingInfoData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceLeadingInfoData.java new file mode 100644 index 0000000..7839517 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceLeadingInfoData.java @@ -0,0 +1,71 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class DeviceLeadingInfoData implements Serializable { + public DeviceLeadingInfoData.RequestData data = new DeviceLeadingInfoData.RequestData(); + + public static class Response { + public DeviceLeadingInfoData.ResponseData data; + public String body; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), DeviceLeadingInfoData.ResponseData.class); + JsonObject jsonObject=new JsonObject(); + jsonObject.addProperty("code","0"); + jsonObject.addProperty("desc","操作成功"); + jsonObject.add("data",json); + body=jsonObject.toString(); + } + } + + public static class ResponseData implements Serializable{ + public List introductions = new ArrayList(); + public List images = new ArrayList(); + public String updateTime; + + public static class ImagesElement implements Serializable{ + public String imageName; + public String imageUrl; + + @Override + public String toString() { + return "ImagesElement{" + + "imageName='" + imageName + '\'' + + ", imageUrl='" + imageUrl + '\'' + + '}'; + } + } + + public static class IntroductionsElement implements Serializable{ + public String introductionContent; + public String introductionName; + + @Override + public String toString() { + return "IntroductionsElement{" + + "introductionContent='" + introductionContent + '\'' + + ", introductionName='" + introductionName + '\'' + + '}'; + } + } + } + + public static class RequestData implements Serializable{ + public String token; + public String deviceModelName; + + @Override + public String toString() { + return "RequestData{" + + "token='" + token + '\'' + + ", deviceModelName='" + deviceModelName + '\'' + + '}'; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceModelOrLeadingInfoCheckData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceModelOrLeadingInfoCheckData.java new file mode 100644 index 0000000..46b39ac --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/DeviceModelOrLeadingInfoCheckData.java @@ -0,0 +1,44 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; + +public class DeviceModelOrLeadingInfoCheckData implements Serializable { + public DeviceModelOrLeadingInfoCheckData.RequestData data = new DeviceModelOrLeadingInfoCheckData.RequestData(); + + public static class Response { + public DeviceModelOrLeadingInfoCheckData.ResponseData data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), DeviceModelOrLeadingInfoCheckData.ResponseData.class); + } + } + + public static class ResponseData implements Serializable { + public boolean isUpdated; + + @Override + public String toString() { + return "ResponseData{" + + "isUpdated=" + isUpdated + + '}'; + } + } + + public static class RequestData implements Serializable { + public String token; + public String deviceModelName; + public String updateTime; + + @Override + public String toString() { + return "RequestData{" + + "token='" + token + '\'' + + ", deviceModelName='" + deviceModelName + '\'' + + ", updateTime='" + updateTime + '\'' + + '}'; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/ModifyDeviceNameData.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/ModifyDeviceNameData.java new file mode 100644 index 0000000..34cf2a0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/openapi/data/ModifyDeviceNameData.java @@ -0,0 +1,38 @@ +package com.mm.android.deviceaddmodule.openapi.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.io.Serializable; + +public class ModifyDeviceNameData implements Serializable { + public ModifyDeviceNameData.RequestData data = new ModifyDeviceNameData.RequestData(); + + public static class Response { + public ModifyDeviceNameData.ResponseData data; + + public void parseData(JsonObject json) { + Gson gson = new Gson(); + this.data = gson.fromJson(json.toString(), ModifyDeviceNameData.ResponseData.class); + } + } + + public static class ResponseData implements Serializable { + } + + public static class RequestData implements Serializable { + public String deviceId; + public String channelId; + public String name; + public String token; + + @Override + public String toString() { + return "RequestData{" + + "deviceId='" + deviceId + '\'' + + ", channelId='" + channelId + '\'' + + ", name='" + name + '\'' + + ", token='" + token + '\'' + + '}'; + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApBindSuccessFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApBindSuccessFragment.java new file mode 100644 index 0000000..0b9ba5e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApBindSuccessFragment.java @@ -0,0 +1,173 @@ +package com.mm.android.deviceaddmodule.p_ap; + + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.InputFilter; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.ApBindSuccessConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CommonEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.NameLengthFilter; +import com.mm.android.deviceaddmodule.mobilecommon.utils.WordInputFilter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.ApBindSuccessPresenter; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.greenrobot.eventbus.EventBus; + +/** + * 配件绑定成功页 + **/ +public class ApBindSuccessFragment extends BaseDevAddFragment implements ApBindSuccessConstract.View, + View.OnClickListener { + private static String AP_RESULT_PARAM = "ap_result_param"; + private final int MAXLETHER = 20; + + ApBindSuccessConstract.Presenter mPresenter; + ClearEditText mApNameEdit; + TextView mNextBtn; + ImageView mDevImg; + + public static ApBindSuccessFragment newInstance(AddApResult addApResult) { + ApBindSuccessFragment fragment = new ApBindSuccessFragment(); + Bundle args = new Bundle(); + args.putSerializable(AP_RESULT_PARAM, addApResult); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + String devName=s.toString().trim(); + if(!TextUtils.isEmpty(devName)){ + mNextBtn.setEnabled(true); + mApNameEdit.removeTextChangedListener(mTextWatcher); + String filterDevName = DeviceAddHelper.strDeviceNameFilter(devName); + if (!filterDevName.equals(devName)) { + mApNameEdit.setText(filterDevName); + mApNameEdit.setSelection(filterDevName.length()); + } + mApNameEdit.addTextChangedListener(mTextWatcher); + }else{ + mNextBtn.setEnabled(false); + } + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_ap_bind_success, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.BLANK); + } + + @Override + protected void initView(View view) { + mApNameEdit = view.findViewById(R.id.ap_name_input); + mNextBtn = view.findViewById(R.id.tv_next); + mNextBtn.setOnClickListener(this); + + mApNameEdit.setFilters(new InputFilter[] {new WordInputFilter(WordInputFilter.REX_NAME) , new NameLengthFilter(MAXLETHER)}); + mApNameEdit.addTextChangedListener(mTextWatcher); + mDevImg = view.findViewById(R.id.dev_img); + } + + @Override + protected void initData() { + mPresenter = new ApBindSuccessPresenter(this); + if (getArguments() != null) { + AddApResult addApResult = (AddApResult) getArguments().getSerializable(AP_RESULT_PARAM); + mPresenter.setData(addApResult); + } + } + + @Override + public String getApName() { + return mApNameEdit.getText().toString().trim(); + } + + @Override + public void setApName(String name) { + mApNameEdit.setText(name); + } + + @Override + public void setApImg(String img) { + if (!TextUtils.isEmpty(img)) { + ImageLoader.getInstance().displayImage(img, mDevImg, + DeviceAddImageLoaderHelper.getCommonOptions4success()); + } + } + + @Override + public void completeAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + boolean isDeviceDetail = deviceAddInfo.isDeviceDetail(); + String deviceId = deviceAddInfo.getGatewayInfo().getSn(); + String apId = deviceAddInfo.getDeviceSn(); + + if (getActivity() != null) getActivity().finish(); + + String code = CommonEvent.AP_PAIR_SUCCEED_2_MID_ACTION; + if(!isDeviceDetail) { + //添加结束跳转到首页设备列表 + code = CommonEvent.AP_PAIR_SUCCEED_2_MAIN_ACTION; + ProviderManager.getDeviceAddCustomProvider().goHomePage(getContext()); + } + + Bundle bundle = new Bundle(); + bundle.putString(LCConfiguration.Device_ID, deviceId); + bundle.putString(LCConfiguration.AP_ID, apId); + CommonEvent commonEvent = new CommonEvent(code); + commonEvent.setBundle(bundle); + EventBus.getDefault().post(commonEvent); + + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_next) { + mPresenter.modifyApName(); + } + } + + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApPairFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApPairFragment.java new file mode 100644 index 0000000..f1e0b90 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/ApPairFragment.java @@ -0,0 +1,109 @@ +package com.mm.android.deviceaddmodule.p_ap; + + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.ApPairConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CircleCountDownView; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.ApPairPresenter; + +/** + * 配件网关配对页 + **/ +public class ApPairFragment extends BaseDevAddFragment implements ApPairConstract.View, CircleCountDownView.OnCountDownFinishListener { + ApPairConstract.Presenter mPresenter; + ImageView mTipImg,mPairImage1,mPairImage2; + TextView mTipTxt,mTipTxt2; + CircleCountDownView mCountDownView; + + + public static ApPairFragment newInstance() { + ApPairFragment fragment = new ApPairFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_ap_pair, container, false); + } + + @Override + protected void initView(View view) { + mPairImage1= view.findViewById(R.id.pair_img1); + mPairImage2= view.findViewById(R.id.pair_img2); + mTipImg= view.findViewById(R.id.tip_img); + mTipTxt= view.findViewById(R.id.tip_txt); + mTipTxt2= view.findViewById(R.id.tip_txt2); + mCountDownView= view.findViewById(R.id.countdown_view); + mCountDownView.setCountDownListener(this); + mCountDownView.startCountDown(); + startAnimation(); + } + + private void startAnimation(){ + AnimatorSet animatorSet=new AnimatorSet(); + ObjectAnimator cloudImage1Anim=ObjectAnimator.ofFloat(mPairImage1,"translationX",-100f,0f); + cloudImage1Anim.setRepeatMode(ValueAnimator.RESTART); + cloudImage1Anim.setRepeatCount(ValueAnimator.INFINITE); + ObjectAnimator cloudImage2Anim=ObjectAnimator.ofFloat(mPairImage2,"translationX",100f,0f); + cloudImage2Anim.setRepeatMode(ValueAnimator.RESTART); + cloudImage2Anim.setRepeatCount(ValueAnimator.INFINITE); + animatorSet.play(cloudImage1Anim).with(cloudImage2Anim); + animatorSet.setDuration(1500); + animatorSet.start(); + } + + @Override + protected void initData() { + mPresenter=new ApPairPresenter(this); + mPresenter.pair(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mCountDownView.stopCountDown(); + } + + @Override + public void countDownFinished() { + mPresenter.stopPair(); + goErrorTipPage(); + } + + @Override + public void middleTimeUp() { + + } + + @Override + public void goErrorTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.AP_ERROR_PAIR_TIMEOUT); + } + + @Override + public void goApBindSuccessPage(AddApResult addApResult) { + mPresenter.stopPair(); + PageNavigationHelper.gotoApBindSuccessPage(this,addApResult); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/GatewayListFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/GatewayListFragment.java new file mode 100644 index 0000000..9fac0fb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/GatewayListFragment.java @@ -0,0 +1,146 @@ +package com.mm.android.deviceaddmodule.p_ap; + + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.adapter.GatewayListAdapter; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.GatewayListConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; +import com.mm.android.deviceaddmodule.presenter.GatewayListPresenter; +import com.nostra13.universalimageloader.core.ImageLoader; + +import java.util.List; + +/** + * 网关列表页 + **/ +public class GatewayListFragment extends BaseDevAddFragment implements GatewayListConstract.View, View.OnClickListener,AdapterView.OnItemClickListener{ + private static final String SELECT_FLAG_PARAM="select_flag_param"; + GatewayListConstract.Presenter mPresenter; + ListView mGatewayList; + TextView mEmptyTipTxt,mApSnTxt,mNextBtn; + ImageView mApImg; + GatewayListAdapter mAdapter; + + public static GatewayListFragment newInstance(boolean hasSelectGateway) { + GatewayListFragment fragment = new GatewayListFragment(); + Bundle args = new Bundle(); + args.putBoolean(SELECT_FLAG_PARAM,hasSelectGateway); + fragment.setArguments(args); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_gateway_list, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + @Override + protected void initView(View view) { + mGatewayList= view.findViewById(R.id.gatway_list); + mEmptyTipTxt= view.findViewById(R.id.empty_tip); + mApImg= view.findViewById(R.id.iv_ap_img); + mApSnTxt= view.findViewById(R.id.tv_ap_sn); + mNextBtn= view.findViewById(R.id.tv_next); + mNextBtn.setOnClickListener(this); + mGatewayList.setOnItemClickListener(this); + } + + @Override + protected void initData() { + mPresenter=new GatewayListPresenter(this); + boolean hasSelectGateway=false; + if(getArguments()!=null){ + hasSelectGateway=getArguments().getBoolean(SELECT_FLAG_PARAM); + } + List data=mPresenter.getGatewayData(hasSelectGateway); + if(data!=null&&data.size()>0) { + mNextBtn.setEnabled(true); + mAdapter = new GatewayListAdapter(data, getActivity()); + mGatewayList.setAdapter(mAdapter); + setSelectedPos(mPresenter.getSelectedpos()); + mNextBtn.setEnabled(mAdapter.getSelectPosition()!=-1); + }else{ + showEmptyTip(); + } + } + + private void showEmptyTip(){ + mGatewayList.setVisibility(View.GONE); + mEmptyTipTxt.setVisibility(View.VISIBLE); + mNextBtn.setEnabled(false); + } + + @Override + public void onClick(View v) { + int id=v.getId(); + if(id==R.id.tv_next){ + int curPos=0; + if(mAdapter!=null) { + curPos = mAdapter.getSelectPosition(); + } + mPresenter.dispatchCurSelect(curPos); + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + DHDevice device = mAdapter.getItem(position); + //只有在线的网关才可点击 + if (device != null && device.isOnline()) { + if(position==mAdapter.getSelectPosition()) {//取消选择 + mAdapter.setSelectPosition(-1); + }else{ + mAdapter.setSelectPosition(position); + } + mNextBtn.setEnabled(mAdapter.getSelectPosition()!=-1); + } + } + + @Override + public void goTipPage() { + PageNavigationHelper.gotoApPowerTipPage(this); + } + + @Override + public void setApSn(String apSn) { + mApSnTxt.setText(apSn); + } + + @Override + public void setApImg(String img) { + if (!TextUtils.isEmpty(img)) { + ImageLoader.getInstance().displayImage(img, mApImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + } + + @Override + public void setSelectedPos(int pos) { + mAdapter.setSelectPosition(pos); + mAdapter.notifyDataSetChanged(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApLightFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApLightFragment.java new file mode 100644 index 0000000..b8536e8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApLightFragment.java @@ -0,0 +1,74 @@ +package com.mm.android.deviceaddmodule.p_ap; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +public class TipApLightFragment extends BaseTipFragment { + + public static TipApLightFragment newInstance() { + TipApLightFragment fragment = new TipApLightFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initView(View view) { + super.initView(view); + mConfirmCheck.setVisibility(View.VISIBLE); + mNextBtn.setEnabled(mConfirmCheck.isChecked()); + mTipImg.setScaleType(ImageView.ScaleType.FIT_XY); + } + + @Override + protected void initData() { + super.initData(); + DeviceIntroductionInfo deviceIntroductionInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_PAIR_OPERATION_INTRODUCTION); + String tipImg = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_PAIR_STATUS_IMAGE); + String helpTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_RESET_GUIDE_INTRODUCTION); + String confirmTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_PAIR_CONFIRM_INTRODUCTION); + if (!TextUtils.isEmpty(tipImg)) { + ImageLoader.getInstance().displayImage(tipImg, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + if (!TextUtils.isEmpty(tipTxt)) { + mTipTxt.setText(tipTxt); + } + if (!TextUtils.isEmpty(helpTxt)) { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(helpTxt); + } + if (!TextUtils.isEmpty(confirmTxt)) { + mConfirmCheck.setText(confirmTxt); + } + } + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoApPairPage(this); + } + + @Override + protected void helpAction() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_RESET); + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApPowerFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApPowerFragment.java new file mode 100644 index 0000000..45ab1cc --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/TipApPowerFragment.java @@ -0,0 +1,44 @@ +package com.mm.android.deviceaddmodule.p_ap; + +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; + +public class TipApPowerFragment extends BaseTipFragment { + + public static TipApPowerFragment newInstance() { + TipApPowerFragment fragment = new TipApPowerFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mTipImg.setImageResource(R.drawable.adddevice_netsetting_battery); + mTipImg.setScaleType(ImageView.ScaleType.FIT_XY); + mTipTxt.setText(R.string.add_device_ap_install_battery); + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoApLightPage(this); + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide1Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide1Fragment.java new file mode 100644 index 0000000..a9d09e6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide1Fragment.java @@ -0,0 +1,105 @@ +package com.mm.android.deviceaddmodule.p_ap.hubap; + +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.contract.HubApGuide1Constract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.presenter.HubApGuide1Presenter; +import com.nostra13.universalimageloader.core.ImageLoader; + +public class HubapGuide1Fragment extends BaseTipFragment implements HubApGuide1Constract.View { + HubApGuide1Constract.Presenter mPresenter; + Handler mHandler; + + public static HubapGuide1Fragment newInstance(String sn, String hubType) { + HubapGuide1Fragment fragment = new HubapGuide1Fragment(); + Bundle args = new Bundle(); + args.putString(LCConfiguration.DEVICESN_PARAM, sn); + args.putString(LCConfiguration.HUB_TYPE_PARAM, hubType); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + @Override + protected void initView(View view) { + super.initView(view); + mHelpTxt.setVisibility(View.GONE); + mTipTxt.setVisibility(View.GONE); + mTipImg.setVisibility(View.GONE); + mNextBtn.setVisibility(View.GONE); + } + + @Override + protected void initData() { + super.initData(); + mPresenter = new HubApGuide1Presenter(this); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (getArguments() != null) { + mHandler = new Handler(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) + mPresenter.checkDevIntroductionInfo(getArguments().getString(LCConfiguration.HUB_TYPE_PARAM)); + } + }, 100); + + } + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoHubGuide2Page(this); + } + + @Override + protected void helpAction() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_RESET); + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + @Override + public void updateTip(String tipImg, String tipTxt, String helpTxt) { + if (!TextUtils.isEmpty(tipTxt)) { + mTipTxt.setText(tipTxt); + } + if (!TextUtils.isEmpty(tipTxt)) { + ImageLoader.getInstance().displayImage(tipImg, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + if (!TextUtils.isEmpty(tipTxt)) { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(helpTxt); + } + } + + @Override + public void showInfoView() { + mTipTxt.setVisibility(View.VISIBLE); + mTipImg.setVisibility(View.VISIBLE); + mNextBtn.setVisibility(View.VISIBLE); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide2Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide2Fragment.java new file mode 100644 index 0000000..6c5cd61 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide2Fragment.java @@ -0,0 +1,67 @@ +package com.mm.android.deviceaddmodule.p_ap.hubap; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +public class HubapGuide2Fragment extends BaseTipFragment { + + public static HubapGuide2Fragment newInstance() { + HubapGuide2Fragment fragment = new HubapGuide2Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + protected void initView(View view) { + super.initView(view); + mHelpTxt.setVisibility(View.VISIBLE); + } + + @Override + protected void initData() { + super.initData(); + DeviceIntroductionInfo deviceIntroductionInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_ACCESSORY_MODE_PAIR_OPERATION_INTRODUCTION); + String tipImg = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.HUB_ACCESSORY_MODE_PAIR_STATUS_IMAGE); + String helpTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_ACCESSORY_MODE_RESET_GUIDE_INTRODUCTION); + if (!TextUtils.isEmpty(tipTxt)) + mTipTxt.setText(tipTxt); + if (!TextUtils.isEmpty(tipImg)) + ImageLoader.getInstance().displayImage(tipImg, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + if (!TextUtils.isEmpty(helpTxt)) { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(helpTxt); + } + + } + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoHubGuide3Page(this); + } + + @Override + protected void helpAction() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_AP_RESET); + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide3Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide3Fragment.java new file mode 100644 index 0000000..5450545 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_ap/hubap/HubapGuide3Fragment.java @@ -0,0 +1,76 @@ +package com.mm.android.deviceaddmodule.p_ap.hubap; + +import android.os.Bundle; +import android.support.v4.app.FragmentManager; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CommonEvent; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.greenrobot.eventbus.EventBus; + +public class HubapGuide3Fragment extends BaseTipFragment { + + public static HubapGuide3Fragment newInstance() { + HubapGuide3Fragment fragment = new HubapGuide3Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initView(View view) { + super.initView(view); + mHelpTxt.setVisibility(View.VISIBLE); + mNextBtn.setText(R.string.common_complete); + } + + @Override + protected void initData() { + super.initData(); + DeviceIntroductionInfo deviceIntroductionInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_RESULT_INTRODUCTION); + String tipImg = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_RESULT_PROMPT_IMAGE); + String helpTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_CONFIRM_INTRODUCTION); + if (!TextUtils.isEmpty(tipTxt)) + mTipTxt.setText(tipTxt); + if (!TextUtils.isEmpty(tipImg)) + ImageLoader.getInstance().displayImage(tipImg, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + if (!TextUtils.isEmpty(helpTxt)) { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(helpTxt); + } + } + } + + @Override + protected void nextAction() { + if(getActivity() != null){ + EventBus.getDefault().post(new CommonEvent(CommonEvent.REFRESH_SINGLE_DEVICE_SYNC_ACTION)); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + } + + } + + @Override + protected void helpAction() { + if(getActivity() != null && getActivity().getSupportFragmentManager() != null) + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_bindsuccess/BindSuccessFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_bindsuccess/BindSuccessFragment.java new file mode 100644 index 0000000..a1ed18b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_bindsuccess/BindSuccessFragment.java @@ -0,0 +1,243 @@ +package com.mm.android.deviceaddmodule.p_bindsuccess; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.InputFilter; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import com.lechange.opensdk.utils.NetWorkUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.BindSuccessConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CommonEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.NameLengthFilter; +import com.mm.android.deviceaddmodule.mobilecommon.utils.WordInputFilter; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.presenter.BindSuccessPresenter; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.greenrobot.eventbus.EventBus; + +import java.util.HashMap; + +/** + * 绑定成功页 + **/ +public class BindSuccessFragment extends BaseDevAddFragment implements BindSuccessConstract.View, + View.OnClickListener { + private final int MAXLETHER = 40; + + BindSuccessConstract.Presenter mPresenter; + ImageView mDevImg; + TextView mOK, mModifyDevicePwdTv; + RelativeLayout mBindSuccessRl; + ClearEditText mDevNameEdit; + ScrollView mBindSuccessSv; + + public static BindSuccessFragment newInstance() { + BindSuccessFragment fragment = new BindSuccessFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + String devName = s.toString().trim(); + if (!TextUtils.isEmpty(devName)) { + mOK.setEnabled(true); + mDevNameEdit.removeTextChangedListener(mTextWatcher); + String filterDevName = DeviceAddHelper.strDeviceNameFilter(devName); + if (!filterDevName.equals(devName)) { + mDevNameEdit.setText(filterDevName); + mDevNameEdit.setSelection(filterDevName.length()); + } + mDevNameEdit.addTextChangedListener(mTextWatcher); + } else { + mOK.setEnabled(false); + } + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_bind_success, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.SHARE); + } + + + protected void initView(View view) { + mBindSuccessRl = view.findViewById(R.id.bind_success_rl); + mDevImg = view.findViewById(R.id.dev_img); + mOK = view.findViewById(R.id.tv_next); + mBindSuccessSv = view.findViewById(R.id.bind_success_sv); + mDevNameEdit = view.findViewById(R.id.device_name_input); + mModifyDevicePwdTv = view.findViewById(R.id.tv_modify_device_pwd); + setModifyDevicePwdTvClick(getString(R.string.mobile_common_modify_device_pwd_tip), getString(R.string.mobile_common_tap_to_view), getString(R.string.mobile_common_how_modify_device_pwd)); + mOK.setOnClickListener(this); + + mDevNameEdit.setFilters(new InputFilter[]{new WordInputFilter(WordInputFilter.REX_NAME), new NameLengthFilter(MAXLETHER)}); + mDevNameEdit.addTextChangedListener(mTextWatcher); + } + + protected void initData() { + mPresenter = new BindSuccessPresenter(this); + mPresenter.getDevName(); + } + + @Override + public boolean onBackPressed() { + return super.onBackPressed(); + } + + + @Override + public void updateDevImg(String img) { + ImageLoader.getInstance().displayImage(img, mDevImg, + DeviceAddImageLoaderHelper.getCommonOptions4success()); + } + + + @Override + public String getDevName() { + return mDevNameEdit.getText().toString().trim(); + } + + @Override + public void setDevName(String name) { + if (TextUtils.isEmpty(name)) + return; + + mDevNameEdit.setText(name); + if (!TextUtils.isEmpty(mDevNameEdit.getText().toString())) + mDevNameEdit.setSelection(mDevNameEdit.getText().toString().length()); + } + + @Override + public void completeAction() { + //添加结束哪来回哪,把DeviceAddActivity结束掉 + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + //通知主页、我的设备列表自动刷新 + EventBus.getDefault().post(new CommonEvent(CommonEvent.DEVICE_ADD_SUCCESS_ACTION)); + } + + @Override + public void deviceName(String name) { + setDevName(name); + } + + public void setModifyDevicePwdTvClick(String str1, String str2, String str3) { + SpannableString info = new SpannableString(str1 + str2 + " " + str3); + if (!TextUtils.isEmpty(str1)) { + info.setSpan(null, 0, str1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + if (!TextUtils.isEmpty(str2)) { + info.setSpan(null, str1.length(), str1.length() + str2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + if (!TextUtils.isEmpty(str3)) { + info.setSpan(new ClickableSpan() { + @Override + public void onClick(View widget) { + ProviderManager.getAppProvider().goModifyDevicePwdGuidePage(getActivity()); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(true); + ds.setColor(getResources().getColor(R.color.c0)); + } + }, str1.length() + str2.length(), str1.length() + str2.length() + str3.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + mModifyDevicePwdTv.setText(info); + mModifyDevicePwdTv.setMovementMethod(LinkMovementMethod.getInstance()); + mModifyDevicePwdTv.setHighlightColor(Color.TRANSPARENT); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_next) { + mPresenter.modifyDevName(); + } + } + + /*private void bindDevice() { + //调后台接口 + NetWorkUtil netWorkUtil = NetWorkUtil.instans(); + HashMap map = new HashMap<>(); + map.put("deviceId", deviceSN); + map.put("houseId", SharedpreferencesUtil.get(Constans.HOUSEID, "")); + map.put("code", key); + if (AppIdUtil.isBaseZhiKong()) { + map.put("addressId", localAddAddressId); + } else { + if (null != getIntent().getExtras().get("deviceAddress")) { + map.put("addressId", getIntent().getExtras().get("deviceAddress").toString()); + } else { + map.put("addressId", "1"); + } + } + map.put("deviceModel", "0"); + map.put("deviceType", getIntent().getExtras().get("deviceType").toString()); + map.put("wifiName", getIntent().getExtras().get("ssid").toString()); + if (null != homeListEntity && TextUtils.isEmpty(homeListEntity.getData().get(deviceNumListPosition).getFloorList())) { + if (null != getIntent().getExtras().get("floor")) { + map.put("floor", getIntent().getExtras().get("floor").toString()); + } + } + netWorkUtil.requestPostByAsynewApi(BIND_DEVICE, map, new NetWorkUtil.ReqCallBack() { + @Override + public void onSuccess(String respone) { + Log.i("bindDevice", "onSuccess()" + respone); + SimpleEntty obj = JSON.parseObject(respone, SimpleEntty.class); + mHandler.obtainMessage(successAddDevice).sendToTarget(); + } + + @Override + public void onFail(String message) { + toast("addDevice failed"); + } + }); + }*/ +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/BaseCloudFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/BaseCloudFragment.java new file mode 100644 index 0000000..629f4d3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/BaseCloudFragment.java @@ -0,0 +1,135 @@ +package com.mm.android.deviceaddmodule.p_cloudconnect; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Intent; +import android.graphics.drawable.Animatable; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.CloudConnectConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CircleCountDownView; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.CloudConnectPresenter; + +public abstract class BaseCloudFragment extends BaseDevAddFragment implements CloudConnectConstract.View, CircleCountDownView.OnCountDownFinishListener { + CloudConnectConstract.Presenter mPresenter; + + TextView mTipTxt; + CircleCountDownView mCountdown_view; + ImageView mProgressImg, mCloudImage1, mCloudImage2; + Animatable mCloudAnimation; + + public abstract void goErrorTipPage(); + + public abstract void initAction(); + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_connect_process, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + protected void initView(View view) { + mTipTxt = view.findViewById(R.id.tv_image_show_tip); + mProgressImg = view.findViewById(R.id.cloud_progrees_img); + mCloudImage1 = view.findViewById(R.id.cloud_image1); + mCloudImage2 = view.findViewById(R.id.cloud_image2); + mCountdown_view = view.findViewById(R.id.countdown_view); + mCountdown_view.setCountDownListener(this); + mCloudAnimation = (Animatable) mProgressImg.getDrawable(); + startAnimation(); + } + + protected void initData() { + mPresenter = new CloudConnectPresenter(this); + initAction(); + } + + private void startAnimation() { + mCloudAnimation.start(); + AnimatorSet animatorSet = new AnimatorSet(); + ObjectAnimator cloudImage1Anim = ObjectAnimator.ofFloat(mCloudImage1, "translationX", 0f, 150f, 0f); + cloudImage1Anim.setRepeatMode(ValueAnimator.RESTART); + cloudImage1Anim.setRepeatCount(ValueAnimator.INFINITE); + ObjectAnimator cloudImage2Anim = ObjectAnimator.ofFloat(mCloudImage2, "translationX", 0f, 150f, 0f); + cloudImage2Anim.setRepeatMode(ValueAnimator.RESTART); + cloudImage2Anim.setRepeatCount(ValueAnimator.INFINITE); + animatorSet.play(cloudImage1Anim).with(cloudImage2Anim); + animatorSet.setDuration(3000); + animatorSet.start(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mCountdown_view.stopCountDown(); + if (mCloudAnimation.isRunning()) { + mCloudAnimation.stop(); + } + mPresenter.recyle(); + } + + @Override + public void countDownFinished() { + mPresenter.recyle(); + DeviceAddModel.newInstance().setLoop(false); + if (mPresenter.isWifiOfflineConfiMode()) { + toast(R.string.add_device_config_failed); + completeAction(); + mPresenter.stopConnectTiming(); + return; + } + goErrorTipPage(); + } + + @Override + public void completeAction() { + if (getActivity() != null) getActivity().finish(); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER); + } + + @Override + public void goNotSupportBuindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND); + } + + @Override + public void goErrorTipPage(int errorCode) { + PageNavigationHelper.gotoErrorTipPage(this, errorCode); + } + + @Override + public void goMainbind(String sn, String code, String encryptPwd) { + Intent intent = new Intent(); //Itent就是我们要发送的内容 + intent.setAction("goMainbind"); //设置你这个广播的action,只有和这个action一样的接受者才能接受者才能接收广播 + intent.putExtra("sn", sn); + intent.putExtra("code", code); + intent.putExtra("encryptPwd", encryptPwd); + if (intent != null) { + getContext().sendBroadcast(intent); //发送广播 + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/CloudConnectFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/CloudConnectFragment.java new file mode 100644 index 0000000..6feb220 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_cloudconnect/CloudConnectFragment.java @@ -0,0 +1,89 @@ +package com.mm.android.deviceaddmodule.p_cloudconnect; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; + +/** + * 设备连接云平台进程展示页 + */ +public class CloudConnectFragment extends BaseCloudFragment{ + private static final String BASECLOUDTYPE = "BaseCloudType"; + + public static CloudConnectFragment newInstance() { + CloudConnectFragment fragment = new CloudConnectFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + public static CloudConnectFragment newInstance(boolean isBindDevice) { + CloudConnectFragment fragment = new CloudConnectFragment(); + Bundle args = new Bundle(); + args.putBoolean(BASECLOUDTYPE,isBindDevice); + fragment.setArguments(args); + return fragment; + } + + @Override + public void goBindSuceesPage() { + PageNavigationHelper.gotoBindSuccessPage(this); + } + + @Override + public void goErrorTipPage() { + mPresenter.stopConnectTiming(); + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.CLOUND_CONNECT_QUERY_STATUS_TIMEOUT); + } + + @Override + public void goBindDevicePage() { + mTipTxt.setText(R.string.add_device_binding_to_account); + mPresenter.bindDevice(); + } + + @Override + public void setCountDownTime(int time) { + mCountdown_view.setCountdownTime(time); + } + + @Override + public void setMiddleTime(int time) { + mCountdown_view.setMiddleTime(time); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goDevSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this); + } + + @Override + public void initAction() { + boolean isBindDevice = false; + if(getArguments() != null && getArguments().containsKey(BASECLOUDTYPE)){ + isBindDevice = getArguments().getBoolean(BASECLOUDTYPE); + } + + mCountdown_view.startCountDown(); + + if(isBindDevice) { + goBindDevicePage(); + } else { + mTipTxt.setText(R.string.add_device_connect_cloud_please_wait); + mPresenter.getDeviceInfo(); + mPresenter.startConnectTiming(); + } + } + + @Override + public void middleTimeUp() { + mPresenter.notifyMiddleTimeUp(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devicelocal/TipDeviceLocalFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devicelocal/TipDeviceLocalFragment.java new file mode 100644 index 0000000..62774ba --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devicelocal/TipDeviceLocalFragment.java @@ -0,0 +1,92 @@ +package com.mm.android.deviceaddmodule.p_devicelocal; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.FragmentManager; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.greenrobot.eventbus.EventBus; + +/** + * 设备本地配网 + */ +public class TipDeviceLocalFragment extends BaseTipFragment { + + public static TipDeviceLocalFragment newInstance() { + TipDeviceLocalFragment fragment = new TipDeviceLocalFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + @Override + protected void initView(View view) { + super.initView(view); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + + mConfirmCheck.setVisibility(View.GONE); + mNextBtn.setVisibility(View.VISIBLE); + mNextBtn.setText(R.string.common_confirm); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo= DeviceAddModel.newInstance().getDeviceInfoCache(); + DeviceIntroductionInfo deviceIntroductionInfo = deviceAddInfo.getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipImage = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.LOCATION_MODE_OPERATION_IMAGE); + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.LOCATION_MODE_OPERATION_INTRODUCTION); + if (!TextUtils.isEmpty(tipImage)) { + ImageLoader.getInstance().displayImage(tipImage, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + if (!TextUtils.isEmpty(tipTxt)) { + mTipTxt.setText(tipTxt); + + } + } + } + + @Override + protected void nextAction() { + if (getActivity() != null) { + if (DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode() + || DeviceAddInfo.DeviceAddType.HUB.equals(DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType())) { + ProviderManager.getDeviceAddCustomProvider().goHomePage(getActivity());//离线配网模式,跳转到主页 + } else { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + } + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevLoginFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevLoginFragment.java new file mode 100644 index 0000000..fa3c130 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevLoginFragment.java @@ -0,0 +1,171 @@ +package com.mm.android.deviceaddmodule.p_devlogin; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.DevLoginConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.presenter.DevLoginPresenter; + +import org.greenrobot.eventbus.EventBus; + +import java.io.Serializable; + +/** + * 设备登录页面 + */ +public class DevLoginFragment extends BaseDevAddFragment implements DevLoginConstract.View, + View.OnClickListener, ClearEditText.ITextChangeListener { + DevLoginConstract.Presenter mPresenter; + ClearPasswordEditText mPwdEdit; + TextView mNext; + Handler mHandler = new Handler(); + long mEventStartTime; //统计开始时间 + + public static DevLoginFragment newInstance() { + DevLoginFragment fragment = new DevLoginFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_dev_login, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mEventStartTime = System.currentTimeMillis(); + } + + protected void initView(View view) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + mNext = view.findViewById(R.id.tv_input_ok); + mPwdEdit = view.findViewById(R.id.et_device_pwd); + mPwdEdit.openEyeMode(ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA); + mNext.setOnClickListener(this); + UIUtils.setEnabledEX(false, mNext); + mPwdEdit.setTextChangeListener(this); + } + + protected void initData() { + mPresenter = new DevLoginPresenter(this); + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_input_ok) { + mPresenter.devLogin(); + } + } + + @Override + public String getDevicePassword() { + return mPwdEdit.getText().toString(); + } + + @Override + public void goSoftAPWifiListPage() { + PageNavigationHelper.gotoSoftApWifiListPage(this); + } + + @Override + public void goDeviceBindPage() { + PageNavigationHelper.gotoDeviceBindPage(this); + } + + @Override + public void goBindSuceesPage() { + PageNavigationHelper.gotoBindSuccessPage(this); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER); + } + + @Override + public void goErrorTipPage(int errorCode) { + PageNavigationHelper.gotoErrorTipPage(this, errorCode); + } + + @Override + public void completeAction() { + if (getActivity() != null) getActivity().finish(); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goDevSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this); + } + + @Override + public void goMainbind(String sn, String code, String encryptPwd) { + Intent intent = new Intent(); //Itent就是我们要发送的内容 + intent.setAction("goMainbind"); //设置你这个广播的action,只有和这个action一样的接受者才能接受者才能接收广播 + intent.putExtra("sn", sn); + intent.putExtra("code", code); + intent.putExtra("encryptPwd", encryptPwd); + if (null != intent) { + getContext().sendBroadcast(intent); //发送广播 + } + } + + @Override + public void afterChanged(EditText v, Editable s) { + + } + + @Override + public void beforeChanged(EditText v, CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(EditText v, CharSequence text, int start, int lengthBefore, int lengthAfter) { + UIUtils.setEnabledEX(text.length() > 0, mNext); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevSecCodeFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevSecCodeFragment.java new file mode 100644 index 0000000..d226d62 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_devlogin/DevSecCodeFragment.java @@ -0,0 +1,124 @@ +package com.mm.android.deviceaddmodule.p_devlogin; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.DevSecCodeConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.presenter.DevSecCodePresenter; + +import org.greenrobot.eventbus.EventBus; + +/** + * 设备安全码页面 + */ +public class DevSecCodeFragment extends BaseDevAddFragment implements DevSecCodeConstract.View, View.OnClickListener { + DevSecCodeConstract.Presenter mPresenter; + ClearEditText mUserInputEdit; + TextView mNext; + Handler mHandler = new Handler(); + + public static DevSecCodeFragment newInstance() { + DevSecCodeFragment fragment = new DevSecCodeFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_dev_sec_code, container, false); + } + + @Override + protected void initView(View view) { + mNext = view.findViewById(R.id.next_btn); + mUserInputEdit = view.findViewById(R.id.et_user_input); + mNext.setOnClickListener(this); + } + + protected void initData() { + mPresenter = new DevSecCodePresenter(this); + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.next_btn) { + mPresenter.validate(); + } + } + + @Override + public String getDeviceSecCode() { + return mUserInputEdit.getText().toString(); + } + + @Override + public void goErrorTipPage(int errorCode) { + PageNavigationHelper.gotoErrorTipPage(this, errorCode); + } + + @Override + public void goBindSuceesPage() { + PageNavigationHelper.gotoBindSuccessPage(this); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER); + } + + @Override + public void completeAction() { + if (getActivity() != null) getActivity().finish(); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goDevSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this); + } + + @Override + public void goMainbind(String sn, String code, String encryptPwd) { + Intent intent = new Intent(); //Itent就是我们要发送的内容 + intent.setAction("goMainbind"); //设置你这个广播的action,只有和这个action一样的接受者才能接受者才能接收广播 + intent.putExtra("sn", sn); + intent.putExtra("code", code); + intent.putExtra("encryptPwd", encryptPwd); + if (null != intent) { + getContext().sendBroadcast(intent); //发送广播 + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/ErrorTipFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/ErrorTipFragment.java new file mode 100644 index 0000000..07e3c89 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/ErrorTipFragment.java @@ -0,0 +1,157 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.ErrorTipConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.presenter.ErrorTipPresenter; +import com.nostra13.universalimageloader.core.ImageLoader; + +/** + * 设备添加错误提示页 + */ +public class ErrorTipFragment extends BaseDevAddFragment implements ErrorTipConstract.View, View.OnClickListener { + ErrorTipConstract.Presenter mPresenter; + public static String ERROR_PARAMS = "error_params"; + ImageView mTipImage; + TextView mTipTxt, mTipTxt2, mHelpLinkTxt, mHelpPhoneTv; + View mHelpLayout; + + private PermissionHelper mPermissionHelper; + + public static ErrorTipFragment newInstance(int errorCode) { + ErrorTipFragment fragment = new ErrorTipFragment(); + Bundle args = new Bundle(); + args.putInt(ERROR_PARAMS, errorCode); + fragment.setArguments(args); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_error_tip, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (mPresenter.isUserBindTipPage()) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.BLANK); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + + protected void initView(View view) { + mTipImage = view.findViewById(R.id.tip_img); + mTipTxt = view.findViewById(R.id.tip_txt); + mTipTxt2 = view.findViewById(R.id.tip_txt2); + mHelpLinkTxt = view.findViewById(R.id.help_link); + mHelpLinkTxt.setOnClickListener(this); + mHelpLayout = view.findViewById(R.id.ll_help); + mHelpPhoneTv = view.findViewById(R.id.tv_help_phone); + mHelpLayout.setVisibility(View.GONE); + + } + + protected void initData() { + mPresenter = new ErrorTipPresenter(this); + if (getArguments() != null) { + int errorcode = getArguments().getInt(ERROR_PARAMS); + mPresenter.dispatchError(errorcode); + } + } + + @Override + public Fragment getParent() { + return this; + } + + @Override + public boolean onBackPressed() { + if (mPresenter.isUserBindTipPageByBind()) { + if(getActivity() != null) getActivity().finish(); + } else if (mPresenter.isResetPage()) { + if(getActivity() != null) getActivity().getSupportFragmentManager().popBackStack(); //退回到上个界面 + } + return mPresenter.isResetPage(); + } + + @Override + public void updateInfo(String info, String img, boolean isNeedMatch) { + if (isNeedMatch) { + setImageMatchScreen(); + } + if (!TextUtils.isEmpty(img)) { + ImageLoader.getInstance().displayImage(img, mTipImage, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + if (!TextUtils.isEmpty(info)) { + mTipTxt.setText(info); + } + } + + @Override + public void updateInfo(int infoId, int tip2Id, String img, boolean isNeedMatch) { + updateInfo(infoId, img, isNeedMatch); + if(tip2Id!=0) + mTipTxt2.setText(tip2Id); + } + + @Override + public void updateInfo(int infoId, String img, boolean isNeedMatch) { + if (isNeedMatch) { + setImageMatchScreen(); + } + if (!TextUtils.isEmpty(img)) { + ImageLoader.getInstance().displayImage(img, mTipImage, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + mTipTxt.setText(infoId); + } + + @Override + public void hideTipTxt() { + mTipTxt.setVisibility(View.GONE); + mTipTxt2.setVisibility(View.GONE); + } + + @Override + public void hideHelp() { + mHelpLayout.setVisibility(View.GONE); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.help_link) { + ProviderManager.getDeviceAddCustomProvider().goFAQWebview(getActivity()); + } + } + + private void setImageMatchScreen() { + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mTipImage.getLayoutParams(); + layoutParams.height = /*LinearLayout.LayoutParams.WRAP_CONTENT*/UIUtils.dp2px(getContextInfo(), 300); + layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT; + layoutParams.topMargin=0; + mTipImage.setLayoutParams(layoutParams); + mTipImage.setScaleType(ImageView.ScaleType.FIT_CENTER); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipAboutWifiPwdFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipAboutWifiPwdFragment.java new file mode 100644 index 0000000..20a4407 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipAboutWifiPwdFragment.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; + +/** + * 不支持5G + */ +public class TipAboutWifiPwdFragment extends BaseDevAddFragment { + public static TipAboutWifiPwdFragment newInstance() { + TipAboutWifiPwdFragment fragment = new TipAboutWifiPwdFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_about_wifi_pwd, container, false); + } + + @Override + protected void initView(View view) { + } + + @Override + protected void initData() { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipConnectFailFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipConnectFailFragment.java new file mode 100644 index 0000000..9d963c5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipConnectFailFragment.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; + +/** + * 不支持5G + */ +public class TipConnectFailFragment extends BaseDevAddFragment { + public static TipConnectFailFragment newInstance() { + TipConnectFailFragment fragment = new TipConnectFailFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_connect_fail, container, false); + } + + @Override + protected void initView(View view) { + } + + @Override + protected void initData() { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipNotSupport5GFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipNotSupport5GFragment.java new file mode 100644 index 0000000..b468e67 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipNotSupport5GFragment.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; + +/** + * 不支持5G + */ +public class TipNotSupport5GFragment extends BaseDevAddFragment { + public static TipNotSupport5GFragment newInstance() { + TipNotSupport5GFragment fragment = new TipNotSupport5GFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_not_support_5g, container, false); + } + + @Override + protected void initView(View view) { + } + + @Override + protected void initData() { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipTimeoutFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipTimeoutFragment.java new file mode 100644 index 0000000..c14cc12 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipTimeoutFragment.java @@ -0,0 +1,84 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.support.v4.app.FragmentManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.TimeoutConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.TimeoutPresenter; + +/** + * 连接超时提示页 + */ +public class TipTimeoutFragment extends BaseDevAddFragment implements TimeoutConstract.View, View.OnClickListener { + TimeoutConstract.Presenter mPresenter; + public static String ERROR_PARAMS = "error_params"; + public static String DEV_TYPE_PARAMS = "dev_type_params"; + TextView mActionTxt1; + + public static TipTimeoutFragment newInstance(int errorCode, String timeoutDevTypeModel) { + TipTimeoutFragment fragment = new TipTimeoutFragment(); + Bundle args = new Bundle(); + args.putInt(ERROR_PARAMS, errorCode); + args.putString(DEV_TYPE_PARAMS, timeoutDevTypeModel); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_tip_timeout, container, false); + } + + protected void initView(View view) { + mActionTxt1 = view.findViewById(R.id.tv_action1); + mActionTxt1.setOnClickListener(this); + } + + protected void initData() { + mPresenter = new TimeoutPresenter(this); + if (getArguments() != null) { + int errorcode = getArguments().getInt(ERROR_PARAMS); + String devtypeModel = getArguments().getString(DEV_TYPE_PARAMS); + mPresenter.setErrorData(errorcode, devtypeModel); + if (errorcode == DeviceAddHelper.ErrorCode.WIRED_WIRELESS_ERROR_CONFIG_TIMEOUT || errorcode == DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ALWAYS || errorcode == DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_FLASH) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (DeviceAddInfo.ConfigMode.LAN.name().equalsIgnoreCase(deviceAddInfo.getConfigMode()) || !deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_action1) { + mPresenter.dispatchAction1(); + } + } + + @Override + public void showAView() { + mActionTxt1.setVisibility(View.VISIBLE); + mActionTxt1.setText(R.string.add_device_yellow_light_twinkle); + } + + @Override + public void goScanPage() { + getActivity().getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipUserBindFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipUserBindFragment.java new file mode 100644 index 0000000..365bc06 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipUserBindFragment.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; + +/** + * 帐号被绑定提示 + */ +public class TipUserBindFragment extends BaseDevAddFragment { + public static TipUserBindFragment newInstance() { + TipUserBindFragment fragment = new TipUserBindFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_user_bind, container, false); + } + + @Override + protected void initView(View view) { + } + + @Override + protected void initData() { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipWifiNameFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipWifiNameFragment.java new file mode 100644 index 0000000..f441040 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_errortip/TipWifiNameFragment.java @@ -0,0 +1,35 @@ +package com.mm.android.deviceaddmodule.p_errortip; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; + +/** + * 不支持5G + */ +public class TipWifiNameFragment extends BaseDevAddFragment { + public static TipWifiNameFragment newInstance() { + TipWifiNameFragment fragment = new TipWifiNameFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_wifi_name, container, false); + } + + @Override + protected void initView(View view) { + } + + @Override + protected void initData() { + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/InitFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/InitFragment.java new file mode 100644 index 0000000..c07bde6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/InitFragment.java @@ -0,0 +1,139 @@ +package com.mm.android.deviceaddmodule.p_init; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.InitContract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.presenter.InitPresenter; + +/** + * 设备初始化页面 + */ +public class InitFragment extends BaseDevAddFragment implements InitContract.View, View.OnClickListener { + static String DEVICE_PARAM="device_param"; + InitContract.Presenter mPresenter; + private ClearPasswordEditText mPasswordNewEdt;; + private TextView mInitTv; + long mEventStartTime; //统计开始时间 + + public static InitFragment newInstance(DEVICE_NET_INFO_EX device_net_info_ex) { + InitFragment fragment = new InitFragment(); + Bundle args = new Bundle(); + args.putSerializable(DEVICE_PARAM,device_net_info_ex); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + String pwd = StringUtils.strPsswordFilter(s.toString()); + if (!pwd.equals(s.toString())) { + mPasswordNewEdt.setText(pwd); + mPasswordNewEdt.setSelection(pwd.length()); + } + mInitTv.setEnabled(pwd.length() >= 8); + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_init, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + mEventStartTime = System.currentTimeMillis(); + } + + protected void initView(View view) { + setProgressDialogCancelable(false); + mPasswordNewEdt = view.findViewById(R.id.et_pwd_new); + mPasswordNewEdt.openEyeMode(ProviderManager.getAppProvider().getAppType()!= LCConfiguration.APP_LECHANGE_OVERSEA); + mInitTv = view.findViewById(R.id.tv_init); + mInitTv.setEnabled(false); + mInitTv.setOnClickListener(this); + mPasswordNewEdt.addTextChangedListener(mTextWatcher); + } + + protected void initData() { + mPresenter = new InitPresenter(this); + if(getArguments()!=null){ + DEVICE_NET_INFO_EX device_net_info_ex=(DEVICE_NET_INFO_EX) getArguments().getSerializable(DEVICE_PARAM); + mPresenter.setDeviceEX(device_net_info_ex); + mPresenter.checkDevice(); + } + mPresenter.playTipSound(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mPresenter.recyle(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_init) { + if(mPresenter.isPwdValid()) { + mPresenter.startDevInitByIp(); + } + } + } + + @Override + public int getMusicRes() { + return R.raw.voiceprompt_lc_device_psw; + } + + @Override + public String getInitPwd() { + return mPasswordNewEdt.getText().toString(); + } + + @Override + public void goSoftAPWifiListPage() { + PageNavigationHelper.gotoSoftApWifiListPage(this); + } + + @Override + public void goConnectCloudPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + + @Override + public void goErrorTipPage() { + //toast(R.string.add_device_init_failed_tip); + PageNavigationHelper.gotoErrorTipPage(this,DeviceAddHelper.ErrorCode.INIT_ERROR_INIT_FAILED); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/SecurityCheckFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/SecurityCheckFragment.java new file mode 100644 index 0000000..f5817ac --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_init/SecurityCheckFragment.java @@ -0,0 +1,113 @@ +package com.mm.android.deviceaddmodule.p_init; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.LinearInterpolator; +import android.view.animation.TranslateAnimation; +import android.widget.ImageView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.SecurityCheckConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CircleCountDownView; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.SecurityCheckPresenter; + +/** + * 设备初始安全检查页面 + */ +public class SecurityCheckFragment extends BaseDevAddFragment implements SecurityCheckConstract.View, CircleCountDownView.OnCountDownFinishListener { + SecurityCheckConstract.Presenter mPresenter; + CircleCountDownView mCountdown_view; + TranslateAnimation mAnimation; + ImageView mScanLine; + long mEventStartTime; //统计开始时间 + + public static SecurityCheckFragment newInstance() { + SecurityCheckFragment fragment = new SecurityCheckFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_security_check, container, false); + } + + protected void initView(View view){ + mScanLine= view.findViewById(R.id.scan_line); + mCountdown_view= view.findViewById(R.id.countdown_view); + mCountdown_view.setCountDownListener(this); + mCountdown_view.startCountDown(); + + mAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0f, TranslateAnimation.ABSOLUTE, 0f, + TranslateAnimation.RELATIVE_TO_PARENT, 0.2f, TranslateAnimation.RELATIVE_TO_PARENT, 0.7f); + mAnimation.setDuration(1500); + mAnimation.setRepeatCount(-1); + mAnimation.setRepeatMode(Animation.REVERSE); + mAnimation.setInterpolator(new LinearInterpolator()); + mScanLine.setAnimation(mAnimation); + mEventStartTime = System.currentTimeMillis(); + } + + protected void initData(){ + mPresenter=new SecurityCheckPresenter(this); + mPresenter.checkDevice(); + //安全检查页更多只能A方案 + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mPresenter.recyle(); + mCountdown_view.stopCountDown(); + } + + @Override + public void countDownFinished() { + //超时 + mPresenter.recyle(); + goErrorTipPage(); + } + + @Override + public void middleTimeUp() { + + } + + @Override + public void goInitPage(DEVICE_NET_INFO_EX device_net_info_ex) { + PageNavigationHelper.gotoInitPage(this,device_net_info_ex); + } + + @Override + public void goErrorTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.INIT_ERROR_SERCRITY_CHECK_TIMEOUT); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goSoftApWifiListPage(boolean isNotNeedLogin) { + PageNavigationHelper.gotoSoftApWifiListPage(this, isNotNeedLogin); + } + + @Override + public void goCloudConnetPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchFragment.java new file mode 100644 index 0000000..67c6647 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchFragment.java @@ -0,0 +1,123 @@ +package com.mm.android.deviceaddmodule.p_inputsn; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.DispatchContract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.presenter.DispatchPresenter; +import com.mm.android.deviceaddmodule.views.AddBoxTipDialog; + +public class DeviceDispatchFragment extends BaseDevAddFragment implements DispatchContract.View { + + private DispatchContract.Presenter mPresenter; + private boolean isFirst = true; + + public static DeviceDispatchFragment newInstance() { + DeviceDispatchFragment fragment = new DeviceDispatchFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initView(View view) { + + } + + @Override + protected void initData() { + mPresenter = new DispatchPresenter(this); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_device_dispatch, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (isFirst || DeviceDispatchHelper.isReAdd()) { + mPresenter.dispatchResult(); + DeviceDispatchHelper.reset(); + } else { + if (getActivity() != null) getActivity().finish(); + } + isFirst = false; + } + + @Override + public void goTypeChoosePage() { + PageNavigationHelper.gotoTypeChoosePage(this, false); + } + + @Override + public void goNotSupportBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND, false); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER, false); + } + + @Override + public void showAddBoxTip() { + if (!PreferencesHelper.getInstance(getActivity()).getBoolean( + LCConfiguration.SHOW_ADD_BOX_TIP)) { + AddBoxTipDialog a = new AddBoxTipDialog(); + a.setDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + goCloudConnectPage(); + } + }); + a.show(getActivity().getSupportFragmentManager(), a.getClass().getName()); + } else { + goCloudConnectPage(); + } + } + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this, false); + } + + @Override + public void goDeviceLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this, false); + } + + @Override + public void goSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this, false); + } + + @Override + public void goDeviceBindPage() { + PageNavigationHelper.gotoDeviceBindPage(this, false); + } + + @Override + public void goIMEIInputPage() { + PageNavigationHelper.gotoIMEIInputPage(this, false); + } + + @Override + public void onDestroy() { + super.onDestroy(); + DeviceDispatchHelper.reset(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchHelper.java new file mode 100644 index 0000000..00032a8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/DeviceDispatchHelper.java @@ -0,0 +1,16 @@ +package com.mm.android.deviceaddmodule.p_inputsn; + +public class DeviceDispatchHelper { + private static boolean reAdd = false; + public static void setReAdd(boolean reAdd){ + DeviceDispatchHelper.reAdd = reAdd; + } + + public static boolean isReAdd(){ + return reAdd; + } + + public static void reset(){ + reAdd = false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/IMEIInputFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/IMEIInputFragment.java new file mode 100644 index 0000000..e4f6350 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/IMEIInputFragment.java @@ -0,0 +1,132 @@ +package com.mm.android.deviceaddmodule.p_inputsn; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +/** + * IMEI输入页 + */ +public class IMEIInputFragment extends BaseDevAddFragment implements View.OnClickListener + ,ClearEditText.ITextChangeListener { + private ClearEditText mUserInputET; // imei输入框 + private TextView mNextBtn; + + public static IMEIInputFragment newInstance() { + IMEIInputFragment fragment = new IMEIInputFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_imei_input, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.BLANK); + } + + protected void initView(View view){ + mUserInputET= view.findViewById(R.id.et_user_input); + mUserInputET.setTextChangeListener(this); + mNextBtn= view.findViewById(R.id.next_btn); + mNextBtn.setOnClickListener(this); + mNextBtn.setEnabled(false); + } + + @Override + protected void initData() { + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mNextBtn.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + /** + * 处理输入 + */ + private void handleInputDone() { + String inputIMEI = mUserInputET.getText().toString().trim().toUpperCase(); + if (isIMEIInValid(inputIMEI)) { + return; + } + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setImeiCode(inputIMEI); + + goNBTipPage(); + } + + private boolean isIMEIInValid(String imei) { + if(TextUtils.isEmpty(imei) + || imei.length() < 15 || imei.length() > 17){ + return true; + } + return false; + } + + @Override + public void onClick(View v) { + int id=v.getId(); + if(R.id.next_btn==id){ + handleInputDone(); + } + } + + @Override + public void afterChanged(EditText v, Editable s) { + mNextBtn.setEnabled(!isIMEIInValid(mUserInputET.getText().toString())); + } + + @Override + public void beforeChanged(EditText v, CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(EditText v, CharSequence text, int start, int lengthBefore, int lengthAfter) { + String str = StringUtils.snFilter(text.toString()); + if (!str.equals(text.toString())) { + v.setText(str); + v.setSelection(str.length()); + } + } + + + private void goNBTipPage() { + PageNavigationHelper.gotoNBTipPage(this); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ManualInputFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ManualInputFragment.java new file mode 100644 index 0000000..06ec05d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ManualInputFragment.java @@ -0,0 +1,202 @@ +package com.mm.android.deviceaddmodule.p_inputsn; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.ManualInputConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResult; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.NetWorkHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.presenter.ManualInputPresenter; +import com.mm.android.deviceaddmodule.views.AddBoxTipDialog; + +import org.greenrobot.eventbus.EventBus; + +/** + * 手动输入设备序列号页 + */ +public class ManualInputFragment extends BaseDevAddFragment implements ManualInputConstract.View, View.OnClickListener + , ClearEditText.ITextChangeListener { + ManualInputConstract.Presenter mPresenter; + private ClearEditText mUserInputET; // 序列号输入框 + private ClearEditText mInputScET; // sc码输入框 + private TextView mNextBtn; + + public static ManualInputFragment newInstance() { + ManualInputFragment fragment = new ManualInputFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_manual_input, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.BLANK); + } + + protected void initView(View view) { + mUserInputET = view.findViewById(R.id.et_user_input); + mUserInputET.setTextChangeListener(this); + mNextBtn = view.findViewById(R.id.next_btn); + mNextBtn.setOnClickListener(this); + mNextBtn.setEnabled(false); + + mInputScET = view.findViewById(R.id.et_input_sc); + mInputScET.setTextChangeListener(this); + } + + @Override + protected void initData() { + mPresenter = new ManualInputPresenter(this); + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mNextBtn.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + /** + * 处理输入 + */ + private void handleInputDone() { + String inputSn = mUserInputET.getText().toString().trim().toUpperCase(); + String inputSc = mInputScET.getText().toString().trim(); + if (mPresenter.isSnInValid(inputSn)) { + return; + } + if (mPresenter.isScCodeInValid(inputSc)) { + return; + } + if (inputSc.length() == 7) { + toast(R.string.add_device_input_corrent_sc_tip); + return; + } + ScanResult scanResult = mPresenter.parseScanStr(inputSn, inputSc); + mPresenter.getDeviceInfo(scanResult.getSn(), scanResult.getMode()); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (R.id.next_btn == id) { + if (NetWorkHelper.isConnected(getActivity())) { + handleInputDone(); + } else { + toast(R.string.mobile_common_bec_common_timeout); + } + } + } + + @Override + public void afterChanged(EditText v, Editable s) { + mNextBtn.setEnabled(!mPresenter.isSnInValid(mUserInputET.getText().toString()) && !mPresenter.isScCodeInValid(mInputScET.getText().toString())); + } + + @Override + public void beforeChanged(EditText v, CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(EditText v, CharSequence text, int start, int lengthBefore, int lengthAfter) { + String str = StringUtils.snFilter(text.toString()); + if (!str.equals(text.toString())) { + v.setText(str); + v.setSelection(str.length()); + } + } + + @Override + public void goTypeChoosePage() { + PageNavigationHelper.gotoTypeChoosePage(this); + } + + @Override + public void goNotSupportBindTipPage() { + //TODO 手输序列号的逻辑里面应该不存在不支持类型的设备在线的情况 + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER); + } + + @Override + public void showAddBoxTip() { + if (!PreferencesHelper.getInstance(getActivity()).getBoolean( + LCConfiguration.SHOW_ADD_BOX_TIP)) { + AddBoxTipDialog a = new AddBoxTipDialog(); + a.setDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + goCloudConnectPage(); + } + }); + a.show(getActivity().getSupportFragmentManager(), a.getClass().getName()); + } else { + goCloudConnectPage(); + } + } + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + + @Override + public void goDeviceLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this); + } + + @Override + public void goDeviceBindPage() { + PageNavigationHelper.gotoDeviceBindPage(this); + } + + @Override + public void goIMEIInputPage() { + PageNavigationHelper.gotoIMEIInputPage(this); + } + + @Override + public void goMainbind(String sn, String code, String encryptPwd) { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ScanFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ScanFragment.java new file mode 100644 index 0000000..9c51329 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/ScanFragment.java @@ -0,0 +1,273 @@ +package com.mm.android.deviceaddmodule.p_inputsn; + +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.google.zxing.Result; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.ScanContract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResult; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.p_inputsn.scanresult.DecodeImgCallback; +import com.mm.android.deviceaddmodule.p_inputsn.scanresult.DecodeImgThread; +import com.mm.android.deviceaddmodule.p_inputsn.scanresult.ImageUtil; +import com.mm.android.deviceaddmodule.presenter.ScanPresenter; +import com.mm.android.deviceaddmodule.views.AddBoxTipDialog; +import com.mm.android.dhqrscanner.BaseScannerView; +import com.mm.android.dhqrscanner.DHScannerView; + +import static android.app.Activity.RESULT_OK; + +/** + * 二维码扫描页 + */ +public class ScanFragment extends BaseDevAddFragment implements ScanContract.View, BaseScannerView.HandleDecodeResultListener + , View.OnClickListener { + ScanContract.Presenter mPresenter; + DHScannerView mDHScannerView; //二维码扫描控件 + TextView mNext, mFlashTv, mPhone; + boolean isLight = false; //闪光灯是否开启 + public static final int REQUEST_IMAGE = 10; + + + public static ScanFragment newInstance() { + ScanFragment fragment = new ScanFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + public void changeFlashLight() { + isLight = !isLight; + mDHScannerView.onFlash(isLight); + Drawable drawable = getResources().getDrawable(isLight ? R.drawable.adddevice_icon_falshlight_h : R.drawable.adddevice_icon_falshlight_n); + drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight()); + mFlashTv.setCompoundDrawables(null, drawable, null, null); + mFlashTv.setText(isLight ? R.string.add_device_falshlight_on : R.string.add_device_falshlight_off); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_scan, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + + protected void initData() { + mPresenter = new ScanPresenter(this); + mPresenter.resetCache();//进入扫描页,清空缓存 + } + + protected void initView(View view) { + mDHScannerView = view.findViewById(R.id.dh_scanview); + mDHScannerView.setHandleDecodeResuleListener(this); + mNext = view.findViewById(R.id.next_btn); + mNext.setOnClickListener(this); + mPhone = view.findViewById(R.id.phone_btn); + mPhone.setOnClickListener(this); + mFlashTv = view.findViewById(R.id.tv_flash); + mFlashTv.setOnClickListener(this); + } + + @Override + public void onResume() { + super.onResume(); + mDHScannerView.onScanResume(); + } + + @Override + public void onPause() { + super.onPause(); + mDHScannerView.onScanPause(); + mDHScannerView.onFlash(false); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mPresenter.recyle(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mDHScannerView.onScanDestory(); + } + + + @Override + public void handleDecodeResult(String result, byte[] bytes, int with, int height) { + if(!isViewActive())return; + if (TextUtils.isEmpty(result)) { + mDHScannerView.onScanResume(); + } else { + LogUtil.debugLog("ScanFragment", "result : " + result); + ScanResult scanResult = mPresenter.parseScanStr(result, ""); + String sn = scanResult.getSn().trim(); + if(!isLetterDigit(sn)) { + toast(R.string.add_device_qrcode_error_tip); + PageNavigationHelper.gotoManualInputPage(this); + return; + } + mPresenter.getDeviceInfo(scanResult.getSn().trim(), scanResult.getMode()); + } + } + + private boolean isLetterDigit(String str) { + // 序列号二维码规则字母 + 数字,长度 10 - 32位 + String regex = "^[a-z0-9A-Z]{10,32}$"; + return str.matches(regex); + } + + @Override + public void openCamerError() { + + } + + @Override + public void showToastInfo(String msg) { + toast(msg); + mDHScannerView.onScanResume(); + } + + @Override + public void showToastInfo(int msgId) { + toast(msgId); + mDHScannerView.onScanResume(); + } + + @Override + public void showToastInfo(int msgId, String msg) { + if (!TextUtils.isEmpty(msg)) { + toast(msg); + } else { + toast(msgId); + } + mDHScannerView.onScanResume(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (R.id.next_btn == id) { + PageNavigationHelper.gotoManualInputPage(this); + } else if(R.id.tv_flash == id) { + changeFlashLight(); + } else if(R.id.phone_btn == id) { + /*打开相册*/ + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_PICK); + intent.setType("image/*"); + startActivityForResult(intent, REQUEST_IMAGE); + } + } + + @Override + public void goTypeChoosePage() { + PageNavigationHelper.gotoTypeChoosePage(this); + } + + @Override + public void goNotSupportBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND); + } + + @Override + public void goOtherUserBindTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER); + } + + @Override + public void showAddBoxTip() { + if (!PreferencesHelper.getInstance(getActivity()).getBoolean( + LCConfiguration.SHOW_ADD_BOX_TIP)) { + AddBoxTipDialog a = new AddBoxTipDialog(); + a.setDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + goCloudConnectPage(); + } + }); + a.show(getActivity().getSupportFragmentManager(), a.getClass().getName()); + } else { + goCloudConnectPage(); + } + } + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + + @Override + public void goDeviceLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goSecCodePage() { + PageNavigationHelper.gotoDevSecCodePage(this); + } + + @Override + public void goDeviceBindPage() { + PageNavigationHelper.gotoDeviceBindPage(this); + } + + @Override + public void goIMEIInputPage() { + PageNavigationHelper.gotoIMEIInputPage(this); + } + + @Override + public void goMainbind(String sn, String code, String encryptPwd) { + Intent intent = new Intent(); //Itent就是我们要发送的内容 + intent.setAction("goMainbind"); //设置你这个广播的action,只有和这个action一样的接受者才能接受者才能接收广播 + intent.putExtra("sn", sn); + intent.putExtra("code", code); + intent.putExtra("encryptPwd", encryptPwd); + if (null != intent) { + getContext().sendBroadcast(intent); //发送广播 + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_IMAGE && resultCode == RESULT_OK) { + String path = ImageUtil.getImageAbsolutePath(getActivity(), data.getData()); + + new DecodeImgThread(path, new DecodeImgCallback() { + @Override + public void onImageDecodeSuccess(Result result) { + handleDecodeResult(result.getText(),null,0,0); + } + + @Override + public void onImageDecodeFailed() { + toast(R.string.device_add_scan_error); + } + }).run(); + + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeFormatManager.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeFormatManager.java new file mode 100644 index 0000000..40bfa88 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeFormatManager.java @@ -0,0 +1,94 @@ +package com.mm.android.deviceaddmodule.p_inputsn.scanresult; + +import android.content.Intent; +import android.net.Uri; + +import com.google.zxing.BarcodeFormat; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public final class DecodeFormatManager { + + private static final Pattern COMMA_PATTERN = Pattern.compile(","); + + public static final Set PRODUCT_FORMATS; + static final Set INDUSTRIAL_FORMATS; + static final Set ONE_D_FORMATS; + static final Set QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE); + static final Set DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX); + static final Set AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC); + static final Set PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417); + + static { + PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, + BarcodeFormat.UPC_E, + BarcodeFormat.EAN_13, + BarcodeFormat.EAN_8, + BarcodeFormat.RSS_14, + BarcodeFormat.RSS_EXPANDED); + INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, + BarcodeFormat.CODE_93, + BarcodeFormat.CODE_128, + BarcodeFormat.ITF, + BarcodeFormat.CODABAR); + ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS); + ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS); + } + + private static final Map> FORMATS_FOR_MODE; + + static { + FORMATS_FOR_MODE = new HashMap>(); + FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS); + FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS); + FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS); + FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS); + FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS); + FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS); + } + + private DecodeFormatManager() { + } + + public static Set parseDecodeFormats(Intent intent) { + Iterable scanFormats = null; + CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS); + if (scanFormatsString != null) { + scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString)); + } + return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE)); + } + + public static Set parseDecodeFormats(Uri inputUri) { + List formats = inputUri.getQueryParameters(Intents.Scan.FORMATS); + if (formats != null && formats.size() == 1 && formats.get(0) != null) { + formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0))); + } + return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE)); + } + + private static Set parseDecodeFormats(Iterable scanFormats, String decodeMode) { + if (scanFormats != null) { + Set formats = EnumSet.noneOf(BarcodeFormat.class); + try { + for (String format : scanFormats) { + formats.add(BarcodeFormat.valueOf(format)); + } + return formats; + } catch (IllegalArgumentException iae) { + // ignore it then + } + } + if (decodeMode != null) { + return FORMATS_FOR_MODE.get(decodeMode); + } + return null; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgCallback.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgCallback.java new file mode 100644 index 0000000..835b867 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgCallback.java @@ -0,0 +1,14 @@ +package com.mm.android.deviceaddmodule.p_inputsn.scanresult; + +import com.google.zxing.Result; + +/** + *

    + * 解析图片的回调 + */ + +public interface DecodeImgCallback { + void onImageDecodeSuccess(Result result); + + void onImageDecodeFailed(); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgThread.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgThread.java new file mode 100644 index 0000000..cbeb7a7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/DecodeImgThread.java @@ -0,0 +1,126 @@ +package com.mm.android.deviceaddmodule.p_inputsn.scanresult; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.text.TextUtils; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.RGBLuminanceSource; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.util.Hashtable; +import java.util.Vector; + +public class DecodeImgThread extends Thread { + + + /*图片路径*/ + private String imgPath; + /*回调*/ + private DecodeImgCallback callback; + private Bitmap scanBitmap; + + + public DecodeImgThread(String imgPath, DecodeImgCallback callback) { + + this.imgPath = imgPath; + this.callback = callback; + } + + @Override + public void run() { + super.run(); + + if (TextUtils.isEmpty(imgPath) || callback == null) { + return; + } + + Bitmap scanBitmap = getBitmap(imgPath, 400, 400); + RGBLuminanceSource source = null; + int width = scanBitmap.getWidth(); + int height = scanBitmap.getHeight(); + int[] pixels = new int[width * height]; + scanBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + source = new RGBLuminanceSource(width, height, pixels); + + MultiFormatReader multiFormatReader = new MultiFormatReader(); + // 解码的参数 + Hashtable hints = new Hashtable(2); + // 可以解析的编码类型 + Vector decodeFormats = new Vector(); + + + // 扫描的类型 一维码和二维码 + + decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); + + hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); + // 设置解析的字符编码格式为UTF8 + hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); + // 设置解析配置参数 + multiFormatReader.setHints(hints); + // 开始对图像资源解码 + Result rawResult = null; + try { + rawResult = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), hints); + + LogUtil.debugLog("解析结果", rawResult.getText()); + + } catch (Exception e) { + e.printStackTrace(); + } + + if (rawResult != null) { + callback.onImageDecodeSuccess(rawResult); + } else { + callback.onImageDecodeFailed(); + } + + + } + + + /** + * 根据路径获取图片 + * + * @param filePath 文件路径 + * @param maxWidth 图片最大宽度 + * @param maxHeight 图片最大高度 + * @return bitmap + */ + private static Bitmap getBitmap(final String filePath, final int maxWidth, final int maxHeight) { + + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(filePath, options); + } + + + /** + * Return the sample size. + * + * @param options The options. + * @param maxWidth The maximum width. + * @param maxHeight The maximum height. + * @return the sample size + */ + private static int calculateInSampleSize(final BitmapFactory.Options options, + final int maxWidth, + final int maxHeight) { + int height = options.outHeight; + int width = options.outWidth; + int inSampleSize = 1; + while ((width >>= 1) >= maxWidth && (height >>= 1) >= maxHeight) { + inSampleSize <<= 1; + } + return inSampleSize; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/ImageUtil.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/ImageUtil.java new file mode 100644 index 0000000..617c796 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/ImageUtil.java @@ -0,0 +1,112 @@ +package com.mm.android.deviceaddmodule.p_inputsn.scanresult; + +import android.annotation.TargetApi; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; + +/** + * 获取图片的路径 + */ + +public class ImageUtil { + + @TargetApi(19) + public static String getImageAbsolutePath(Context context, Uri imageUri) { + if (context == null || imageUri == null) + return null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, imageUri)) { + if (isExternalStorageDocument(imageUri)) { + String docId = DocumentsContract.getDocumentId(imageUri); + String[] split = docId.split(":"); + String type = split[0]; + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } else if (isDownloadsDocument(imageUri)) { + String id = DocumentsContract.getDocumentId(imageUri); + Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + return getDataColumn(context, contentUri, null, null); + } else if (isMediaDocument(imageUri)) { + String docId = DocumentsContract.getDocumentId(imageUri); + String[] split = docId.split(":"); + String type = split[0]; + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + String selection = MediaStore.Images.Media._ID + "=?"; + String[] selectionArgs = new String[]{split[1]}; + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } // MediaStore (and general) + else if ("content".equalsIgnoreCase(imageUri.getScheme())) { + // Return the remote address + if (isGooglePhotosUri(imageUri)) + return imageUri.getLastPathSegment(); + return getDataColumn(context, imageUri, null, null); + } + // File + else if ("file".equalsIgnoreCase(imageUri.getScheme())) { + return imageUri.getPath(); + } + return null; + } + + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + Cursor cursor = null; + String column = MediaStore.Images.Media.DATA; + String[] projection = {column}; + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + int index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Photos. + */ + public static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/Intents.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/Intents.java new file mode 100644 index 0000000..9301c5b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_inputsn/scanresult/Intents.java @@ -0,0 +1,261 @@ +package com.mm.android.deviceaddmodule.p_inputsn.scanresult; + +/** + * This class provides the constants to use when sending an Intent to Barcode Scanner. + * These strings are effectively API and cannot be changed. + * + */ +public final class Intents { + private Intents() { + } + + public static final class Scan { + /** + * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return + * the results. + */ + public static final String ACTION = "com.google.zxing.client.android.SCAN"; + + /** + * By default, sending this will decode all barcodes that we understand. However it + * may be useful to limit scanning to certain formats. Use + * {@link android.content.Intent#putExtra(String, String)} with one of the values below. + * + * Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}. + * It is overridden by that setting. + */ + public static final String MODE = "SCAN_MODE"; + + /** + * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get + * prices, reviews, etc. for products. + */ + public static final String PRODUCT_MODE = "PRODUCT_MODE"; + + /** + * Decode only 1D barcodes. + */ + public static final String ONE_D_MODE = "ONE_D_MODE"; + + /** + * Decode only QR codes. + */ + public static final String QR_CODE_MODE = "QR_CODE_MODE"; + + /** + * Decode only Data Matrix codes. + */ + public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE"; + + /** + * Decode only Aztec. + */ + public static final String AZTEC_MODE = "AZTEC_MODE"; + + /** + * Decode only PDF417. + */ + public static final String PDF417_MODE = "PDF417_MODE"; + + /** + * Comma-separated list of formats to scan for. The values must match the names of + * {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}. + * Example: "EAN_13,EAN_8,QR_CODE". This overrides {@link #MODE}. + */ + public static final String FORMATS = "SCAN_FORMATS"; + + /** + * Optional parameter to specify the id of the camera from which to recognize barcodes. + * Overrides the default camera that would otherwise would have been selected. + * If provided, should be an int. + */ + public static final String CAMERA_ID = "SCAN_CAMERA_ID"; + + /** + * @see com.google.zxing.DecodeHintType#CHARACTER_SET + */ + public static final String CHARACTER_SET = "CHARACTER_SET"; + + /** + * Optional parameters to specify the width and height of the scanning rectangle in pixels. + * The app will try to honor these, but will clamp them to the size of the preview frame. + * You should specify both or neither, and pass the size as an int. + */ + public static final String WIDTH = "SCAN_WIDTH"; + public static final String HEIGHT = "SCAN_HEIGHT"; + + /** + * Desired duration in milliseconds for which to pause after a successful scan before + * returning to the calling intent. Specified as a long, not an integer! + * For example: 1000L, not 1000. + */ + public static final String RESULT_DISPLAY_DURATION_MS = "RESULT_DISPLAY_DURATION_MS"; + + /** + * Prompt to show on-screen when scanning by intent. Specified as a {@link String}. + */ + public static final String PROMPT_MESSAGE = "PROMPT_MESSAGE"; + + /** + * If a barcode is found, Barcodes returns {@link android.app.Activity#RESULT_OK} to + * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)} + * of the app which requested the scan via + * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)} + * The barcodes contents can be retrieved with + * {@link android.content.Intent#getStringExtra(String)}. + * If the user presses Back, the result code will be {@link android.app.Activity#RESULT_CANCELED}. + */ + public static final String RESULT = "SCAN_RESULT"; + + /** + * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_FORMAT} + * to determine which barcode format was found. + * See {@link com.google.zxing.BarcodeFormat} for possible values. + */ + public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT"; + + /** + * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_UPC_EAN_EXTENSION} + * to return the content of any UPC extension barcode that was also found. Only applicable + * to {@link com.google.zxing.BarcodeFormat#UPC_A} and {@link com.google.zxing.BarcodeFormat#EAN_13} + * formats. + */ + public static final String RESULT_UPC_EAN_EXTENSION = "SCAN_RESULT_UPC_EAN_EXTENSION"; + + /** + * Call {@link android.content.Intent#getByteArrayExtra(String)} with {@link #RESULT_BYTES} + * to get a {@code byte[]} of raw bytes in the barcode, if available. + */ + public static final String RESULT_BYTES = "SCAN_RESULT_BYTES"; + + /** + * Key for the value of {@link com.google.zxing.ResultMetadataType#ORIENTATION}, if available. + * Call {@link android.content.Intent#getIntArrayExtra(String)} with {@link #RESULT_ORIENTATION}. + */ + public static final String RESULT_ORIENTATION = "SCAN_RESULT_ORIENTATION"; + + /** + * Key for the value of {@link com.google.zxing.ResultMetadataType#ERROR_CORRECTION_LEVEL}, if available. + * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_ERROR_CORRECTION_LEVEL}. + */ + public static final String RESULT_ERROR_CORRECTION_LEVEL = "SCAN_RESULT_ERROR_CORRECTION_LEVEL"; + + /** + * Prefix for keys that map to the values of {@link com.google.zxing.ResultMetadataType#BYTE_SEGMENTS}, + * if available. The actual values will be set under a series of keys formed by adding 0, 1, 2, ... + * to this prefix. So the first byte segment is under key "SCAN_RESULT_BYTE_SEGMENTS_0" for example. + * Call {@link android.content.Intent#getByteArrayExtra(String)} with these keys. + */ + public static final String RESULT_BYTE_SEGMENTS_PREFIX = "SCAN_RESULT_BYTE_SEGMENTS_"; + + /** + * Setting this to false will not save scanned codes in the history. Specified as a {@code boolean}. + */ + public static final String SAVE_HISTORY = "SAVE_HISTORY"; + + private Scan() { + } + } + + public static final class History { + + public static final String ITEM_NUMBER = "ITEM_NUMBER"; + + private History() { + } + } + + public static final class Encode { + /** + * Send this intent to encode a piece of data as a QR code and display it full screen, so + * that another person can scan the barcode from your screen. + */ + public static final String ACTION = "com.google.zxing.client.android.ENCODE"; + + /** + * The data to encode. Use {@link android.content.Intent#putExtra(String, String)} or + * {@link android.content.Intent#putExtra(String, android.os.Bundle)}, + * depending on the type and format specified. Non-QR Code formats should + * just use a String here. For QR Code, see Contents for details. + */ + public static final String DATA = "ENCODE_DATA"; + + /** + * The type of data being supplied if the format is QR Code. Use + * {@link android.content.Intent#putExtra(String, String)} with one of {@link Contents.Type}. + */ + public static final String TYPE = "ENCODE_TYPE"; + + /** + * The barcode format to be displayed. If this isn't specified or is blank, + * it defaults to QR Code. Use {@link android.content.Intent#putExtra(String, String)}, where + * format is one of {@link com.google.zxing.BarcodeFormat}. + */ + public static final String FORMAT = "ENCODE_FORMAT"; + + /** + * Normally the contents of the barcode are displayed to the user in a TextView. Setting this + * boolean to false will hide that TextView, showing only the encode barcode. + */ + public static final String SHOW_CONTENTS = "ENCODE_SHOW_CONTENTS"; + + private Encode() { + } + } + + public static final class SearchBookContents { + /** + * Use Google Book Search to search the contents of the book provided. + */ + public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS"; + + /** + * The book to search, identified by ISBN number. + */ + public static final String ISBN = "ISBN"; + + /** + * An optional field which is the text to search for. + */ + public static final String QUERY = "QUERY"; + + private SearchBookContents() { + } + } + + public static final class WifiConnect { + /** + * Internal intent used to trigger connection to a wi-fi network. + */ + public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT"; + + /** + * The network to connect to, all the configuration provided here. + */ + public static final String SSID = "SSID"; + + /** + * The network to connect to, all the configuration provided here. + */ + public static final String TYPE = "TYPE"; + + /** + * The network to connect to, all the configuration provided here. + */ + public static final String PASSWORD = "PASSWORD"; + + private WifiConnect() { + } + } + + public static final class Share { + /** + * Give the user a choice of items to encode as a barcode, then render it as a QR Code and + * display onscreen for a friend to scan with their phone. + */ + public static final String ACTION = "com.google.zxing.client.android.SHARE"; + + private Share() { + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_nb/TipNBFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_nb/TipNBFragment.java new file mode 100644 index 0000000..a6891a0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_nb/TipNBFragment.java @@ -0,0 +1,72 @@ +package com.mm.android.deviceaddmodule.p_nb; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +public class TipNBFragment extends BaseTipFragment { + + public static TipNBFragment newInstance() { + TipNBFragment fragment = new TipNBFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + @Override + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mConfirmCheck.setVisibility(View.GONE); + mTipTxt.setText(R.string.add_device_nb_tip1); + mTipTxt2.setVisibility(View.VISIBLE); + mTipTxt2.setText(R.string.add_device_nb_tip2); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo= DeviceAddModel.newInstance().getDeviceInfoCache(); + DeviceIntroductionInfo deviceIntroductionInfo = deviceAddInfo.getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipImage = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.THIRD_PARTY_PLATFORM_MODE_GUIDING_LIGHT_IMAGE); + if (!TextUtils.isEmpty(tipImage)) { + ImageLoader.getInstance().displayImage(tipImage, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + } + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_offlineconfig/OfflineConfigFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_offlineconfig/OfflineConfigFragment.java new file mode 100644 index 0000000..1fad419 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_offlineconfig/OfflineConfigFragment.java @@ -0,0 +1,79 @@ +package com.mm.android.deviceaddmodule.p_offlineconfig; + +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.OfflineConfigConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.presenter.OfflineConfigPresenter; + +/** + * 设备离线重连 + **/ +public class OfflineConfigFragment extends BaseDevAddFragment implements OfflineConfigConstract.View { + protected ImageView mTipImg; + protected TextView mTipTxt, mNextBtn; + OfflineConfigConstract.Presenter mPresenter; + Handler mHandler=new Handler(); + + public static OfflineConfigFragment newInstance(String sn,String devModelName, String imei) { + OfflineConfigFragment fragment = new OfflineConfigFragment(); + Bundle args = new Bundle(); + args.putString(LCConfiguration.DEVICESN_PARAM,sn); + args.putString(LCConfiguration.DEVICE_MODEL_NAME_PARAM,devModelName); + args.putString(LCConfiguration.DEVICE_IMEI_PARAM, imei); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_base_tip, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.BLANK); + } + + @Override + protected void initView(View view) { + mTipImg = view.findViewById(R.id.tip_img); + mTipTxt = view.findViewById(R.id.tip_txt); + mNextBtn = view.findViewById(R.id.tv_next); + mTipImg.setVisibility(View.GONE); + mTipTxt.setVisibility(View.GONE); + mNextBtn.setVisibility(View.GONE); + } + + @Override + protected void initData() { + mPresenter=new OfflineConfigPresenter(this); + mPresenter.resetCache(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (isViewActive()) + mPresenter.getDeviceInfo(getArguments().getString(LCConfiguration.DEVICESN_PARAM), + getArguments().getString(LCConfiguration.DEVICE_MODEL_NAME_PARAM), + getArguments().getString(LCConfiguration.DEVICE_IMEI_PARAM)); + } + }, 100); + } + + @Override + public void onGetDeviceInfoError() { + getActivity().finish(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/BaseTipSoftApFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/BaseTipSoftApFragment.java new file mode 100644 index 0000000..2fab988 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/BaseTipSoftApFragment.java @@ -0,0 +1,158 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.Manifest; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.contract.BaseSoftApTipConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.base.DefaultPermissionListener; +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.location.FuseLocationUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; +/** + * 软AP添加引导提示页基类 + */ +public abstract class BaseTipSoftApFragment extends BaseTipFragment implements BaseSoftApTipConstract.View { + BaseSoftApTipConstract.Presenter mPresenter; + + protected abstract void gotoNextSoftApTipPage(); + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + + @Override + protected void nextAction() { + if(mPresenter.isLastTipPage()){ + mPresenter.verifyWifiOrLocationPermission(); + } else { + gotoNextSoftApTipPage(); + } + } + + @Override + protected void helpAction() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_RESET); + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + protected void initView(View view) { + super.initView(view); + RelativeLayout.LayoutParams params= (RelativeLayout.LayoutParams) mTipImg.getLayoutParams(); + params.height= /*RelativeLayout.LayoutParams.WRAP_CONTENT*/UIUtils.dp2px(getContextInfo(), 300); + params.width=RelativeLayout.LayoutParams.MATCH_PARENT; + params.setMargins(0,0,0,0); + mTipImg.setScaleType(ImageView.ScaleType.FIT_CENTER); + } + + @Override + public void updateTipImage(String imageUrl) { + if (!TextUtils.isEmpty(imageUrl)) + ImageLoader.getInstance().displayImage(imageUrl, mTipImg, DeviceAddImageLoaderHelper.getCommonOptions()); + } + + @Override + public void updateTipTxt(String tipInfo) { + if (!TextUtils.isEmpty(tipInfo)) { + mTipTxt.setText(tipInfo); + } else { + mTipTxt.setText(R.string.add_device_operation_by_instructions); + } + } + + @Override + public void updateResetTxt(String resetTxt) { + if (TextUtils.isEmpty(resetTxt)) { + mHelpTxt.setVisibility(View.GONE); + } else { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(resetTxt); + } + } + + + @Override + public void goErrorTipPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.SOFTAP_ERROR_CONNECT_HOT_FAILED); + } + + @Override + public void gotoSoftApTipConnectWifiPage() { + PageNavigationHelper.gotoSoftApTipConnectWifiPage(this); + } + + @Override + public void applyLocationPermission() { + if (getActivity() == null) return; + //1.判断是否该应用有地理位置权限 2.判断是否开启定位服务 + PermissionHelper permissionHelper = new PermissionHelper(this); + if (permissionHelper.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { + verifyLocationService(); + } else { + permissionHelper.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new DefaultPermissionListener() { + @Override + public void onGranted() { + verifyLocationService(); + } + + @Override + public boolean onDenied() { + return false; + } + }); + } + } + + + private void verifyLocationService() { + if (FuseLocationUtil.isGpsEnabled(getActivity())) { + gotoSoftApTipConnectWifiPage(); + } else { + showOpenLocationServiceDialog(); + } + + } + + private void showOpenLocationServiceDialog() { + LCAlertDialog dialog = new LCAlertDialog.Builder(getActivity()) + .setTitle(R.string.add_device_goto_open_location_service) + .setCancelButton(R.string.common_cancel, null) + .setConfirmButton(R.string.common_confirm, new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, boolean isChecked) { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + startActivity(intent); + dialog.dismiss(); + } + }).create(); + dialog.show(getFragmentManager(), null); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/DevWifiListFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/DevWifiListFragment.java new file mode 100644 index 0000000..9ce5e59 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/DevWifiListFragment.java @@ -0,0 +1,172 @@ +package com.mm.android.deviceaddmodule.p_softap; + + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.adapter.WifiListAdapter; +import com.mm.android.deviceaddmodule.base.BaseWifiListenerFragment; +import com.mm.android.deviceaddmodule.contract.DevWifiListConstract; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.BaseEvent; +import com.mm.android.deviceaddmodule.presenter.DevWifiListPresenter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 软AP添加Wifi选择页 + */ +public class DevWifiListFragment extends BaseWifiListenerFragment implements DevWifiListConstract.View, AdapterView.OnItemClickListener { + private static final String IS_NOT_NEED_LOGIN = "isNotNeedLogin"; + DevWifiListConstract.Presenter mPresenter; + private WifiListAdapter mAdapter; + private List mListData; + private boolean isNotNeedLogin; + LinearLayout mWifiListContainer,mErrorTip; + ListView mList; + private TextView mWifiNameTip; + private TextView mWifi5GTip; + private ImageView mWifiIv; + + public static DevWifiListFragment newInstance(boolean isNotNeedLogin) { + DevWifiListFragment fragment = new DevWifiListFragment(); + Bundle args = new Bundle(); + args.putBoolean(IS_NOT_NEED_LOGIN, isNotNeedLogin); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onMessageEvent(BaseEvent event) { + super.onMessageEvent(event); + if (event instanceof DeviceAddEvent) { + String code = event.getCode(); + if (DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST.equals(code)) { + mPresenter.getWifiList(); + } + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_dev_wifi_list, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.REFRESH); + } + + protected void initView(View view) { + mWifiListContainer= view.findViewById(R.id.wifi_list_container); + mWifiNameTip = view.findViewById(R.id.dev_wifi_name); + mWifi5GTip = view.findViewById(R.id.tv_5g_tip); + mWifi5GTip.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + PageNavigationHelper.gotoErrorTipPage(DevWifiListFragment.this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G); + } + }); + mWifiNameTip.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + PageNavigationHelper.gotoErrorTipPage(DevWifiListFragment.this, DeviceAddHelper.ErrorCode.COMMON_ERROR_WIFI_NAME); + } + }); + mWifiIv = view.findViewById(R.id.iv_wifi); + mErrorTip= view.findViewById(R.id.error_tip); + mList = view.findViewById(R.id.wifi_list); + mList.setOnItemClickListener(this); + } + + protected void initData() { + if (getArguments() != null) { + isNotNeedLogin = getArguments().getBoolean(IS_NOT_NEED_LOGIN, false); + } + mPresenter = new DevWifiListPresenter(this, isNotNeedLogin); + + View view = LayoutInflater.from(this.getContext()).inflate(R.layout.device_add_wifi_list_item_more, null); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + goHiddenWifiPwdPage(isNotNeedLogin); + } + }); + mList.addFooterView(view,null,true); + + + mListData = new ArrayList<>(); + mAdapter = new WifiListAdapter(R.layout.device_add_wifi_list_item, mListData, getActivity()); + mList.setAdapter(mAdapter); + + check5GWifiTip(); + } + + private void check5GWifiTip() { + if (!mPresenter.isDevSupport5G()) { + mWifi5GTip.setVisibility(View.VISIBLE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword_nosupport5g_layer); + } else { + mWifi5GTip.setVisibility(View.GONE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword); + } + } + + @Override + public void updateWifiList(List list) { + mList.setVisibility(View.VISIBLE); + mListData.clear(); + if (list != null) + mListData.addAll(list); + mAdapter.notifyDataSetChanged(); + } + + @Override + public void goWifiPwdPage(WlanInfo wlanInfo, boolean isNotNeedLogin) { + PageNavigationHelper.gotoSoftApWifiPwdPage(this, wlanInfo, isNotNeedLogin); + } + + @Override + public void goHiddenWifiPwdPage(boolean isNotNeedLogin) { + PageNavigationHelper.gotoHiddenWifiPwdPage(this, isNotNeedLogin); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void showListView() { + mWifiListContainer.setVisibility(View.VISIBLE); + mErrorTip.setVisibility(View.GONE); + } + + @Override + public void showErrorInfoView() { + mWifiListContainer.setVisibility(View.GONE); + mErrorTip.setVisibility(View.VISIBLE); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + goWifiPwdPage(mAdapter.getItem(position), isNotNeedLogin); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/HiddenWifiPwdFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/HiddenWifiPwdFragment.java new file mode 100644 index 0000000..b42af91 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/HiddenWifiPwdFragment.java @@ -0,0 +1,215 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.HiddenWifiPwdConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIHelper; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.HiddenWifiPresenter; + +import org.greenrobot.eventbus.EventBus; + +/** + * 输入隐藏wifi密码页 + */ +public class HiddenWifiPwdFragment extends BaseDevAddFragment implements HiddenWifiPwdConstract.View, View.OnClickListener { + + private static String WLAN_PARAM = "wlan_param"; + private static final String IS_NOT_NEED_LOGIN = "isNotNeedLogin"; + HiddenWifiPwdConstract.Presenter mPresenter; + private TextView mNextTv; + private ClearEditText mWifiSsidTv; + private ClearPasswordEditText mWifiPwdEt; + private TextView m5GWifiTipTv; + + public static HiddenWifiPwdFragment newInstance(boolean isNotNeedLogin) { + HiddenWifiPwdFragment fragment = new HiddenWifiPwdFragment(); + Bundle args = new Bundle(); + args.putBoolean(IS_NOT_NEED_LOGIN, isNotNeedLogin); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mSsidTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + if (!mWifiSsidTv.getText().toString().equalsIgnoreCase("")) { + setConnectButtonState(true); + }else { + setConnectButtonState(false); + } + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + mWifiPwdEt.removeTextChangedListener(mTextWatcher); + String str = Utils4AddDevice.wifiPwdFilter(s.toString()); + if (!str.equals(s.toString())) { + mWifiPwdEt.setText(str); + mWifiPwdEt.setSelection(str.length()); + } + mWifiPwdEt.addTextChangedListener(mTextWatcher); + + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_hidden_wifi, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + protected void initView(View view) { + + mNextTv = view.findViewById(R.id.next); + mWifiSsidTv = view.findViewById(R.id.wifi_name); + mWifiPwdEt = view.findViewById(R.id.wifi_psw); + mWifiPwdEt.openEyeMode(ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA); + mWifiSsidTv.addTextChangedListener(mSsidTextWatcher); + mWifiPwdEt.addTextChangedListener(mTextWatcher); + mNextTv.setOnClickListener(this); + + m5GWifiTipTv = view.findViewById(R.id.tv_5g_tip); + m5GWifiTipTv.setOnClickListener(this); + + } + + protected void initData() { + mPresenter = new HiddenWifiPresenter(this); + if (getArguments() != null) { + + boolean isNotNeedLogin = getArguments().getBoolean(IS_NOT_NEED_LOGIN, false); + mPresenter.setIsNotNeedLogin(isNotNeedLogin); + } + setConnectButtonState(false); + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + + if (mPresenter.isDevSupport5G()) { + m5GWifiTipTv.setVisibility(View.GONE); + } else { + m5GWifiTipTv.setVisibility(View.VISIBLE); + } + } + + private void setSSIDTextView() { + if (null != getActivity() && !Utils4AddDevice.isWifi(getActivity())) { + mWifiSsidTv.setText(""); + return; + } + mWifiSsidTv.setText(mPresenter.getCurWifiName()); + } + + private void setConnectButtonState(boolean enable) { + UIHelper.setEnabledEX(enable, mNextTv); + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mNextTv.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (null != getActivity() && mWifiPwdEt != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPwdEt.getWindowToken(), 0); + + } + super.onDestroyView(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (R.id.next == id) { + + mPresenter.connectWifi(); + } else if (R.id.tv_5g_tip == id) { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G); + }else if(R.id.switch_wifi == id){ + CommonHelper.gotoWifiSetting(getActivity()); + } + } + + @Override + public String getWifiPwd() { + return mWifiPwdEt.getText().toString(); + } + + public String getWifiSSID() { + return mWifiSsidTv.getText().toString(); + } + + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/SoftApWifiPwdFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/SoftApWifiPwdFragment.java new file mode 100644 index 0000000..cfbe32a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/SoftApWifiPwdFragment.java @@ -0,0 +1,232 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.SoftApWifiPwdConstract; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIHelper; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.SoftApWifiPwdPresenter; + +import org.greenrobot.eventbus.EventBus; + +/** + * 输入wifi密码页 + */ +public class SoftApWifiPwdFragment extends BaseDevAddFragment implements SoftApWifiPwdConstract.View, View.OnClickListener { + private static String WLAN_PARAM = "wlan_param"; + private static final String IS_NOT_NEED_LOGIN = "isNotNeedLogin"; + SoftApWifiPwdConstract.Presenter mPresenter; + private TextView mNextTv; + private TextView mWifiSsidTv; + private ClearPasswordEditText mWifiPwdEt; + private TextView m5GWifiTipTv; + private TextView mSaveWifiPwdChebox; + private ImageView mSwitchWifiIv; + private ImageView mWifiIv; + + public static SoftApWifiPwdFragment newInstance(WlanInfo wlanInfo, boolean isNotNeedLogin) { + SoftApWifiPwdFragment fragment = new SoftApWifiPwdFragment(); + Bundle args = new Bundle(); + args.putSerializable(WLAN_PARAM, wlanInfo); + args.putBoolean(IS_NOT_NEED_LOGIN, isNotNeedLogin); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + mWifiPwdEt.removeTextChangedListener(mTextWatcher); + String str = Utils4AddDevice.wifiPwdFilter(s.toString()); + if (!str.equals(s.toString())) { + mWifiPwdEt.setText(str); + mWifiPwdEt.setSelection(str.length()); + } + mWifiPwdEt.addTextChangedListener(mTextWatcher); + setConnectButtonState(); + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_wifi_pwd, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + protected void initView(View view) { + mWifiIv = view.findViewById(R.id.iv_wifi); + mSwitchWifiIv = view.findViewById(R.id.switch_wifi); + mSwitchWifiIv.setVisibility(View.GONE); + mNextTv = view.findViewById(R.id.next); + m5GWifiTipTv = view.findViewById(R.id.tv_5g_tip); + mWifiSsidTv = view.findViewById(R.id.ssid); + mWifiPwdEt = view.findViewById(R.id.wifi_pwd); + mWifiPwdEt.openEyeMode(ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA); + mWifiPwdEt.addTextChangedListener(mTextWatcher); + mNextTv.setOnClickListener(this); + mSaveWifiPwdChebox = view.findViewById(R.id.wifi_pwd_check); + m5GWifiTipTv.setOnClickListener(this); + mSaveWifiPwdChebox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + view.setSelected(!view.isSelected()); + if (!view.isSelected()) { + mPresenter.updateWifiCache(); + } + } + }); + mSwitchWifiIv.setOnClickListener(this); + } + + protected void initData() { + mPresenter = new SoftApWifiPwdPresenter(this); + if (getArguments() != null) { + WlanInfo wlanInfo = (WlanInfo) getArguments().getSerializable(WLAN_PARAM); + mPresenter.setWlanInfo(wlanInfo); + boolean isNotNeedLogin = getArguments().getBoolean(IS_NOT_NEED_LOGIN, false); + mPresenter.setIsNotNeedLogin(isNotNeedLogin); + } + check5GWifiTip(); + setConnectButtonState(); + setSSIDTextView(); + setWifiPwd(); + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + + private void setSSIDTextView() { + if (null != getActivity() && !Utils4AddDevice.isWifi(getActivity())) { + mWifiSsidTv.setText(""); + return; + } + mWifiSsidTv.setText(mPresenter.getCurWifiName()); + } + + private void setWifiPwd() { + String wifiPwd = mPresenter.getSavedWifiPwd(); + boolean wifiCheckBoxStatus = mPresenter.getSavedWifiCheckBoxStatus(); + + if (!TextUtils.isEmpty(wifiPwd)) { + mWifiPwdEt.setText(wifiPwd); + mSaveWifiPwdChebox.setSelected(wifiCheckBoxStatus); + }else{ + mWifiPwdEt.setText(""); + mSaveWifiPwdChebox.setSelected(wifiCheckBoxStatus); + } + } + + private void check5GWifiTip() { + if (!mPresenter.isDevSupport5G()) { + m5GWifiTipTv.setVisibility(View.VISIBLE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword_nosupport5g_layer); + } else { + m5GWifiTipTv.setVisibility(View.INVISIBLE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword); + } + } + + private void setConnectButtonState() { + UIHelper.setEnabledEX(true, mNextTv); + } + + @Override + public void showProgressDialog() { + hideSoftKeyboard(); + mNextTv.postDelayed(new Runnable() { + @Override + public void run() { + if (!isDestoryView()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_LOADING_VIEW_ACTION)); + } + } + }, 100); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (null != getActivity() && mWifiPwdEt != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPwdEt.getWindowToken(), 0); + + } + super.onDestroyView(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (R.id.next == id) { + if (null != getActivity() && !Utils4AddDevice.isWifi(getActivity())) { + toastInCenter(R.string.add_device_con_wifi); + return; + } + mPresenter.connectWifi(); + } else if (R.id.tv_5g_tip == id) { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G); + }else if(R.id.switch_wifi == id){ + CommonHelper.gotoWifiSetting(getActivity()); + } + } + + @Override + public String getWifiPwd() { + return mWifiPwdEt.getText().toString(); + } + + @Override + public boolean isSavePwdChecked() { + return mSaveWifiPwdChebox.isSelected(); + } + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApConnectWifiFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApConnectWifiFragment.java new file mode 100644 index 0000000..87964e5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApConnectWifiFragment.java @@ -0,0 +1,218 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Paint; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.TipSoftApConnectWifiConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CloseTimeFilterEvent; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.NoticeToBackEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.TipSoftApConnectWifiPresenter; +import com.mm.android.deviceaddmodule.services.TimeFilterService; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import static android.content.Context.WIFI_SERVICE; + +/** + * 软AP添加引导提示页-自动连接wifi + */ +public class TipSoftApConnectWifiFragment extends BaseDevAddFragment implements TipSoftApConnectWifiConstract.View { + TipSoftApConnectWifiConstract.Presenter mPresenter; + TextView mShowTipTv, mWifiNameTv, mWifiPwdTv, mShowTip1Tv; + TextView mGotoWifiSetting, mAboutWifiPwdTv; + LinearLayout mWifiPwdLayout; + ImageView mCopyIv; + private boolean mIsBack; //是否需要返回到上一页(主要是应用在长时间未连接热点,点击通知栏需要返回到上一页) + + public static TipSoftApConnectWifiFragment newInstance() { + TipSoftApConnectWifiFragment fragment = new TipSoftApConnectWifiFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(NoticeToBackEvent event) { + mIsBack = true; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_tip_soft_ap_connect_wifi, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + @Override + protected void initView(View view) { + mShowTipTv = view.findViewById(R.id.tv_image_show_tip); + mShowTipTv.setText(R.string.add_device_wait_to_connect_wifi); + mShowTip1Tv = view.findViewById(R.id.tv_show_tip); + mWifiNameTv = view.findViewById(R.id.tv_wifi_name); + + mWifiPwdLayout = view.findViewById(R.id.layout_wifi_pwd); + mWifiPwdTv = view.findViewById(R.id.tv_wifi_pwd); + mWifiPwdTv.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);//下划线 + mWifiPwdTv.getPaint().setAntiAlias(true);//抗锯齿 + mWifiPwdTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mPresenter.copyWifiPwd(); + } + }); + + mCopyIv = view.findViewById(R.id.iv_copy); + mCopyIv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mPresenter.copyWifiPwd(); + } + }); + + mGotoWifiSetting = (TextView) view.findViewById(R.id.tv_goto_connect); + mGotoWifiSetting.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + //取消之前的定时任务 + EventBus.getDefault().post(new CloseTimeFilterEvent()); + Intent intent = new Intent(getActivity(), TimeFilterService.class); + intent.putExtra(LCConfiguration.SSID, mPresenter.getHotSSID()); + getActivity().startService(intent); + // CommonHelper.gotoWifiSetting(getActivity()); + Intent wifiIntent = new Intent(); + wifiIntent.setFlags(intent.FLAG_ACTIVITY_NO_HISTORY | intent.FLAG_ACTIVITY_NEW_TASK); + wifiIntent.setAction("android.net.wifi.PICK_WIFI_NETWORK"); + startActivity(wifiIntent); + } + }); + mAboutWifiPwdTv = (TextView) view.findViewById(R.id.tv_about_wifi_pwd); + mAboutWifiPwdTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PageNavigationHelper.gotoErrorTipPage(TipSoftApConnectWifiFragment.this, DeviceAddHelper.ErrorCode.COMMON_ERROR_ABOUT_WIFI_PWD); + } + }); + } + + protected void initData() { + mPresenter = new TipSoftApConnectWifiPresenter(this); + mPresenter.connectWifiAction(true); + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + + @Override + public void updateWifiName(String wifiName) { + mWifiNameTv.setText(wifiName); + } + + @Override + public void updateConnectFailedTipText(String wifiName, String wifiPwd, boolean isSupportAddBySc, boolean isManualInput) { + mGotoWifiSetting.setVisibility(View.VISIBLE); + mAboutWifiPwdTv.setVisibility(isSupportAddBySc ? View.VISIBLE : View.GONE); + mShowTipTv.setText(getString(R.string.add_device_connect_wifi_failed)); + mShowTipTv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.adddevice_icon_help, 0); + mShowTipTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + PageNavigationHelper.gotoErrorTipPage(TipSoftApConnectWifiFragment.this, DeviceAddHelper.ErrorCode.COMMON_ERROR_CONNECT_FAIL); + } + }); + mShowTip1Tv.setText(getString(isSupportAddBySc ? R.string.add_device_wait_to_connect_wifi_failed_sc : R.string.add_device_wait_to_connect_wifi_failed, wifiName)); + mWifiPwdLayout.setVisibility(isSupportAddBySc ? View.VISIBLE : View.GONE); + mWifiPwdTv.setText(wifiPwd); + mWifiPwdTv.setClickable(!isManualInput); + mCopyIv.setVisibility(isManualInput ? View.GONE : View.VISIBLE); + } + + @Override + protected IntentFilter createBroadCast() { + IntentFilter filter = new IntentFilter(); + filter.addAction(LCConfiguration.CONNECTIVITY_CHAGET_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + return filter; + } + + @Override + protected void onReceive(Context context, Intent intent) { + if (isDestoryView()) + return; + if (LCConfiguration.CONNECTIVITY_CHAGET_ACTION.equals(intent.getAction()) + || WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction()) + || WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) { + LogUtil.debugLog("bz", "onReceive"); + final int netWorkState = Utils4AddDevice.getNetWorkState(getContextInfo()); + LogUtil.debugLog("bz", "netWorkState : " + netWorkState); + mPresenter.dispatchHotConnected(); + } + } + + @Override + public void goSecurityCheckPage() { + PageNavigationHelper.gotoSecurityCheckPage(this); + } + + @Override + public void onResume() { + super.onResume(); + if (mIsBack) { + if (getActivity() == null) + return; + getActivity().getSupportFragmentManager().popBackStack(); + mIsBack = false; + } else { + if (mPresenter.getHotSSID().contains("V6") || mPresenter.getHotSSID().contains("G1") || mPresenter.getHotSSID().contains("G2")) { + PageNavigationHelper.gotoSecurityCheckPage(this); + } + + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + cancelProgressDialog(); + //取消定时任务 + EventBus.getDefault().post(new CloseTimeFilterEvent()); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep1Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep1Fragment.java new file mode 100644 index 0000000..e663aba --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep1Fragment.java @@ -0,0 +1,31 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.presenter.BaseSoftApTipPresenter; + +/** + * 软AP添加引导提示页1 + */ +public class TipSoftApStep1Fragment extends BaseTipSoftApFragment { + + public static TipSoftApStep1Fragment newInstance() { + TipSoftApStep1Fragment fragment = new TipSoftApStep1Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void gotoNextSoftApTipPage() { + PageNavigationHelper.gotoSoftApTip2Page(this); + } + + + @Override + protected void initData() { + super.initData(); + mPresenter=new BaseSoftApTipPresenter(this,0); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep2Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep2Fragment.java new file mode 100644 index 0000000..13ff62d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep2Fragment.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.presenter.BaseSoftApTipPresenter; +/** + * 软AP添加引导提示页2 + */ +public class TipSoftApStep2Fragment extends BaseTipSoftApFragment { + + public static TipSoftApStep2Fragment newInstance() { + TipSoftApStep2Fragment fragment = new TipSoftApStep2Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void gotoNextSoftApTipPage() { + PageNavigationHelper.gotoSoftApTip3Page(this); + } + + @Override + protected void initData() { + super.initData(); + mPresenter=new BaseSoftApTipPresenter(this,1); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep3Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep3Fragment.java new file mode 100644 index 0000000..6713d31 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep3Fragment.java @@ -0,0 +1,29 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.presenter.BaseSoftApTipPresenter; +/** + * 软AP添加引导提示页3 + */ +public class TipSoftApStep3Fragment extends BaseTipSoftApFragment { + + public static TipSoftApStep3Fragment newInstance() { + TipSoftApStep3Fragment fragment = new TipSoftApStep3Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void gotoNextSoftApTipPage() { + PageNavigationHelper.gotoSoftApTip4Page(this); + } + + @Override + protected void initData() { + super.initData(); + mPresenter=new BaseSoftApTipPresenter(this,2); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep4Fragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep4Fragment.java new file mode 100644 index 0000000..3d786e5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/TipSoftApStep4Fragment.java @@ -0,0 +1,30 @@ +package com.mm.android.deviceaddmodule.p_softap; + +import android.os.Bundle; + +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.presenter.BaseSoftApTipPresenter; +/** + * 软AP添加引导提示页4 + */ +public class TipSoftApStep4Fragment extends BaseTipSoftApFragment { + + public static TipSoftApStep4Fragment newInstance() { + TipSoftApStep4Fragment fragment = new TipSoftApStep4Fragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void gotoNextSoftApTipPage() { + PageNavigationHelper.gotoSoftApTipConnectWifiPage(this); + } + + + @Override + protected void initData() { + super.initData(); + mPresenter=new BaseSoftApTipPresenter(this,3); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/oversea/SoftApResultFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/oversea/SoftApResultFragment.java new file mode 100644 index 0000000..1614b9f --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_softap/oversea/SoftApResultFragment.java @@ -0,0 +1,76 @@ +package com.mm.android.deviceaddmodule.p_softap.oversea; + + +import android.os.Bundle; +import android.view.View; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.greenrobot.eventbus.EventBus; + + +/** + + * 软Ap 设备连接wifi判断页,用户手动判断设备是否已连接上wifi(国外乐橙) + */ +public class SoftApResultFragment extends BaseTipFragment implements View.OnClickListener { + public static SoftApResultFragment newInstance() { + SoftApResultFragment fragment = new SoftApResultFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + protected void nextAction() { + if(DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode()){ + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + ProviderManager.getDeviceAddCustomProvider().goHomePage(getActivity()); + }else { + PageNavigationHelper.gotoDeviceBindPage(this); + } + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + protected void initView(View view){ + super.initView(view); + tipImageMatch(); + mTipImg.setImageResource(R.drawable.adddevice_netsetting_connectrouter); + mTipTxt.setText(R.string.add_device_softap_dev_connect_tip); + mConfirmCheck.setText(R.string.add_device_softap_dev_connect_check_tip); + mConfirmCheck.setVisibility(View.VISIBLE); + } + + protected void initData(){ + super.initData(); + DeviceIntroductionInfo deviceIntroductionInfo= DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if(deviceIntroductionInfo!=null){ + String tipImg=deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESULT_PROMPT_IMAGE); + String tipTxt=deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESULT_INTRODUCTION); + String checkTxt=deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_CONFIRM_INTRODUCTION); + mTipTxt.setText(tipTxt); + mConfirmCheck.setText(checkTxt); + ImageLoader.getInstance().displayImage(tipImg,mTipImg, DeviceAddImageLoaderHelper.getCommonOptions()); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_typechoose/TypeChooseFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_typechoose/TypeChooseFragment.java new file mode 100644 index 0000000..53e56c8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_typechoose/TypeChooseFragment.java @@ -0,0 +1,207 @@ +package com.mm.android.deviceaddmodule.p_typechoose; + + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.TypeChooseConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearEditText; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.TypeChoosePresenter; +import com.mm.android.deviceaddmodule.views.ChooseNetDialog; + +import org.greenrobot.eventbus.EventBus; + +/** + * 设备类型选择页 + */ +public class TypeChooseFragment extends BaseDevAddFragment implements TypeChooseConstract.View, View.OnClickListener { + TypeChooseConstract.Presenter mPresenter; + View mView; + private ClearEditText mTvNameInput; + private TextView mTvTip; + private TextView mTvSure; + private boolean isSelfInput = true; + private ImageView ivSelfInput; + private ImageView ivChooseOther; + + public static TypeChooseFragment newInstance() { + TypeChooseFragment fragment = new TypeChooseFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + isDestoryView = false; + if (mView != null) { + ViewGroup parent = (ViewGroup) mView.getParent(); + if (parent != null) { + parent.removeView(mView); + } + } else { + mView = inflater.inflate(R.layout.fragment_type_input, container, false); + initView(mView); + initData(); + } + if (mPresenter != null) { + mPresenter.resetDevPwdCache(); + } + return mView; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + + } + + protected void initView(View view) { + mTvNameInput = view.findViewById(R.id.tv_name_input); + view.findViewById(R.id.ll_choose_other).setOnClickListener(this); + view.findViewById(R.id.ll_self_input).setOnClickListener(this); + mTvTip = view.findViewById(R.id.tv_tip); + ivSelfInput = view.findViewById(R.id.iv_self_input); + ivChooseOther = view.findViewById(R.id.iv_choose_other); + mTvSure = view.findViewById(R.id.tv_sure); + mTvSure.setOnClickListener(this); + + String str1 = getResources().getString(R.string.add_device_choose_type_tip1); + String str2 = getResources().getString(R.string.add_device_choose_type_tip2); + String str3 = getResources().getString(R.string.add_device_choose_type_tip3); + String str4 = getResources().getString(R.string.add_device_choose_type_tip4); + String str5 = getResources().getString(R.string.add_device_choose_type_tip5); + String str6 = getResources().getString(R.string.add_device_choose_type_tip6); + SpannableString info = new SpannableString(str1 + str2 + str3 + str4 + str5 + str6); + if (!TextUtils.isEmpty(str1)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.cf4)), 0, str1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + info.setSpan(new StyleSpan(Typeface.BOLD), 0, str1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (!TextUtils.isEmpty(str2)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.c40)), str1.length(), str1.length() + str2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + info.setSpan(new StyleSpan(Typeface.BOLD), str1.length(), str1.length() + str2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (!TextUtils.isEmpty(str3)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.c40)), str1.length() + str2.length(), str1.length() + str2.length() + str3.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (!TextUtils.isEmpty(str4)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.c40)), str1.length() + str2.length() + str3.length(), str1.length() + str2.length() + str3.length() + str4.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + info.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),str1.length() + str2.length() + str3.length(), str1.length() + str2.length() + str3.length() + str4.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (!TextUtils.isEmpty(str5)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.c40)), str1.length() + str2.length() + str3.length() + str4.length(), str1.length() + str2.length() + str3.length() + str4.length() + str5.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (!TextUtils.isEmpty(str6)) { + info.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.c40)), str1.length() + str2.length() + str3.length() + str4.length() + str5.length(), str1.length() + str2.length() + str3.length() + str4.length() + str5.length() + str6.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + info.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),str1.length() + str2.length() + str3.length() + str4.length() + str5.length(), str1.length() + str2.length() + str3.length() + str4.length() + str5.length() + str6.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + mTvTip.setText(info); + } + + protected void initData() { + mPresenter = new TypeChoosePresenter(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mPresenter.resetDevPwdCache(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.ll_choose_other) { + isSelfInput = false; + ivSelfInput.setImageResource(R.drawable.adddevice_box_checkbox); + ivChooseOther.setImageResource(R.drawable.adddevice_box_checkbox_checked); + } else if (id == R.id.ll_self_input) { + isSelfInput = true; + ivChooseOther.setImageResource(R.drawable.adddevice_box_checkbox); + ivSelfInput.setImageResource(R.drawable.adddevice_box_checkbox_checked); + } else if (id == R.id.tv_sure) { + if (UIUtils.isFastDoubleClick()) { + return; + } + if (isSelfInput) { + //手动输入 + String name = mTvNameInput.getText().toString().trim(); + if (TextUtils.isEmpty(name)) { + toast(R.string.device_tip_content); + return; + } + mPresenter.getDeviceInfoSync(name); + } else { + //其他选择 + ChooseNetDialog chooseNetDialog = new ChooseNetDialog(getContext()); + chooseNetDialog.setOnChooseNetLisenter(new ChooseNetDialog.OnChooseNetLisenter() { + @Override + public void softap() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_SOFTAP_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.SOFTAP); + } + + @Override + public void wlan() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRELESS_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.WLAN); + } + + @Override + public void lan() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRED_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + } + }); + chooseNetDialog.show(); + } + } + } + + LCAlertDialog mLCAlertDialog; + private final String searchError = "searchError"; + + @Override + public void showSearchError() { + LCAlertDialog.Builder builder = new LCAlertDialog.Builder(getContext()); + builder.setTitle(""); + builder.setMessage(R.string.add_device_choose_type_error); + builder.setCancelButton(R.string.common_cancel, null); + builder.setConfirmButton(R.string.common_confirm, + new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, boolean isChecked) { + dismissLCAlertDialog(); + } + }); + + mLCAlertDialog = builder.create(); + mLCAlertDialog.show(getActivity().getSupportFragmentManager(), + searchError); + } + + private void dismissLCAlertDialog() { + if (mLCAlertDialog != null && mLCAlertDialog.isVisible()) { + mLCAlertDialog.dismissAllowingStateLoss(); + mLCAlertDialog = null; + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/SmartConfigFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/SmartConfigFragment.java new file mode 100644 index 0000000..618d02c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/SmartConfigFragment.java @@ -0,0 +1,174 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.graphics.drawable.Animatable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.SmartConfigConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CircleCountDownView; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.presenter.SmartConfigPresenter; + +import static com.mm.android.deviceaddmodule.helper.PageNavigationHelper.WIFI_PWD_TAG; + +/** + * 设备wifi配置页面 + */ +public class SmartConfigFragment extends BaseDevAddFragment implements SmartConfigConstract.View, CircleCountDownView.OnCountDownFinishListener, + View.OnClickListener { + SmartConfigConstract.Presenter mPresenter; + CircleCountDownView mCountDownView; + ImageView mWifiAnimationView; + Animatable mWifiAnimation; + TextView mTip2Txt, mTipWifiPwdErrorTxt; + long mEventStartTime; //统计开始时间 + + public static SmartConfigFragment newInstance(/*boolean isQRCodeConfig*/) { + SmartConfigFragment fragment = new SmartConfigFragment(); + Bundle args = new Bundle(); + + fragment.setArguments(args); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_smart_config, container, false); + } + + protected void initView(View view) { + mTipWifiPwdErrorTxt = view.findViewById(R.id.tip_wifi_pwd_error); + mTip2Txt = view.findViewById(R.id.tip2_txt); + mCountDownView = view.findViewById(R.id.countdown_view); + mCountDownView.setCountDownListener(this); + mWifiAnimationView = view.findViewById(R.id.wifi_animation_view); + mWifiAnimation = (Animatable) mWifiAnimationView.getDrawable(); + mWifiAnimation.start(); + mTipWifiPwdErrorTxt.setOnClickListener(this); + } + + protected void initData() { + mPresenter = new SmartConfigPresenter(this/*, isQRCodeConfig*/); + //配对界面更多按钮只展示重新添加和取消 + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + + mPresenter.startSmartConfig(); + mCountDownView.startCountDown(); + mEventStartTime = System.currentTimeMillis(); + } + + @Override + public void onPause() { + super.onPause(); + LogUtil.debugLog("AudioConfig", "onPause"); + mPresenter.pauseAudio(); + } + + @Override + public void onResume() { + super.onResume(); + LogUtil.debugLog("AudioConfig", "onResume"); + mPresenter.playAudio(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (mWifiAnimation.isRunning()) { + mWifiAnimation.stop(); + } + LogUtil.debugLog("AudioConfig", "onDestroyView"); + mPresenter.releaseAudio(); + mPresenter.recyle(); + } + + @Override + public void goDevInitPage(DEVICE_NET_INFO_EX device_net_info_ex) { + PageNavigationHelper.gotoSecurityCheckPage(this); + } + + @Override + public void goConnectCloudPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } + + @Override + public void goDevLoginPage() { + PageNavigationHelper.gotoDevLoginPage(this); + } + + @Override + public void goConfigTimeoutPage() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.WIRED_WIRELESS_ERROR_CONFIG_TIMEOUT); + } + + @Override + public void goWfiPwdPage() { + getActivity().getSupportFragmentManager().popBackStackImmediate(WIFI_PWD_TAG, 0); + } + + @Override + public void stopCountDown() { + mCountDownView.stopCountDown(); + } + + @Override + public void updateTip2Txt(boolean isSupportSoundWave, boolean isSupportSoundWaveV2) { + if (isSupportSoundWave || isSupportSoundWaveV2) { + if (ProviderManager.getAppProvider().getAppType() == 1) { + mTip2Txt.setText(R.string.add_device_higher_phone_volume); + } else { + mTip2Txt.setText(isSupportSoundWaveV2 ? R.string.add_device_adjust_phone_volume_to_hear_jiji : R.string.add_device_adjust_phone_volume_to_hear_bugu); + } + } else { + mTip2Txt.setText(R.string.add_device_keep_phone_close_to_device); + } + } + + @Override + public void hideTipWifiPwdErrorTxt(boolean isOversea) { + mTipWifiPwdErrorTxt.setVisibility(isOversea ? View.GONE : View.VISIBLE); + } + + @Override + public void countDownFinished() { + goConfigTimeoutPage(); + } + + @Override + public void middleTimeUp() { + + } + + @Override + public void completeAction() { + if (getActivity() != null) getActivity().finish(); + } + + @Override + public void goBindDevicePage() { + PageNavigationHelper.gotoDeviceBindPage(this); + } + + @Override + public void onClick(View v) { + if (mPresenter != null) { + mPresenter.wifiPwdErrorClick(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipLightFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipLightFragment.java new file mode 100644 index 0000000..bfd01ec --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipLightFragment.java @@ -0,0 +1,85 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.DeviceAddImageLoaderHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.nostra13.universalimageloader.core.ImageLoader; + +/** + * 设备灯光提示页 + */ +public class TipLightFragment extends BaseTipFragment implements View.OnClickListener { + + + public static TipLightFragment newInstance() { + TipLightFragment fragment = new TipLightFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void nextAction() { + PageNavigationHelper.gotoSoundTipPage(this); + } + + @Override + protected void helpAction() { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_RESET); + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + @Override + protected void initView(View view) { + super.initView(view); + mConfirmCheck.setVisibility(View.VISIBLE); + mNextBtn.setEnabled(false); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo=DeviceAddModel.newInstance().getDeviceInfoCache(); + if(DeviceAddInfo.ConfigMode.LAN.name().equalsIgnoreCase(deviceAddInfo.getConfigMode()) + || !deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } + DeviceIntroductionInfo deviceIntroductionInfo = deviceAddInfo.getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipImage = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_GUIDING_LIGHT_IMAGE); + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_CONFIG_INTRODUCTION); + String checkTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_CONFIG_CONFIRM_INTRODUCTION); + String helpTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_RESET_GUIDE_INTRODUCTION); + if (!TextUtils.isEmpty(tipImage)) { + ImageLoader.getInstance().displayImage(tipImage, mTipImg, + DeviceAddImageLoaderHelper.getCommonOptions()); + } + if (!TextUtils.isEmpty(tipTxt)) { + mTipTxt.setText(tipTxt); + + } + if (!TextUtils.isEmpty(checkTxt)) { + mConfirmCheck.setText(checkTxt); + } + if (!TextUtils.isEmpty(helpTxt)) { + mHelpTxt.setVisibility(View.VISIBLE); + mHelpTxt.setText(helpTxt); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipNetCablePluginFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipNetCablePluginFragment.java new file mode 100644 index 0000000..4317374 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipNetCablePluginFragment.java @@ -0,0 +1,71 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +/** + * 网线插入提示 + */ +public class TipNetCablePluginFragment extends BaseTipFragment { + + public static TipNetCablePluginFragment newInstance() { + TipNetCablePluginFragment fragment = new TipNetCablePluginFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void nextAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + PageNavigationHelper.gotoCloudConnectPage(this); + } else { + PageNavigationHelper.gotoSameNetworkTipPage(this); + } + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + + @Override + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mTipImg.setImageResource(R.drawable.adddevice_netsetting_networkcable); + mTipImg.setScaleType(ImageView.ScaleType.FIT_CENTER); + mTipTxt.setText(R.string.add_device_plug_cable_to_device); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo= DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoftAP.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE4); + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SmartConfig.name()) + || deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWave.name()) + || deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWaveV2.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE3); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipPowerFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipPowerFragment.java new file mode 100644 index 0000000..b8dcccb --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipPowerFragment.java @@ -0,0 +1,129 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.view.View; +import android.widget.ImageView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +/** + * 连接电源提示 + */ +public class TipPowerFragment extends BaseTipFragment { + private static String CONFIG_PARAM = "config_param"; + boolean mIsWirelessConfig = true; + Handler mHandler = new Handler(); + + public static TipPowerFragment newInstance(boolean isWirelessConfig) { + TipPowerFragment fragment = new TipPowerFragment(); + Bundle args = new Bundle(); + args.putBoolean(CONFIG_PARAM, isWirelessConfig); + fragment.setArguments(args); + return fragment; + } + + private void changeWiredWirless(boolean isWireless){ + mIsWirelessConfig=isWireless; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoftAP.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE4); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } + + @Override + protected void nextAction() { + if (mIsWirelessConfig) { + wirelessNavigation(); + } else { + wiredNavigation(); + } + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mTipImg.setImageResource(R.drawable.common_netsetting_power); + mTipImg.setScaleType(ImageView.ScaleType.FIT_CENTER); + mTipTxt.setText(R.string.add_device_plug_power); + } + + protected void initData() { + super.initData(); + if (getArguments() != null) { + mIsWirelessConfig = getArguments().getBoolean(CONFIG_PARAM); + } + } + + private void wirelessNavigation() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (Utils4AddDevice.isWifi(getActivity())) { + // 手机已连接wifi + SearchDeviceManager manager = SearchDeviceManager.getInstance(); + String sn = deviceAddInfo.getDeviceSn(); + DEVICE_NET_INFO_EX info = manager.getDeviceNetInfo(sn); + if (info != null) { + // 支持sc码,进入云配置流程 + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + PageNavigationHelper.gotoCloudConnectPage(this); + } else { + // 搜索到设备进入初始化流程 + PageNavigationHelper.gotoSecurityCheckPage(this); + } + } else { + // 未搜到设备,进入配网流程 + PageNavigationHelper.gotoWifiPwdPage(this, null); + } + } else { + // 未连接wifi,进入将手机连接WiFi网络提示页 + PageNavigationHelper.gotoWifiConnectTipPage(this); + } + } + + private void wiredNavigation() { + SearchDeviceManager manager = SearchDeviceManager.getInstance(); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String sn = deviceAddInfo.getDeviceSn(); + DEVICE_NET_INFO_EX info = manager.getDeviceNetInfo(sn); + if (info != null) { + // 支持sc码,进入云配置流程 + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + PageNavigationHelper.gotoCloudConnectPage(this); + } else { + // 搜索到设备,进入初始化流程 + PageNavigationHelper.gotoSecurityCheckPage(this); + } + } else { + PageNavigationHelper.gotoNetCableTipPage(this); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSameNetworkFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSameNetworkFragment.java new file mode 100644 index 0000000..ccef886 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSameNetworkFragment.java @@ -0,0 +1,74 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +/** + * 同一网络提示页 + */ +public class TipSameNetworkFragment extends BaseTipFragment{ + + public static TipSameNetworkFragment newInstance() { + TipSameNetworkFragment fragment = new TipSameNetworkFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + protected void nextAction() { + if(!Utils4AddDevice.isWifi(getActivity().getApplicationContext())){ + showToastInfo(R.string.add_device_con_wifi); + return; + } + PageNavigationHelper.gotoSecurityCheckPage(this); + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } + + @Override + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mConfirmCheck.setVisibility(View.VISIBLE); + mTipTxt.setText(R.string.add_device_same_network_tip); + mTipImg.setImageResource(R.drawable.adddevice_samenet); + mConfirmCheck.setText(R.string.add_device_confirm_same_network); + mNextBtn.setEnabled(false); + mTipImg.setScaleType(ImageView.ScaleType.FIT_CENTER); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoftAP.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE4); + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SmartConfig.name()) + || deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWave.name()) + || deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWaveV2.name())) { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE3); + } else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSoundFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSoundFragment.java new file mode 100644 index 0000000..49cb2e6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipSoundFragment.java @@ -0,0 +1,117 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + + +import android.content.Context; +import android.media.AudioManager; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import android.widget.ImageView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseTipFragment; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +/** + * 设备声音提示页 + */ +public class TipSoundFragment extends BaseTipFragment { + + private int mCountDownTime = 5; // 倒计时5s + private Handler mHandle = new Handler(); + + private Runnable mRunable = new Runnable() { + @Override + public void run() { + if(!isAdded() || getActivity().isFinishing()){ + return; + } + if(mCountDownTime > 0) { + mNextBtn.setText(String.format(getString(R.string.add_device_next_step_count_down), mCountDownTime)); + mCountDownTime--; + mHandle.postDelayed(this, 1000); + } else { + nextAction(); + } + } + }; + + public static TipSoundFragment newInstance() { + TipSoundFragment fragment = new TipSoundFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initView(View view) { + super.initView(view); + tipImageMatch(); + mTipImg.setImageResource(R.drawable.adddevice_netsetting_near); + mTipImg.setScaleType(ImageView.ScaleType.FIT_CENTER); + String configMode=DeviceAddModel.newInstance().getDeviceInfoCache().getConfigMode(); + boolean isSupportSoundWave = configMode!=null && configMode.contains(DeviceAddInfo.ConfigMode.SoundWave.name()); + boolean isSupportSoundWaveV2 = DeviceAddHelper.isSupportSoundWaveV2(DeviceAddModel.newInstance().getDeviceInfoCache()); + if(isSupportSoundWave || isSupportSoundWaveV2){ + mTipTxt.setText(R.string.add_device_turn_up_volume_notice); + mTipTxt2.setVisibility(View.VISIBLE); + if(ProviderManager.getAppProvider().getAppType()==1) { + mTipTxt2.setText(R.string.add_device_phone_will_emit_signal); + } else { + mTipTxt2.setText(isSupportSoundWaveV2 ? R.string.add_device_will_hear_jiji : R.string.add_device_will_hear_bugu); + } + + /* mTipTxt.setText(R.string.add_device_adjust_phone_volume); + mTipTxt2.setVisibility(View.VISIBLE); + mTipTxt2.setText(R.string.add_device_will_hear_bugu);*/ + }else { + mTipTxt.setText(R.string.add_device_keep_phone_close_to_device); + mTipImg.setImageResource(R.drawable.adddevice_netsetting_closeto); + } + + mHandle.post(mRunable); + } + + @Override + protected void initData() { + super.initData(); + DeviceAddInfo deviceAddInfo=DeviceAddModel.newInstance().getDeviceInfoCache(); + if(DeviceAddInfo.ConfigMode.LAN.name().equalsIgnoreCase(deviceAddInfo.getConfigMode()) + || !deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } + } + + @Override + protected void nextAction() { + mHandle.removeCallbacks(mRunable); + + if (getActivity() != null) { + AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int max = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int current = am.getStreamVolume(AudioManager.STREAM_MUSIC); + if (current < max * 0.8) { //音量未调至最大的80%则需要toast提示 + showToastInfo(getString(R.string.add_device_add_volume_tip)); + } + } + + PageNavigationHelper.gotoSmartConfigPage(this/*, false*/); + } + + @Override + protected void helpAction() { + + } + + @Override + protected void init() { + initView(mView); + initData(); + } +} \ No newline at end of file diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipWifiConnectFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipWifiConnectFragment.java new file mode 100644 index 0000000..d66b1d6 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/TipWifiConnectFragment.java @@ -0,0 +1,109 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.TipWifiConnectConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.presenter.TipWifiConnectPresenter; + +/** + * wifi连接提示页 + */ +public class TipWifiConnectFragment extends BaseDevAddFragment implements TipWifiConnectConstract.View{ + TipWifiConnectConstract.Presenter mPresenter; + TextView mGotoWifiSetting; + private int last_network_type = -3; + + public static TipWifiConnectFragment newInstance() { + TipWifiConnectFragment fragment = new TipWifiConnectFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_wifi_connect_tip, container, false); + } + + @Override + protected void initView(View view) { + mGotoWifiSetting = (TextView)view.findViewById(R.id.tv_goto_connect); + mGotoWifiSetting.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + CommonHelper.gotoWifiSetting(getActivity()); + } + }); + } + + protected void initData(){ + mPresenter=new TipWifiConnectPresenter(this); + String configMode = mPresenter.getConfigMode(); + if (DeviceAddInfo.ConfigMode.LAN.name().equalsIgnoreCase(configMode) + || !configMode.contains(DeviceAddInfo.ConfigMode.LAN.name())) + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } + } + + @Override + protected void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + if (LCConfiguration.CONNECTIVITY_CHAGET_ACTION.equals(intent.getAction())) { + final int netWorkState = Utils4AddDevice.getNetWorkState(getContextInfo()); + LogUtil.debugLog("TipWifiConnectFragment", "netWorkState : " + netWorkState); + if(netWorkState == Utils4AddDevice.NETWORK_WIFI && last_network_type != Utils4AddDevice.NETWORK_WIFI) { + mPresenter.searchDevice(); + } + last_network_type = netWorkState; + } + } + + @Override + protected IntentFilter createBroadCast() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(LCConfiguration.CONNECTIVITY_CHAGET_ACTION); + return intentFilter; + } + + @Override + public void goDevInitPage(DEVICE_NET_INFO_EX device_net_info_ex) { + PageNavigationHelper.gotoSecurityCheckPage(this); + } + + @Override + public void goWifiConfigPage() { + PageNavigationHelper.gotoWifiPwdPage(this,this); + } + + @Override + public void goCloudConnectPage() { + PageNavigationHelper.gotoCloudConnectPage(this); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/WifiPwdFragment.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/WifiPwdFragment.java new file mode 100644 index 0000000..945efe0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/p_wiredwireless/WifiPwdFragment.java @@ -0,0 +1,300 @@ +package com.mm.android.deviceaddmodule.p_wiredwireless; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.provider.Settings; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.base.BaseDevAddFragment; +import com.mm.android.deviceaddmodule.contract.WifiPwdConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.PageNavigationHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.DefaultPermissionListener; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.common.PermissionHelper; +import com.mm.android.deviceaddmodule.mobilecommon.dialog.LCAlertDialog; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.location.FuseLocationUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIHelper; +import com.mm.android.deviceaddmodule.mobilecommon.widget.ClearPasswordEditText; +import com.mm.android.deviceaddmodule.presenter.WifiPwdPresenter; + +/** + * 输入wifi密码页 + */ +public class WifiPwdFragment extends BaseDevAddFragment implements WifiPwdConstract.View, View.OnClickListener { + private ImageView mWifiIv; + private TextView mNextTv; + private TextView mWifiSsidTv; + private ClearPasswordEditText mWifiPwdEt; + private TextView m5GWifiTipTv; + private TextView mSaveWifiPwdChebox; + WifiPwdConstract.Presenter mPresenter; + private ImageView mSwitchWifiIv; + + public static WifiPwdFragment newInstance() { + WifiPwdFragment fragment = new WifiPwdFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + private final TextWatcher mTextWatcher = new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) { + mWifiPwdEt.removeTextChangedListener(mTextWatcher); + String str = Utils4AddDevice.wifiPwdFilter(s.toString()); + if (!str.equals(s.toString())) { + mWifiPwdEt.setText(str); + mWifiPwdEt.setSelection(str.length()); + } + mWifiPwdEt.addTextChangedListener(mTextWatcher); + setConnectButtonState(); + } + + @Override + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void afterTextChanged(Editable arg0) { + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_wifi_pwd, container, false); + } + + @Override + public void onResume() { + super.onResume(); + mWifiSsidTv.setText(mPresenter.getCurWifiName()); + setWifiPwd(); + + } + + @Override + public void onPause() { + super.onPause(); + mPresenter.updateWifiCache();//更新wifi信息到缓存 + } + + protected void initView(View view) { + mWifiIv = view.findViewById(R.id.iv_wifi); + mSwitchWifiIv = view.findViewById(R.id.switch_wifi); + mNextTv = view.findViewById(R.id.next); + m5GWifiTipTv = view.findViewById(R.id.tv_5g_tip); + mWifiSsidTv = view.findViewById(R.id.ssid); + mWifiPwdEt = view.findViewById(R.id.wifi_pwd); + mWifiPwdEt.openEyeMode(ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA); + mWifiPwdEt.addTextChangedListener(mTextWatcher); + mNextTv.setOnClickListener(this); + mSaveWifiPwdChebox = view.findViewById(R.id.wifi_pwd_check); + m5GWifiTipTv.setOnClickListener(this); + mSaveWifiPwdChebox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + view.setSelected(!view.isSelected()); + } + }); + + mSwitchWifiIv.setOnClickListener(this); + } + + protected void initData() { + mPresenter = new WifiPwdPresenter(this); + String configMode = mPresenter.getConfigMode(); + if (DeviceAddInfo.ConfigMode.LAN.name().equalsIgnoreCase(configMode) + || !configMode.contains(DeviceAddInfo.ConfigMode.LAN.name())) + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE); + else { + DeviceAddHelper.updateTile(DeviceAddHelper.TitleMode.MORE2); + } + check5GWifiTip(); + setConnectButtonState(); + setSSIDTextView(true); + } + + private void setSSIDTextView(boolean needCheckPermission) { + if (null != getActivity() && !Utils4AddDevice.isWifi(getActivity())) { + mWifiSsidTv.setText(""); + mWifiPwdEt.setText(""); + showToastInfo(R.string.add_device_con_wifi); + return; + } + + String curWifiName = mPresenter.getCurWifiName(); + if (TextUtils.isEmpty(curWifiName) && needCheckPermission) { + dealWithUnknownSsid(); + return; + } + + mWifiSsidTv.setText(curWifiName); + setWifiPwd(); + } + + private void dealWithUnknownSsid() { + if (getActivity() == null) return; + //1.判断是否该应用有地理位置权限 2.判断是否开启定位服务 + PermissionHelper permissionHelper = new PermissionHelper(this); + if (permissionHelper.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { + verifyLocationService(); + } else { + permissionHelper.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new DefaultPermissionListener() { + @Override + public void onGranted() { + verifyLocationService(); + } + + @Override + public boolean onDenied() { + return true; + } + }); + } + + + } + + private void verifyLocationService() { + if (FuseLocationUtil.isGpsEnabled(getActivity())) { + mWifiSsidTv.setText(mPresenter.getCurWifiName()); + setWifiPwd(); + } else { + showOpenLocationServiceDialog(); + } + + } + + private void showOpenLocationServiceDialog() { + LCAlertDialog dialog = new LCAlertDialog.Builder(getActivity()) + .setTitle(R.string.add_device_goto_open_location_service) + .setCancelButton(R.string.common_cancel, null) + .setConfirmButton(R.string.common_confirm, new LCAlertDialog.OnClickListener() { + @Override + public void onClick(LCAlertDialog dialog, int which, boolean isChecked) { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + startActivity(intent); + dialog.dismiss(); + } + }).create(); + dialog.show(getFragmentManager(), null); + } + + private void setWifiPwd() { + String wifiPwd = mPresenter.getSavedWifiPwd(); + boolean wifiCheckBoxStatus = mPresenter.getSavedWifiCheckBoxStatus(); + + if (!TextUtils.isEmpty(wifiPwd)) { + mWifiPwdEt.setText(wifiPwd); + mSaveWifiPwdChebox.setSelected(wifiCheckBoxStatus); + } else { + mWifiPwdEt.setText(""); + mSaveWifiPwdChebox.setSelected(wifiCheckBoxStatus); + } + } + + private void check5GWifiTip() { + if (!mPresenter.isDevSupport5G()) { + m5GWifiTipTv.setVisibility(View.VISIBLE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword_nosupport5g_layer); + } else { + m5GWifiTipTv.setVisibility(View.GONE); + mWifiIv.setImageResource(R.drawable.adddevice_icon_wifipassword); + } + } + + private void setConnectButtonState() { + if (null != getActivity() && !Utils4AddDevice.isWifi(getActivity())) { + UIHelper.setEnabledEX(false, mNextTv); + } else { + UIHelper.setEnabledEX(true, mNextTv); + } + } + + @Override + protected IntentFilter createBroadCast() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(LCConfiguration.CONNECTIVITY_CHAGET_ACTION); + return intentFilter; + } + + @Override + protected void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + if (LCConfiguration.CONNECTIVITY_CHAGET_ACTION.equals(intent.getAction())) { + setConnectButtonState(); + setSSIDTextView(false); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (null != getActivity() && mWifiPwdEt != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPwdEt.getWindowToken(), 0); + + } + super.onDestroyView(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (getActivity() == null) return; + if (R.id.next == id) { + if (!Utils4AddDevice.isWifi(getActivity())) { + toastInCenter(R.string.add_device_con_wifi); + return; + } + + if (TextUtils.isEmpty(mWifiSsidTv.getText().toString())) { + toast(R.string.mobile_common_permission_explain_access_location_usage); + return; + } + + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(mWifiPwdEt.getWindowToken(), 0); + + PageNavigationHelper.gotoLightTipPage(this); + } else if (R.id.tv_5g_tip == id) { + PageNavigationHelper.gotoErrorTipPage(this, DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G); + } else if (R.id.switch_wifi == id) { + CommonHelper.gotoWifiSetting(getActivity()); + } + } + + @Override + public String getWifiPwd() { + return mWifiPwdEt.getText().toString(); + } + + @Override + public boolean isSavePwdChecked() { + return mSaveWifiPwdChebox.isSelected(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApBindSuccessPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApBindSuccessPresenter.java new file mode 100644 index 0000000..ed05954 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApBindSuccessPresenter.java @@ -0,0 +1,78 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHNetworkUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.ApBindSuccessConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class ApBindSuccessPresenter implements ApBindSuccessConstract.Presenter { + WeakReference mView; + AddApResult mAddApResult; + + public ApBindSuccessPresenter(ApBindSuccessConstract.View view) { + mView = new WeakReference<>(view); + } + + private void initApView() { + DeviceIntroductionInfo deviceIntroductionInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String img = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_FINISH_DEVICE_IMAGE); + mView.get().setApImg(img); + } + if (mAddApResult != null) { + mView.get().setApName(mAddApResult.getApName()); + } + } + + @Override + public void modifyApName() { + if(!DHNetworkUtil.isConnected(mView.get().getContextInfo())){ + mView.get().showToastInfo(R.string.mobile_common_bec_common_network_exception); + return; + } + + final String apName = mView.get().getApName(); + if (TextUtils.isEmpty(apName)) { + mView.get().showToastInfo(R.string.device_manager_input_device_name); + return; + } + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + mView.get().showProgressDialog(); + final String deviceId = deviceAddInfo.getGatewayInfo().getSn(); + final String apId = deviceAddInfo.getDeviceSn(); + LCBusinessHandler modifyHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + mView.get().cancelProgressDialog(); + if (HandleMessageCode.HMC_SUCCESS == msg.what) { + mView.get().completeAction(); + } else { + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + } + }; + boolean hasToDeviceAbility = deviceAddInfo.hasAbility(DeviceAbility.ModifyName); + DeviceAddModel.newInstance().modifyAPDevice(deviceId, apId, apName, hasToDeviceAbility, modifyHandler); + } + + @Override + public void setData(AddApResult addApResult) { + mAddApResult = addApResult; + initApView(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApPairPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApPairPresenter.java new file mode 100644 index 0000000..2743ae5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ApPairPresenter.java @@ -0,0 +1,59 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; + +import com.mm.android.deviceaddmodule.contract.ApPairConstract; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.AddApResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class ApPairPresenter implements ApPairConstract.Presenter { + WeakReference mView; + + public ApPairPresenter(ApPairConstract.View view) { + mView = new WeakReference<>(view); + } + + @Override + public void pair() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + DeviceAddInfo.GatewayInfo gatewayInfo = deviceAddInfo.getGatewayInfo(); + if(gatewayInfo == null){ //异常保护 + return; + } + String deviceId = gatewayInfo.getSn(); + String apId = deviceAddInfo.getDeviceSn(); + getPariResultSync(deviceId, apId); + } + + @Override + public void stopPair() { + DeviceAddModel.newInstance().setLoop(false); + } + + private void getPariResultSync(final String deviceId, final String apId) { + LCBusinessHandler resultHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (HandleMessageCode.HMC_SUCCESS == msg.what) { + AddApResult addApResult = (AddApResult) msg.obj; + apPairSucceed(addApResult); + }else{ + getPariResultSync(deviceId, apId); + } + } + }; + DeviceAddModel.newInstance().getAddApResultAsync(deviceId, apId, resultHandler); + } + + private void apPairSucceed(AddApResult addApResult) { + if(mView.get() != null){ + mView.get().goApBindSuccessPage(addApResult); + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BaseSoftApTipPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BaseSoftApTipPresenter.java new file mode 100644 index 0000000..c3a4415 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BaseSoftApTipPresenter.java @@ -0,0 +1,117 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Build; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHNetworkUtil; +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.BaseSoftApTipConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class BaseSoftApTipPresenter implements BaseSoftApTipConstract.Presenter { + private int TIME_OUT_TIME = 10 * 1000; //连接设备热点超时时间 + private static final int CONNECT_FAILED = 0; //连接热点失败 + DHWifiUtil mDHWifiUtil; + String mDeviceSn; + boolean mConnectResult; + WeakReference mView; + DeviceIntroductionInfo mTips; + String mResetTxt; //reset引导信息 + int mCurStep = 0; //当前引导页索引,从0开始 + int mMaxStep = 1; //总引导页数 + + + public BaseSoftApTipPresenter(BaseSoftApTipConstract.View view, int curStep) { + mView = new WeakReference<>(view); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + mTips = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mCurStep = curStep; + initPageTip(); + } + + private void initPageTip() { + if(mTips!=null) { + mResetTxt = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESET_GUIDE_INTRODUCTION); + String oneTips = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_ONE_INTRODUCTION); + String oneTipsImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_ONE_IMAGE); + String twoTips = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_TWO_INTRODUCTION); + String twoTipsImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_TWO_IMAGE); + String threeTips = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_THREE_INTRODUCTION); + String threeTipsImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_THREE_IMAGE); + String fourTips = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_FOUR_INTRODUCTION); + String fourTipsImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_GUIDING_STEP_FOUR_IMAGE); + + if (!TextUtils.isEmpty(oneTips)) { + mMaxStep = 1; + } + if (!TextUtils.isEmpty(twoTips)) { + mMaxStep = 2; + } + if (!TextUtils.isEmpty(threeTips)) { + mMaxStep = 3; + } + if (!TextUtils.isEmpty(fourTips)) { + mMaxStep = 4; + } + if(mCurStep==mMaxStep-1){ + mView.get().updateResetTxt(mResetTxt); + } + if(mCurStep==0){ + mView.get().updateTipImage(!TextUtils.isEmpty(oneTipsImg) ? oneTipsImg : "drawable://" + R.drawable.adddevice_supportsoftap); + mView.get().updateTipTxt(oneTips); + }else if(mCurStep==1){ + mView.get().updateTipImage(twoTipsImg); + mView.get().updateTipTxt(twoTips); + }else if(mCurStep==2){ + mView.get().updateTipImage(threeTipsImg); + mView.get().updateTipTxt(threeTips); + }else if(mCurStep==3){ + mView.get().updateTipImage(fourTipsImg); + mView.get().updateTipTxt(fourTips); + } + } + } + + @Override + public boolean isWifiConnect(){ + return DHNetworkUtil.NetworkType.NETWORK_WIFI.equals(DHNetworkUtil.getNetworkType(mView.get().getContextInfo())); + } + + + @Override + public boolean isLastTipPage() { + return mCurStep==mMaxStep-1; + } + + + @Override + public void verifyWifiOrLocationPermission(){ + if(!isWifiConnect()){ //预先打开wifi + mDHWifiUtil.openWifi(); + } + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ + mView.get().applyLocationPermission(); + }else{ + mView.get().gotoSoftApTipConnectWifiPage(); + } + } + + @Override + public void dealWithUnknownSsid() { + + String curWifiName = mDHWifiUtil.getCurrentWifiInfo().getSSID().replaceAll("\"", ""); + if(LCConfiguration.UNKNOWN_SSID.equals(curWifiName)){ + mView.get().applyLocationPermission(); + }else { + mView.get().gotoSoftApTipConnectWifiPage(); + } + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BindSuccessPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BindSuccessPresenter.java new file mode 100644 index 0000000..56bf020 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/BindSuccessPresenter.java @@ -0,0 +1,145 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHNetworkUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.BindSuccessConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; +import com.mm.android.deviceaddmodule.openapi.data.DeviceDetailListData; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class BindSuccessPresenter implements BindSuccessConstract.Presenter { + private static final String CHANNEL_INDEX = "0"; + WeakReference mView; + String mDevDefaultName; + DeviceAddInfo mDeviceAddInfo; + boolean mIsOverSea; + + public BindSuccessPresenter(BindSuccessConstract.View view) { + mView = new WeakReference<>(view); + initViewData(); + } + + private void initViewData() { + mDeviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + mDevDefaultName = mDeviceAddInfo.getDeviceDefaultName(); + mView.get().setDevName(mDevDefaultName); + updateDevImg(); + mIsOverSea = ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA; + } + + private void updateDevImg() { + DeviceIntroductionInfo deviceIntroductionInfo = mDeviceAddInfo.getDevIntroductionInfo(); + if (deviceIntroductionInfo != null && deviceIntroductionInfo.getImageInfos() != null) { + HashMap imageInfos = deviceIntroductionInfo.getImageInfos(); + String img = ""; + if (imageInfos.containsKey(DeviceAddHelper.OMSKey.WIFI_MODE_FINISH_DEVICE_IMAGE)) { + img = imageInfos.get(DeviceAddHelper.OMSKey.WIFI_MODE_FINISH_DEVICE_IMAGE); + } else if (imageInfos.containsKey(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESULT_PROMPT_IMAGE)) { + img = imageInfos.get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESULT_PROMPT_IMAGE); + } else if (imageInfos.containsKey(DeviceAddHelper.OMSKey.LOCATION_MODE_FINISH_DEVICE_IMAGE)) { + img = imageInfos.get(DeviceAddHelper.OMSKey.LOCATION_MODE_FINISH_DEVICE_IMAGE); + } else if (imageInfos.containsKey(DeviceAddHelper.OMSKey.THIRD_PARTY_PLATFORM_MODE_RESULT_PROMPT_IMAGE)) { + img = imageInfos.get(DeviceAddHelper.OMSKey.THIRD_PARTY_PLATFORM_MODE_RESULT_PROMPT_IMAGE); + } + mView.get().updateDevImg(img); + } + } + + @Override + public void refreshDevice(final boolean isExit) { + mView.get().completeAction(); + } + + @Override + public void modifyDevName() { + if (!DHNetworkUtil.isConnected(mView.get().getContextInfo())) { + mView.get().showToastInfo(R.string.mobile_common_bec_common_network_exception); + return; + } + + final String sn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + String channelId = ""; + // 国内单通道设备修改通道名称 + if (ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA + && DeviceAddModel.newInstance().getDeviceInfoCache().getChannelNum() == 1) { + channelId = CHANNEL_INDEX; + } + final String devName = mView.get().getDevName(); + if (TextUtils.isEmpty(devName)) { + mView.get().showToastInfo(R.string.device_manager_input_device_name); + return; + } + + mView.get().showProgressDialog(); + LCBusinessHandler modifyNameHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + refreshDevice(true); + } else { + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + } + }; + DeviceAddModel.newInstance().modifyDeviceName(sn, channelId, devName, modifyNameHandler); + } + + @Override + public void getDevName() { + mView.get().showProgressDialog(); + final LCBusinessHandler handler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + //成功 + DeviceDetailListData.Response response = (DeviceDetailListData.Response) msg.obj; + mView.get().deviceName(response.data.deviceList.get(0).name); + } else { + //失败 + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + }; + new BusinessRunnable(handler) { + @Override + public void doBusiness() throws BusinessException { + try { + //获取设备详情列表request参数封装 + DeviceDetailListData deviceDetailListData = new DeviceDetailListData(); + List deviceListBeans = new ArrayList<>(); + DeviceDetailListData.RequestData.DeviceListBean deviceListBean = new DeviceDetailListData.RequestData.DeviceListBean(); + deviceListBean.deviceId = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + deviceListBeans.add(deviceListBean); + deviceDetailListData.data.deviceList = deviceListBeans; + //获取设备详情列表 + DeviceDetailListData.Response result = DeviceAddOpenApiManager.deviceOpenDetailList(deviceDetailListData); + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, result).sendToTarget(); + } catch (BusinessException e) { + throw e; + } + } + }; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/CloudConnectPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/CloudConnectPresenter.java new file mode 100644 index 0000000..e99dc80 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/CloudConnectPresenter.java @@ -0,0 +1,230 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.CloudConnectConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +public class CloudConnectPresenter implements CloudConnectConstract.Presenter { + static int TIME_OUT = 60; //查询超时时间、单位S + static int MIDDLE_TIME = 50; //P2P设备最大允许等待时间,单位S,若已在服务注册、DMS不在线的P2P类型设备,在该时间到后,直接走绑定流程 + static int SOFT_AP_TIME_OUT = 120; //软AP查询超时时间、单位S + static int SOFT_AP_MIDDLE_TIME = 100; //P2P设备最大允许等待时间,单位S,若已在服务注册、DMS不在线的P2P类型设备,在该时间到后,直接走绑定流程 + static int NB_TIME_OUT = 180; //NB查询超时时间、单位S + WeakReference mView; + long mEventStartTime; //统计开始时间 + + public CloudConnectPresenter(CloudConnectConstract.View view) { + mView = new WeakReference<>(view); + int timeout = TIME_OUT; + int middleTime = MIDDLE_TIME; + DeviceAddInfo.DeviceAddType deviceAddType = DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType(); + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddType)) { + timeout = SOFT_AP_TIME_OUT; + middleTime = SOFT_AP_MIDDLE_TIME; + } else if (DeviceAddInfo.DeviceAddType.NBIOT.equals(deviceAddType)) { + timeout = NB_TIME_OUT; + } + mView.get().setCountDownTime(timeout); + mView.get().setMiddleTime(middleTime); + } + + + @Override + public void bindDevice() { + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + final String sn = deviceAddInfo.getDeviceSn(); + String pwd = deviceAddInfo.getDevicePwd(); + // 无auth能力集的设备没有设备密码 + final String devPwd = pwd; + String userName = StringUtils.getRTSPAuthPassword("admin", sn); + DeviceAddInfo.GPSInfo gpsInfo = deviceAddInfo.getGpsInfo(); + final String code = deviceAddInfo.getRegCode(); + String imeiCode = deviceAddInfo.getImeiCode(); + LCBusinessHandler bindHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + if (DeviceAddInfo.BindStatus.bindByMe.name().equals(deviceAddInfo.getBindStatus())) { //设备被当前帐户绑定 + mView.get().showToastInfo(R.string.add_device_device_bind_by_yourself); + mView.get().completeAction(); + } else if (DeviceAddInfo.BindStatus.bindByOther.name().equals(deviceAddInfo.getBindStatus())) { //设备被其他帐户绑定 + mView.get().goOtherUserBindTipPage(); + } else { +// mView.get().goBindSuceesPage(); + } + } else { + String errorDesp = ((BusinessException) msg.obj).errorDescription; + if (errorDesp.contains("DV1014")) { //设备绑定错误连续超过10次,限制绑定30分钟 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN); + } else if (errorDesp.contains("DV1015")) { //设备绑定错误连续超过20次,限制绑定24小时 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE); + } else if (errorDesp.contains("DV1044")) { //设备IP不在统一局域网内 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_IP_ERROR); + } else if (errorDesp.contains("DV1045")) { // 设备冲突 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_CODE_CONFLICT); + } else if (errorDesp.contains("DV1042")) { // 设备密码错误达限制次数,设备锁定 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_LOCKED); + } else if (errorDesp.contains("DV1027")) { // 设备安全码错误 + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + mView.get().goDevSecCodePage(); + deviceAddInfo.setRegCode(""); + } else if (errorDesp.contains("DV1016") || errorDesp.contains("DV1025")) { // 设备密码错误(环回认证失败)/设备SC码或设备密码错误 + // mView.get().showToastInfo(R.string.add_device_verify_device_pwd_failed); + mView.get().goDevLoginPage(); + deviceAddInfo.setDevicePwd(""); + } else if (errorDesp.contains("DV1037")) { //NB设备的imei和device id 不匹配 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH); + } else { + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + mView.get().goErrorTipPage(); + } + } + } + }; + DeviceAddModel.newInstance().bindDevice(sn, code, "", imeiCode, gpsInfo.getLongitude(), gpsInfo.getLatitude(), userName, devPwd, bindHandler); + bindHandler.postDelayed(new Runnable() { + @Override + public void run() { + mView.get().goMainbind(sn, code, devPwd); + mView.get().completeAction(); + } + }, 5000); + } + + @Override + public void getDeviceInfo() { + String deviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + String model = DeviceAddModel.newInstance().getDeviceInfoCache().getModelName(); + String imeiCode = DeviceAddModel.newInstance().getDeviceInfoCache().getImeiCode(); + final String requestId = DeviceAddModel.newInstance().getDeviceInfoCache().getRequestId(); + LCBusinessHandler getDeviceHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + dispatchResult(); + } else {//发生异常且倒计时未完成,重新查询 + String errorDesp = ((BusinessException) msg.obj).errorDescription; + if (errorDesp.contains("DV1037")) { + DeviceAddModel.newInstance().setLoop(false); + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH); + } else { + getDeviceInfo(); + } + } + + } + }; + DeviceAddModel.newInstance().getDeviceInfoLoop(deviceSn, model, imeiCode, TIME_OUT, getDeviceHandler); + } + + @Override + public void recyle() { + + DeviceAddModel.newInstance().setMiddleTimeUp(false); + } + + @Override + public boolean isWifiOfflineConfiMode() { + return DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode(); + } + + @Override + public void notifyMiddleTimeUp() { + DeviceAddModel.newInstance().setMiddleTimeUp(true); + } + + @Override + public void startConnectTiming() { + mEventStartTime = System.currentTimeMillis(); + } + + @Override + public void stopConnectTiming() { + + } + + private void dispatchResult() { + stopConnectTiming(); + DeviceAddModel.newInstance().setLoop(false); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String status = deviceAddInfo.getStatus(); + if (TextUtils.isEmpty(status)) { + status = DeviceAddInfo.Status.offline.name(); + } + if (DeviceAddInfo.Status.online.name().equals(status) + || DeviceAddInfo.Status.sleep.name().equals(status) + || DeviceAddInfo.Status.upgrading.name().equals(status) //设备已在线 + || (DeviceAddInfo.Status.offline.name().equals(status) && deviceAddInfo.isDeviceInServer() && deviceAddInfo.isP2PDev())) {//或者设备已在服务上注册,但不在线的P2P类型设备 + if (isWifiOfflineConfiMode()) {//wifi离线配置 + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.OFFLINE_CONFIG_SUCCESS_ACTION)); + mView.get().showToastInfo(R.string.add_device_wifi_config_success); + return; + } + + //设备不支持绑定 + if (!deviceAddInfo.isSupport()) { + mView.get().goNotSupportBuindTipPage(); + return; + } + + String devPwd = DeviceAddModel.newInstance().getDeviceInfoCache().getDevicePwd(); + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { + if (TextUtils.isEmpty(devPwd)) { + mView.get().goDevLoginPage(); + } else { + mView.get().goBindDevicePage(); + } + } else { + + if (deviceAddInfo.hasAbility(DeviceAbility.Auth)) { + if (TextUtils.isEmpty(devPwd)) { + mView.get().goDevLoginPage();//输入设备密码 + } else { + mView.get().goBindDevicePage();//直接绑定 + } + } else if (deviceAddInfo.hasAbility(DeviceAbility.RegCode)) { + if (TextUtils.isEmpty(deviceAddInfo.getRegCode())) { + mView.get().goDevSecCodePage();//输入安全码 + } else { + mView.get().goBindDevicePage();//直接绑定 + } + } else { + mView.get().goBindDevicePage();//直接绑定 + } + } + } else { + if (isWifiOfflineConfiMode()) {//wifi离线配置 + mView.get().showToastInfo(R.string.add_device_config_failed); + mView.get().completeAction(); + } else { + mView.get().goErrorTipPage(); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevLoginPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevLoginPresenter.java new file mode 100644 index 0000000..4839f54 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevLoginPresenter.java @@ -0,0 +1,222 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.content.Intent; +import android.os.Message; +import android.text.TextUtils; + +import com.company.NetSDK.FinalVar; +import com.dahua.mobile.utility.network.DHNetworkUtil; +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.DevLoginConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceBindResult; +import com.mm.android.deviceaddmodule.mobilecommon.p2pDevice.P2PErrorHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.service.DeviceAddService; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + + +public class DevLoginPresenter implements DevLoginConstract.Presenter { + WeakReference mView; + String mDeviceSn; + boolean mIsWifiOfflineMode; + DHWifiUtil mDHWifiUtil; + + public DevLoginPresenter(DevLoginConstract.View view) { + mView = new WeakReference<>(view); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mIsWifiOfflineMode = DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode(); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + } + + @Override + public void devLogin() { + if (!DHNetworkUtil.isConnected(mView.get().getContextInfo())) { + mView.get().showToastInfo(R.string.mobile_common_bec_common_network_exception); + return; + } + if (!checkInput(mView.get().getDevicePassword())) { + mView.get().showToastInfo(R.string.device_manager_password_error); + return; + } + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + DeviceAddInfo.DeviceAddType deviceAddType = deviceAddInfo.getCurDeviceAddType(); + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddType)) { + String status = deviceAddInfo.getStatus(); + if (TextUtils.isEmpty(status)) { + status = DeviceAddInfo.Status.offline.name(); + } + + if (!DeviceAddInfo.Status.offline.name().equals(status)) {//设备已在线,直接绑定 + mView.get().showProgressDialog(); + verifyPassword(deviceAddInfo.getDeviceSn(), "admin", mView.get().getDevicePassword()); + } else { + goIPLogin(); + } + } else { + if (!deviceAddInfo.isEasy4ipP2PDev() && deviceAddInfo.hasAbility(DeviceAbility.Auth)) {//pass设备并且有Auth能力级,走协议验证密码 + mView.get().showProgressDialog(); + verifyPassword(deviceAddInfo.getDeviceSn(), "admin", mView.get().getDevicePassword()); + } else { + mView.get().cancelProgressDialog(); + mView.get().showToastInfo(R.string.add_device_not_support_to_bind); + } + } + } + + private boolean checkInput(String password) { + return !(password.length() == 0); + } + + //ip登录 + private void goIPLogin() { + String ip = mDHWifiUtil.getGatewayIp(); + + LCBusinessHandler ipLoginHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + int result = (int) msg.obj; + onLoginResult(result); + } + } + + }; + DeviceAddModel.newInstance().deviceIPLogin(ip, mView.get().getDevicePassword(), /*type == DHDeviceExtra.DeviceLoginType.SafeMode.ordinal(), */ipLoginHandler); + } + + //有auth能力级的设备走密码验证(绑定接口进行验证) + private void verifyPassword(final String sn, String user, String pwd) { + String encryptUser = StringUtils.getRTSPAuthPassword(user, sn); + final String encryptPwd = pwd; + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + DeviceAddInfo.GPSInfo gpsInfo = deviceAddInfo.getGpsInfo(); + final String code = deviceAddInfo.getRegCode(); + final LCBusinessHandler bindHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + if (DeviceAddInfo.BindStatus.bindByMe.name().equals(deviceAddInfo.getBindStatus())) { //设备被当前帐户绑定 + mView.get().showToastInfo(R.string.add_device_device_bind_by_yourself); + mView.get().completeAction(); + } else if (DeviceAddInfo.BindStatus.bindByOther.name().equals(deviceAddInfo.getBindStatus())) { //设备被其他帐户绑定 + mView.get().goOtherUserBindTipPage(); + } else { +// mView.get().goBindSuceesPage(); + } + } else { + String errorDesp = ((BusinessException) msg.obj).errorDescription; + if (errorDesp.contains("DV1014")) { //设备绑定错误连续超过10次,限制绑定30分钟 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN); + } else if (errorDesp.contains("DV1015")) { //设备绑定错误连续超过20次,限制绑定24小时 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE); + } else if (errorDesp.contains("DV1044")) { //设备IP不在统一局域网内 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_IP_ERROR); + } else if (errorDesp.contains("DV1045")) { // 设备冲突 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_CODE_CONFLICT); + } else if (errorDesp.contains("DV1042")) { // 设备密码错误达限制次数,设备锁定 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_LOCKED); + } else if (errorDesp.contains("DV1027")) { // 设备安全码错误 + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + mView.get().goDevSecCodePage(); + deviceAddInfo.setRegCode(""); + } else if (errorDesp.contains("DV1016") || errorDesp.contains("DV1025")) { // 设备密码错误(环回认证失败)/设备SC码或设备密码错误 + mView.get().showToastInfo(R.string.add_device_verify_device_pwd_failed); + } else if (errorDesp.contains("DV1037")) { //NB设备的imei和device id 不匹配 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH); + } else { + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + } + }; + + + DeviceAddModel.newInstance().bindDevice(sn, code, "", "", gpsInfo.getLongitude(), gpsInfo.getLatitude(), encryptUser, encryptPwd, bindHandler); + new BusinessRunnable(bindHandler) { + @Override + public void doBusiness() throws BusinessException { + DeviceAddService deviceAddService = new DeviceAddService(); + DeviceAddInfo mDeviceAddInfo = new DeviceAddInfo(); + DeviceBindResult deviceBindResult = deviceAddService.userDeviceBind(sn, encryptPwd, 45 * 1000); + mDeviceAddInfo.setDeviceDefaultName(deviceBindResult.getDeviceName()); + mDeviceAddInfo.setBindStatus(deviceBindResult.getBindStatus()); + mDeviceAddInfo.setBindAcount(deviceBindResult.getUserAccount()); + mDeviceAddInfo.setRecordSaveDays(deviceBindResult.getRecordSaveDays()); + mDeviceAddInfo.setStreamType(deviceBindResult.getStreamType()); + mDeviceAddInfo.setServiceTime(deviceBindResult.getServiceTime()); + bindHandler.obtainMessage(HandleMessageCode.HMC_SUCCESS).sendToTarget(); + } + }; + bindHandler.postDelayed(new Runnable() { + @Override + public void run() { + mView.get().goMainbind(sn, code, encryptPwd); + mView.get().completeAction(); + } + }, 5000); + } + + private void onLoginResult(int result) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + mView.get().cancelProgressDialog(); + + DeviceAddInfo.DeviceAddType deviceAddType = DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType(); + + if (result != FinalVar.NET_NOERROR) { + if (DeviceAddHelper.isDevPwdError(result)) {//密码错误 + mView.get().showToastInfo(R.string.add_device_password_error_and_will_lock); + } else { + if (P2PErrorHelper.LOGIN_ERROR_USER_LOCKED == result + || FinalVar.NET_LOGIN_ERROR_LOCKED == result) {//设备被锁定 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_LOCKED); + } else { + //其他错误,统一提示 + mView.get().showToastInfo(R.string.add_device_connect_error_and_quit_retry); + } + } + return; + } + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setDevicePwd(mView.get().getDevicePassword()); + if (mIsWifiOfflineMode) { + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddType)) { + mView.get().goSoftAPWifiListPage(); + } else { + //TODO 如果需要即时同步新密码,deviceAddInfo.getDevicePwd()密码需要通知到列表更新 + mView.get().showToastInfo(R.string.add_device_wifi_config_success); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + ProviderManager.getDeviceAddCustomProvider().goHomePage(mView.get().getContextInfo()); + } + } else { + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddType)) { + mView.get().goSoftAPWifiListPage(); + } else { + mView.get().goDeviceBindPage(); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevSecCodePresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevSecCodePresenter.java new file mode 100644 index 0000000..f55bd32 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevSecCodePresenter.java @@ -0,0 +1,108 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.DevSecCodeConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.StringUtils; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +public class DevSecCodePresenter implements DevSecCodeConstract.Presenter { + WeakReference mView; + String mDeviceSn; + boolean mIsWifiOfflineMode; + DHWifiUtil mDHWifiUtil; + + public DevSecCodePresenter(DevSecCodeConstract.View view) { + mView = new WeakReference<>(view); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mIsWifiOfflineMode = DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode(); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo()); + } + + @Override + public void validate() { + if (!checkInput(mView.get().getDeviceSecCode())) { + mView.get().showToastInfo(R.string.mobile_common_bec_add_device_valid_error); + return; + } + mView.get().showProgressDialog(); + bindDevice(mView.get().getDeviceSecCode()); + } + + private boolean checkInput(String regCode) { + return !(TextUtils.isEmpty(regCode) || regCode.length() < 6); + } + + private void bindDevice(final String code) { + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + final String sn = deviceAddInfo.getDeviceSn(); + String pwd = deviceAddInfo.getDevicePwd(); + // 无auth能力集的设备没有设备密码(进入该流程肯定无auth能力集) + final String devPwd = TextUtils.isEmpty(pwd) ? "" : StringUtils.getRTSPAuthPassword(pwd, sn); + String userName = StringUtils.getRTSPAuthPassword("admin", sn); + DeviceAddInfo.GPSInfo gpsInfo = deviceAddInfo.getGpsInfo(); + LCBusinessHandler bindHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + if (DeviceAddInfo.BindStatus.bindByMe.name().equals(deviceAddInfo.getBindStatus())) { //设备被当前帐户绑定 + mView.get().showToastInfo(R.string.add_device_device_bind_by_yourself); + mView.get().completeAction(); + } else if (DeviceAddInfo.BindStatus.bindByOther.name().equals(deviceAddInfo.getBindStatus())) { //设备被其他帐户绑定 + mView.get().goOtherUserBindTipPage(); + } else { +// mView.get().goBindSuceesPage(); + } + } else { + String errorDesp = ((BusinessException) msg.obj).errorDescription; + if (errorDesp.contains("DV1014")) { //设备绑定错误连续超过10次,限制绑定30分钟 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN); + } else if (errorDesp.contains("DV1015")) { //设备绑定错误连续超过20次,限制绑定24小时 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE); + } else if (errorDesp.contains("DV1045")) { // 设备冲突 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_CODE_CONFLICT); + } else if (errorDesp.contains("DV1044")) { //设备IP不在统一局域网内 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_IP_ERROR); + } else if (errorDesp.contains("DV1027")) { // 设备安全码错误 + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } else if (errorDesp.contains("DV1016") || errorDesp.contains("DV1025")) { // 设备密码错误(环回认证失败)/设备SC码或设备密码错误 + mView.get().showToastInfo(R.string.add_device_verify_device_pwd_failed); + mView.get().goDevLoginPage(); + deviceAddInfo.setDevicePwd(""); + } else if (errorDesp.contains("DV1037")) { //NB设备的imei和device id 不匹配 + mView.get().goErrorTipPage(DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH); + } else { + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + } + }; + DeviceAddModel.newInstance().bindDevice(sn, code, "", "", gpsInfo.getLongitude(), gpsInfo.getLatitude(), userName, code, bindHandler); + bindHandler.postDelayed(new Runnable() { + @Override + public void run() { + mView.get().goMainbind(sn, code, code); + mView.get().completeAction(); + } + }, 5000); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevWifiListPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevWifiListPresenter.java new file mode 100644 index 0000000..f3c2fbd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DevWifiListPresenter.java @@ -0,0 +1,93 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.contract.DevWifiListConstract; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +public class DevWifiListPresenter implements DevWifiListConstract.Presenter { + WeakReference mView; + private List mListData; + DHWifiUtil mDHWifiUtil; + String mDeviceSn; + private boolean mIsNotNeedLogin; + private boolean isSupport5G; + + public DevWifiListPresenter(DevWifiListConstract.View view, boolean isNotNeedLogin) { + mView = new WeakReference<>(view); + mDHWifiUtil=new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + mDeviceSn=DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mListData=new ArrayList<>(); + mIsNotNeedLogin = isNotNeedLogin; + String wifiMode = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiTransferMode(); + if (!TextUtils.isEmpty(wifiMode)) { + isSupport5G = wifiMode.toUpperCase().contains("5GHZ"); + } + getWifiList(); + } + + @Override + public boolean isDevSupport5G() { + return isSupport5G; + } + + @Override + public void getWifiList(){ + mView.get().showProgressDialog(); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST_DISABLE_ACTION)); + mListData.clear(); + String gatwayip= mDHWifiUtil.getGatewayIp(); + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String pwd = deviceAddInfo.getDevicePwd(); + + LCBusinessHandler getWifiListHandler=new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if(mView.get()!=null&&mView.get().isViewActive()){ + mView.get().cancelProgressDialog(); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SOFTAP_REFRSH_WIFI_LIST_ENABLE_ACTION)); + } + }, 500); + + if(msg.what== HandleMessageCode.HMC_SUCCESS){ + dispatchListResult(msg); + } else if(msg.what== HandleMessageCode.HMC_BATCH_MIDDLE_RESULT) { // 登陆失败 + mView.get().goDevLoginPage(); + } else { + mView.get().showErrorInfoView(); + } + } + } + }; + + if(mIsNotNeedLogin) { + DeviceAddModel.newInstance().getSoftApWifiList4Sc(gatwayip, getWifiListHandler); + } else { + DeviceAddModel.newInstance().getSoftApWifiList(gatwayip, pwd, /*type == DHDeviceExtra.DeviceLoginType.SafeMode.ordinal(), */getWifiListHandler); + } + } + + private void dispatchListResult(Message msg){ + mView.get().showListView(); + mListData= (List) msg.obj; + mView.get().updateWifiList(mListData); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DeviceAddPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DeviceAddPresenter.java new file mode 100644 index 0000000..ebd846c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DeviceAddPresenter.java @@ -0,0 +1,254 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.contract.DeviceAddConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.CommonHelper; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.zxing.Extras; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +public class DeviceAddPresenter implements DeviceAddConstract.Presenter { + WeakReference mView; + private SearchDeviceManager mServiceManager; + private String curTitleMode = DeviceAddHelper.TitleMode.BLANK.name(); //当前标题模式 + + public DeviceAddPresenter(DeviceAddConstract.View view) { + mView = new WeakReference<>(view); + // 启动搜索设备的服务 + mServiceManager = SearchDeviceManager.getInstance(); + mServiceManager.connnectService(); + } + + @Override + public String getCurTitleMode() { + return curTitleMode; + } + + @Override + public void setCurTitleMode(String titleMode) { + curTitleMode = titleMode; + } + + @Override + public void dispatchIntentData(Intent intent) { + Bundle bundle = intent.getExtras(); + boolean isHubPair = false; + String hubType = "";//hub 二代 + String sn = ""; + boolean offlineConfigType = false; + String deviceModelName = ""; + boolean isDeviceDetail = false; + String imeiCode = ""; + String scCode = ""; + String devPwd = ""; + boolean isFromDeviceDispatch = false; + DeviceAddInfo dispatch = null; + if (bundle != null) { + + isFromDeviceDispatch = bundle.getBoolean(Extras.device.EXTRAS_FROM_DISPATCH, false); + dispatch = (DeviceAddInfo) bundle.getSerializable(Extras.device.EXTRAS_DEVICE_DISPATCH); + + sn = bundle.getString(LCConfiguration.DEVICESN_PARAM); + isDeviceDetail = bundle.getBoolean(LCConfiguration.IS_DEVICE_DETAIL_PARAM); + DeviceAddInfo.GatewayInfo gatewayInfo = new DeviceAddInfo.GatewayInfo(); + gatewayInfo.setSn(sn); + DeviceAddModel.newInstance().getDeviceInfoCache().setGatewayInfo(gatewayInfo); + // 是否为中间页添加 + DeviceAddModel.newInstance().getDeviceInfoCache().setDeviceDetail(isDeviceDetail); + + isHubPair = bundle.getBoolean(LCConfiguration.HUB_PAIR_PARAM); + hubType = bundle.getString(LCConfiguration.HUB_TYPE_PARAM); + offlineConfigType = bundle.getBoolean(LCConfiguration.OFFLINE_CONFIG_TYPE_PARAM); + deviceModelName = bundle.getString(DeviceAddHelper.DEVICE_MODEL_NAME_PARAM); + + imeiCode = bundle.getString(LCConfiguration.DEVICE_IMEI_PARAM); + scCode = bundle.getString(LCConfiguration.SC_CODE_PARAM); + devPwd = bundle.getString(LCConfiguration.DEVICE_PWD_PARAM); + + } + + if (offlineConfigType) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setWifiOfflineMode(true); + deviceAddInfo.setDeviceSn(sn); + deviceAddInfo.setImeiCode(imeiCode); + deviceAddInfo.setSc(scCode); + deviceAddInfo.setDevicePwd(devPwd); + deviceAddInfo.setDeviceModel(deviceModelName); + LogUtil.debugLog("DeviceAddPresenter", "offlineConfigType deviceAddModel: " + DeviceAddModel.newInstance()); + LogUtil.debugLog("DeviceAddPresenter", "offlineConfigType deviceAddInfo: " + deviceAddInfo); + mView.get().setTitle(R.string.mobile_common_network_config); + deviceAddInfo.setStartTime(System.currentTimeMillis()); + mView.get().goOfflineConfigPage(sn, deviceModelName, imeiCode); + return; + } + if (isHubPair) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.HUB); + mView.get().goHubPairPage(sn, hubType); + } else if (isFromDeviceDispatch && dispatch != null) { + DeviceAddModel.newInstance().updateDeviceAllCache(dispatch); + mView.get().goDispatchPage(); + } else { + mView.get().goScanPage(); + } + } + + @Override + public void getGPSLocation() { + double[] gps = CommonHelper.getGpsInfo(mView.get().getContextInfo()); + DeviceAddInfo.GPSInfo gpsInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getGpsInfo(); + gpsInfo.setLongitude(String.valueOf(gps[0])); + gpsInfo.setLatitude(String.valueOf(gps[1])); + } + + @Override + public void dispatchPageNavigation() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (DeviceAddModel.newInstance().getDeviceInfoCache().isWifiConfigModeOptional()) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.SHOW_TYPE_CHOSE_ACTION)); + return; + } + if (DeviceAddInfo.DeviceType.ap.name().equals(deviceAddInfo.getType())) { + //TODO 当前版本不支持配件添加,直接提示返回 + + mView.get().goNotSupportBindTipPage(); + return; + } else { + //设备 + if (TextUtils.isEmpty(deviceAddInfo.getModelName()) && TextUtils.isEmpty(deviceAddInfo.getNc())) {//modelName 为空的情况 进入设备选择页 V3.9+ + mView.get().goTypeChoosePage(); + } else { + if (TextUtils.isEmpty(deviceAddInfo.getConfigMode())) { + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + mView.get().goWiredwirelessPage(false); + } else { + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoftAP.name())) { //软AP + // 局域网内搜索到则直接走初始化或连接云平台流程 + DEVICE_NET_INFO_EX deviceNetInfoEx = SearchDeviceManager.getInstance().getDeviceNetInfo(deviceAddInfo.getDeviceSn()); + if (deviceNetInfoEx != null) { + // 支持sc码,进入云配置流程 + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + mView.get().goCloudConnetPage(); + } else if (DeviceAddHelper.isDeviceNeedInit(deviceNetInfoEx)) { + mView.get().goInitPage(deviceNetInfoEx); + } else { + mView.get().goCloudConnetPage(); + } + } else { + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.SOFTAP); + mView.get().goSoftApPage(); + } + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.NBIOT.name())) { //NB配网 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.NBIOT); + if (TextUtils.isEmpty(deviceAddInfo.getImeiCode())) { + mView.get().goIMEIInputPage(); + } else { + mView.get().goNBPage(); + } + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoundWave.name()) + || deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SmartConfig.name())) { //无线 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.WLAN); + mView.get().goWiredwirelessPage(true); + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.LAN.name())) { //有线 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + mView.get().goWiredwirelessPage(false); + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.Location.name())) { //设备本地配网 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LOCAL); + mView.get().goLocationPage(); + } else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.Bluetooth.name())) { // 蓝牙锁配网 + Bundle bundle = new Bundle(); + bundle.putSerializable(LCConfiguration.BUNDLE_DEVICE_ADD_INFO, deviceAddInfo); + bundle.putString(LCConfiguration.DEVICE_MODEL, deviceAddInfo.getModelName()); + mView.get().gotoAddBleLockPage(bundle); + } else { + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + mView.get().goWiredwirelessPage(false); + } + } + } + } + } + + @Override + public void uninit() { + mServiceManager = SearchDeviceManager.getInstance(); + if (mServiceManager.checkSearchDeviceServiceIsExist()) { + mServiceManager = SearchDeviceManager.getInstance(); + mServiceManager.checkSearchDeviceServiceDestory(); + } + DeviceAddModel.newInstance().recyle(); + DeviceAddHelper.clearNetWork(); + } + + @Override + public void getDeviceShareInfo() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + + if (TextUtils.isEmpty(deviceAddInfo.getDeviceSn())) { + mView.get().showToastInfo(R.string.mobile_common_bec_common_network_exception); + return; + } + + mView.get().gotoDeviceSharePage(deviceAddInfo.getDeviceSn()); + } + + @Override + public boolean canBeShare() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + + //配件不能共享 + if (DeviceAddInfo.DeviceType.ap.name().equals(deviceAddInfo.getType())) { + return false; + } + + //DS11不能共享 + if ("DS11".equalsIgnoreCase(deviceAddInfo.getDeviceModel())) { + return false; + } + + //H1G不能共享 + if ("ARC2000E-GSW".equalsIgnoreCase(deviceAddInfo.getDeviceModel())) { + return false; + } + return true; + } + + @Override + public void changeToWireless() { + mView.get().goWiredwirelessPageNoAnim(true); + } + + @Override + public void changeToWired() { + // 软ap与有线流程切换后,设备密码会被清掉,故需要重新将sc码设置成设备密码 + DeviceAddHelper.setDevicePwdBySc(); + mView.get().goWiredwirelessPageNoAnim(false); + } + + @Override + public void changeToSoftAp() { + // 软ap与有线流程切换后,设备密码会被清掉,故需要重新将sc码设置成设备密码 + DeviceAddHelper.setDevicePwdBySc(); + mView.get().goSoftApPageNoAnim(); + } + + @Override + public void changeToNB() { + mView.get().goNBPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DispatchPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DispatchPresenter.java new file mode 100644 index 0000000..16d7a61 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/DispatchPresenter.java @@ -0,0 +1,231 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.DispatchContract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +import static com.mm.android.deviceaddmodule.helper.Utils4AddDevice.isDeviceTypeBox; + +public class DispatchPresenter implements DispatchContract.Presenter { + WeakReference mView; + + public DispatchPresenter(DispatchContract.View view) { + mView = new WeakReference<>(view); + } + + private void getDevIntroductionInfoSync(String deviceModel, final boolean isOnlineAction) { + LCBusinessHandler getDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + dispatchIntroductionResult(isOnlineAction); + } + }; + DeviceAddModel.newInstance().getDevIntroductionInfo(deviceModel, getDevIntroductionHandler); + } + + private void checkDevIntroductionInfo(final String deviceModelName, final boolean isOnlineAction) { + + mView.get().showProgressDialog(); + LCBusinessHandler checkDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + DeviceIntroductionInfo deviceIntroductionInfo = null; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + deviceIntroductionInfo = (DeviceIntroductionInfo) msg.obj; + } + if (deviceIntroductionInfo == null) { //表示需要更新 + getDevIntroductionInfoSync(deviceModelName, isOnlineAction); + } else { + dispatchIntroductionResult(isOnlineAction); + } + } + }; + DeviceAddModel.newInstance().checkDevIntroductionInfo(deviceModelName, checkDevIntroductionHandler); + } + + private void dispatchIntroductionResult(boolean isOnlineAction) { + mView.get().cancelProgressDialog(); + if(isOnlineAction){ + gotoPage(); + }else { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CONFIG_PAGE_NAVIGATION_ACTION)); + } + } + + //扫描出的二维码是否有效 + @Override + public boolean isSnInValid(String sn) { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { + return (sn.length() == 0 + || sn.getBytes().length > 64); + } else { + return TextUtils.isEmpty(sn); + } + } + + @Override + public boolean isScCodeInValid(String scCode) { + return false; + } + + + @Override + public boolean isManualInputPage() { + return false; + } + + protected void updateDeviceAddInfo(final String deviceSn, final String model, String regCode, String nc, String sc, String imeiCode) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setDeviceSn(deviceSn); + deviceAddInfo.setDeviceCodeModel(model); + deviceAddInfo.setDeviceModel(model); + deviceAddInfo.setRegCode(regCode); + deviceAddInfo.setSc(sc); + deviceAddInfo.setNc(nc); // 将16进制的字符串转换为数字 + // 支持SC码的设备,使用SC码作为设备密码 + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + deviceAddInfo.setDevicePwd(sc); + } + deviceAddInfo.setImeiCode(imeiCode); + } + + /** + * 处理服务返回的设备信息 + */ + public void dispatchResult() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (!deviceAddInfo.isSupport()) { + mView.get().goNotSupportBindTipPage(); + }else if (DeviceAddInfo.BindStatus.bindByMe.name().equals(deviceAddInfo.getBindStatus())) { //设备被当前帐户绑定 + mView.get().showToastInfo(R.string.add_device_device_bind_by_yourself); + } else if (DeviceAddInfo.BindStatus.bindByOther.name().equals(deviceAddInfo.getBindStatus())) { //设备被其他帐户绑定 + mView.get().goOtherUserBindTipPage(); + } else if (DeviceAddInfo.DeviceType.ap.name().equals(deviceAddInfo.getType())) { //配件 + checkDevIntroductionInfo(deviceAddInfo.getDeviceModel(),false); + } else { // 设备 + if (isManualInputPage() // 若二维码中无sc码处理成与ios一致 + && deviceAddInfo.hasAbility(DeviceAbility.SCCode) && (deviceAddInfo.getSc() == null || deviceAddInfo.getSc().length() != 8)) { // 已上平台有sc码能力但sc码输入错误 + mView.get().showToastInfo(R.string.add_device_input_corrent_sc_tip); + } else if (!deviceAddInfo.isDeviceInServer()) { //设备未在平台上注册 + //走设备离线添加流程 + deviceOfflineAction(); + } else if (DeviceAddInfo.Status.offline.name().equals(deviceAddInfo.getStatus())) { //设备离线 + deviceOfflineAction(); + } else if (DeviceAddInfo.Status.online.name().equals(deviceAddInfo.getStatus()) + || DeviceAddInfo.Status.sleep.name().equals(deviceAddInfo.getStatus()) + || DeviceAddInfo.Status.upgrading.name().equals(deviceAddInfo.getStatus())) { //设备在线/休眠/升级中 + deviceOnlineAction(); + } + } + + if(isManualInputPage()) { + deviceAddInfo.setStartTime(System.currentTimeMillis()); + } + } + + /** + *

    + * 获取设备信息失败,或者设备离线状态下,需要对结果进行处理 + *

    + */ + private void deviceOfflineAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (isDeviceTypeBox(deviceAddInfo.getDeviceCodeModel())) {// 如果是乐盒设备,直接提示设备不在线 + mView.get().showToastInfo(R.string.add_device_box_is_offline); + } else { + if ((!TextUtils.isEmpty(deviceAddInfo.getDeviceCodeModel()) + || !TextUtils.isEmpty(deviceAddInfo.getDeviceModel()))) { //扫码信息中存在设备类型 + String deviceModel = deviceAddInfo.getDeviceModel(); + if (TextUtils.isEmpty(deviceModel)) { + deviceModel = deviceAddInfo.getDeviceCodeModel(); + } + checkDevIntroductionInfo(deviceModel,false); + } else { + mView.get().goTypeChoosePage(); //设备选择 + } + } + } + + /** + *

    + * 获取到设备信息,并且设备在线,对结果进行处理 + *

    + */ + private void deviceOnlineAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (isDeviceTypeBox(deviceAddInfo.getDeviceCodeModel())) { + // 盒子,不支持 + mView.get().showToastInfo(R.string.add_device_not_support_to_bind); + return; + } else {// 其他设备 + if (!TextUtils.isEmpty(deviceAddInfo.getDeviceCodeModel()) + || !TextUtils.isEmpty(deviceAddInfo.getDeviceModel())) { //扫码信息中存在设备类型 + String deviceModel = deviceAddInfo.getDeviceModel(); + if (TextUtils.isEmpty(deviceModel)) { + deviceModel = deviceAddInfo.getDeviceCodeModel(); + } + checkDevIntroductionInfo(deviceModel,true); + } else { + gotoPage(); + } + } + } + + private void gotoPage() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.ONLINE); + + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.NBIOT.name())) { //NB配网 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.NBIOT); + if(TextUtils.isEmpty(deviceAddInfo.getImeiCode())){ + mView.get().goIMEIInputPage(); //NB配网需要输入IMEI号 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + }else if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + mView.get().goCloudConnectPage(); + } else { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { // 海外 + mView.get().goDeviceLoginPage(); + } else { + if (deviceAddInfo.hasAbility(DeviceAbility.Auth)) { + if (TextUtils.isEmpty(deviceAddInfo.getDevicePwd())) { + mView.get().goDeviceLoginPage();//输入设备密码 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + } else if (deviceAddInfo.hasAbility(DeviceAbility.RegCode)) { + if (TextUtils.isEmpty(deviceAddInfo.getRegCode())) { + mView.get().goSecCodePage();//输入安全码 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + } + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ErrorTipPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ErrorTipPresenter.java new file mode 100644 index 0000000..8a4065c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ErrorTipPresenter.java @@ -0,0 +1,392 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.support.v4.app.FragmentTransaction; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.ErrorTipConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.DeviceHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.p_errortip.TipAboutWifiPwdFragment; +import com.mm.android.deviceaddmodule.p_errortip.TipConnectFailFragment; +import com.mm.android.deviceaddmodule.p_errortip.TipNotSupport5GFragment; +import com.mm.android.deviceaddmodule.p_errortip.TipTimeoutFragment; +import com.mm.android.deviceaddmodule.p_errortip.TipUserBindFragment; +import com.mm.android.deviceaddmodule.p_errortip.TipWifiNameFragment; + +import java.lang.ref.WeakReference; + +public class ErrorTipPresenter implements ErrorTipConstract.Presenter { + WeakReference mView; + DeviceAddHelper.TimeoutDevTypeModel mCurTypeModel; + DeviceIntroductionInfo mTips; + int mErrorCode; + boolean isDoorbellType = false; + + public ErrorTipPresenter(ErrorTipConstract.View view) { + mView = new WeakReference<>(view); + mTips = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.COMMON_MODEL; + String errorType = ""; + if (mTips != null && mTips.getStrInfos() != null) { + errorType = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ERROR_TIPS_TYPE); + } + if ("Doorbell".equalsIgnoreCase(errorType) + || "Small Bell".equalsIgnoreCase(errorType)) {//doorbell类型不显示语音提示 + isDoorbellType = true; + } + } + + + @Override + public void dispatchError(int errorCode) { + mErrorCode = errorCode; + switch (errorCode) { + case DeviceAddHelper.ErrorCode.COMMON_ERROR_ABOUT_WIFI_PWD: + goAboutWifiPwdTipPage(); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G: + goNotSupport5GTipPage(); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_CONNECT_FAIL: + goConnectFailTipPage(); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_WIFI_NAME: + goWifiNameTipPage(); + break; + case DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND://不支持绑定的型号 + goNotSupportTipPage(); + break; + case DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER://被其他用户绑定 + case DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER: + goUserBindTipPage(); + break; + case DeviceAddHelper.ErrorCode.WIRED_WIRELESS_ERROR_CONFIG_TIMEOUT: //超时 + case DeviceAddHelper.ErrorCode.INIT_ERROR_SERCRITY_CHECK_TIMEOUT: + case DeviceAddHelper.ErrorCode.CLOUND_CONNECT_ERROR_CONNECT_TIMEOUT: + case DeviceAddHelper.ErrorCode.CLOUND_CONNECT_QUERY_STATUS_TIMEOUT: + case DeviceAddHelper.ErrorCode.AP_ERROR_PAIR_TIMEOUT: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ROTATE: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ALWAYS: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_FLASH: + case DeviceAddHelper.ErrorCode.INIT_ERROR_INIT_FAILED: + + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_IP_ERROR: + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_CODE_CONFLICT: + + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH: + + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_LOCKED: + goTimeoutTipPage(errorCode); + break; + default: //reset或其他提示 + dispatchReset(errorCode); + break; + } + } + + + @Override + public boolean isResetPage() { + if (mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_ABOUT_WIFI_PWD + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_5G + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_RESET + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_AP_RESET + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_RESET + || mErrorCode == DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER + || mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ALWAYS + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ROTATE + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_WIFI_NAME + || mErrorCode == DeviceAddHelper.ErrorCode.COMMON_ERROR_CONNECT_FAIL + || mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND) { + return true; + } + + return false; + } + + @Override + public boolean isUserBindTipPage() { + if (mErrorCode == DeviceAddHelper.ErrorCode.INPUT_SN_ERROR_BIND_BY_OTHER + || mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER + || mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND) { + return true; + } else { + return false; + } + } + + @Override + public boolean isUserBindTipPageByBind() { + if (mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_BIND_BY_OTHER + || mErrorCode == DeviceAddHelper.ErrorCode.DEVICE_BIND_ERROR_NOT_SUPPORT_TO_BIND) { + return true; + } else { + return false; + } + } + + private void dispatchReset(int errorcode) { + switch (errorcode) { + case DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_RESET: + String tipInfo = ""; + String tipImg = ""; + if (mTips != null) { + tipInfo = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_RESET_OPERATION_INTRODUCTION); + tipImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.WIFI_MODE_RESET_IMAGE); + if (TextUtils.isEmpty(tipInfo)) { + tipInfo = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESET_OPERATION_INTRODUCTION); + tipImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_RESET_IMAGE); + } + if (TextUtils.isEmpty(tipInfo)) { + tipInfo = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_RESET_OPERATION_INTRODUCTION); + tipImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_RESET_IMAGE); + } + } + mView.get().updateInfo(tipInfo, tipImg, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_RESET: + tipInfo = ""; + tipImg = ""; + if (mTips != null) { + tipInfo = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_RESET_OPERATION_INTRODUCTION); + tipImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_RESET_IMAGE); + } + mView.get().updateInfo(tipInfo, tipImg, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_NOT_SUPPORT_HUB_AP_RESET: + tipInfo = ""; + tipImg = ""; + if (mTips != null) { + tipInfo = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_ACCESSORY_MODE_RESET_OPERATION_INTRODUCTION); + tipImg = mTips.getImageInfos().get(DeviceAddHelper.OMSKey.HUB_ACCESSORY_MODE_RESET_IMAGE); + } + mView.get().updateInfo(tipInfo, tipImg, false); + break; + } + } + + //用户已绑定 + private void goUserBindTipPage() { + String bindAcount = DeviceAddModel.newInstance().getDeviceInfoCache().getBindAcount(); + String info = String.format(mView.get().getContextInfo().getString(R.string.add_device_device_bind_by_other), bindAcount); + mView.get().updateInfo(info, "drawable://" + R.drawable.adddevice_icon_device_default, false); + mView.get().hideHelp(); + TipUserBindFragment fragment = TipUserBindFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //不支持绑定的设备 + private void goNotSupportTipPage() { + String errorStr = mView.get().getContextInfo().getString(R.string.add_device_not_support_to_bind); + mView.get().updateInfo(errorStr, "drawable://" + R.drawable.adddevice_icon_device_default, false); + mView.get().hideHelp(); + TipUserBindFragment fragment = TipUserBindFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //关于WIFI密码 + private void goAboutWifiPwdTipPage() { + mView.get().updateInfo("", "drawable://" + R.drawable.adddevice_pic_serialnumber, true); + mView.get().hideTipTxt(); + TipAboutWifiPwdFragment fragment = TipAboutWifiPwdFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //关于软Ap连接失败 + private void goConnectFailTipPage() { + mView.get().updateInfo("", "drawable://" + R.drawable.adddevice_icon_hotspotexplain_fail, true); + mView.get().hideTipTxt(); + TipConnectFailFragment fragment = TipConnectFailFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //关于软Ap连接失败 + private void goWifiNameTipPage() { + mView.get().updateInfo("", "drawable://" + R.drawable.adddevice_icon_wifiexplain_choosewifi, true); + mView.get().hideTipTxt(); + TipWifiNameFragment fragment = TipWifiNameFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //不支持5G + private void goNotSupport5GTipPage() { + mView.get().updateInfo("", "drawable://" + R.drawable.adddevice_icon_wifiexplain, false); + mView.get().hideTipTxt(); + TipNotSupport5GFragment fragment = TipNotSupport5GFragment.newInstance(); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + //超时 + private void goTimeoutTipPage(int errorcode) { + if (mTips != null) { + String tipType = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ERROR_TIPS_TYPE); + + //国内需要根据配网模式获取不同的错误模式。海外目前仍取老字段,后面版本同步 + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE){ + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (deviceAddInfo == null){ + tipType = tipType; + }else if (DeviceAddInfo.DeviceType.ap.name().equals(deviceAddInfo.getType())){ + tipType = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ERROR_ACCESSORY_TIPS_TYPE); //配件 + }else if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.SoftAP.name())){ + tipType = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ERROR_SOFTAP_TIPS_TYPE); //软AP + }else { + tipType = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.ERROR_WIFI_TIPS_TYPE); //有线无线 + } + } + + + if (!TextUtils.isEmpty(tipType)) { + if (tipType.toLowerCase().contains("A Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.A_MODEL; + } else if (tipType.toLowerCase().contains("CK Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.CK_MODEL; + } else if (tipType.toLowerCase().contains("Accessory General".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.AP_MODEL; + } else if (tipType.toLowerCase().contains("IPC General".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.COMMON_MODEL; + } else if (tipType.toLowerCase().contains("Doorbell".toLowerCase()) + || tipType.toLowerCase().contains("Small Bell".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.DOORBELL_MODEL; + + isReportH1GTimeout(); + } else if (tipType.toLowerCase().contains("TP1 Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.TP1_MODEL; + } else if (tipType.toLowerCase().contains("TP1S Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.TP1S_MODEL; + } else if (tipType.toLowerCase().contains("G1 Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.G1_MODEL; + } else if (tipType.toLowerCase().contains("K5 Mode".toLowerCase())) { + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.K5_MODEL; + }else if(tipType.toLowerCase().contains("HUB1".toLowerCase()) || tipType.toLowerCase().contains("HUB2".toLowerCase())){ + } + } else { + + } + } + switch (errorcode) { + case DeviceAddHelper.ErrorCode.WIRED_WIRELESS_ERROR_CONFIG_TIMEOUT: + String img = "drawable://" + R.drawable.common_failhrlp_default; + dispathTypeModel(img); + break; + case DeviceAddHelper.ErrorCode.AP_ERROR_PAIR_TIMEOUT: + img = "drawable://" + R.drawable.common_failhrlp_default; + mCurTypeModel = DeviceAddHelper.TimeoutDevTypeModel.AP_MODEL; + dispathTypeModel(img); + break; + case DeviceAddHelper.ErrorCode.SOFTAP_ERROR_CONNECT_HOT_FAILED: + img = "drawable://" + R.drawable.common_failhrlp_default; + dispathTypeModel(img); + break; + case DeviceAddHelper.ErrorCode.CLOUND_CONNECT_QUERY_STATUS_TIMEOUT: + case DeviceAddHelper.ErrorCode.CLOUND_CONNECT_ERROR_CONNECT_TIMEOUT: + img = "drawable://" + R.drawable.adddevice_fail_configurationfailure; + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType())) {//软Ap + mView.get().updateInfo(R.string.add_device_connect_timeout, isDoorbellType ? 0 : R.string.add_device_operation_by_voice_tip, img, false); + } else { + mView.get().updateInfo(R.string.add_device_config_failed, img, false); + } + break; + case DeviceAddHelper.ErrorCode.INIT_ERROR_SERCRITY_CHECK_TIMEOUT: + img = "drawable://" + R.drawable.adddevice_fail_undetectable; + mView.get().updateInfo(R.string.add_device_detect_safe_network_config_failed, img, false); + break; + case DeviceAddHelper.ErrorCode.INIT_ERROR_INIT_FAILED: + img = "drawable://" + R.drawable.adddevice_fail_undetectable; + mView.get().updateInfo(R.string.add_device_timeout_init_failed, img, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ALWAYS: + mView.get().updateInfo(R.string.add_device_red_light_always, R.string.add_device_disconnect_power_and_restart, "drawable://" + R.drawable.common_netsetting_power, true); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_ROTATE: + mView.get().updateInfo(R.string.add_device_red_light_rotate,R.string.add_device_disconnect_power_and_restart, "drawable://" + R.drawable.common_netsetting_power, true); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_RED_FLASH: + mView.get().updateInfo(R.string.add_device_red_light_twinkle,R.string.add_device_timeout_title_tip8, "drawable://" + R.drawable.adddevice_failhrlp_g1, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_BIND_MROE_THAN_TEN: + mView.get().updateInfo(R.string.add_device_commom_dev_more_than_ten_tip, "drawable://" + R.drawable.adddevice_fail_rest, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_MROE_THAN_TEN_TWICE: + mView.get().updateInfo(R.string.add_device_commom_dev_more_than_ten_twice_tip, "drawable://" + R.drawable.adddevice_fail_rest, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_IP_ERROR: + mView.get().updateInfo(R.string.add_device_commom_dev_ip_error_tip, "drawable://" + R.drawable.common_netsetting_power, false); + break; + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_CODE_CONFLICT: + mView.get().updateInfo(R.string.add_device_commom_dev_sn_code_conflict_tip, "drawable://" + R.drawable.adddevice_fail_configurationfailure, false); + break; + + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_LOCKED: + mView.get().updateInfo(R.string.mobile_common_bec_device_locked, "drawable://" + R.drawable.common_netsetting_power, true); + break; + + case DeviceAddHelper.ErrorCode.COMMON_ERROR_DEVICE_SN_OR_IMEI_NOT_MATCH: + mView.get().updateInfo(R.string.add_device_device_sn_or_imei_not_match, "drawable://" + R.drawable.adddevice_fail_configurationfailure, true); + break; + default: + break; + } + String devtypeModel = ""; + if (mCurTypeModel != null) { + devtypeModel = mCurTypeModel.name(); + } + TipTimeoutFragment fragment = TipTimeoutFragment.newInstance(errorcode, devtypeModel); + FragmentTransaction transaction = mView.get().getParent().getChildFragmentManager().beginTransaction(); + transaction.add(R.id.child_content, fragment); + transaction.commit(); + } + + private void dispathTypeModel(String img) { + if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.A_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout, R.string.add_device_operation_by_voice_or_light, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.CK_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout, R.string.add_device_operation_by_voice_or_light, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.COMMON_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout, R.string.add_device_timeout_title_tip7, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.DOORBELL_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout, isDoorbellType ? 0 : R.string.add_device_operation_by_voice_tip, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.AP_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.TP1_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout,R.string.add_device_operation_by_voice_or_light, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.TP1S_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout,R.string.add_device_operation_by_voice_or_light, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.G1_MODEL)) { + img = "drawable://" + R.drawable.adddevice_failhrlp_g1; + mView.get().updateInfo(R.string.add_device_connect_timeout,R.string.add_device_operation_by_voice_or_light, img, false); + } else if (mCurTypeModel.equals(DeviceAddHelper.TimeoutDevTypeModel.K5_MODEL)) { + mView.get().updateInfo(R.string.add_device_connect_timeout,R.string.add_device_operation_by_voice_tip, img, false); + } + } + + private boolean isReportH1GTimeout(){ + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if(deviceAddInfo != null && DeviceHelper.isH1G(deviceAddInfo.getModelName())){ + return true; + } + + return false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/GatewayListPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/GatewayListPresenter.java new file mode 100644 index 0000000..1e8b17d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/GatewayListPresenter.java @@ -0,0 +1,103 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.GatewayListConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorCode; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.device.DHDevice; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +public class GatewayListPresenter implements GatewayListConstract.Presenter { + WeakReference mView; + List mGatewayData; + int mSelectedPos=-1; + + public GatewayListPresenter(GatewayListConstract.View view) { + mView = new WeakReference<>(view); + mGatewayData = new ArrayList<>(); + initApView(); + } + + private void initApView() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + mView.get().setApSn(deviceAddInfo.getDeviceSn()); + DeviceIntroductionInfo deviceIntroductionInfo = deviceAddInfo.getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String img = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.ACCESSORY_MODE_FINISH_DEVICE_IMAGE); + mView.get().setApImg(img); + } + } + + @Override + public List getGatewayData(boolean selectedGateway) { + //TODO 网关列表选择不能依赖本地缓存,需要开新接口从服务拉数据 + return mGatewayData; + } + + @Override + public int gatewaySize() { + return mGatewayData.size(); + } + + @Override + public void dispatchCurSelect(int curPos) { + if (curPos >= 0 && curPos < mGatewayData.size()) { + DHDevice device = mGatewayData.get(curPos); + DeviceAddInfo.GatewayInfo gatewayInfo = new DeviceAddInfo.GatewayInfo(); + gatewayInfo.setSn(device.getDeviceId()); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setGatewayInfo(gatewayInfo); + String deviceId = deviceAddInfo.getGatewayInfo().getSn(); + String apId = deviceAddInfo.getDeviceSn(); + String apType = deviceAddInfo.getCatalog(); + String apModel = deviceAddInfo.getDeviceModel(); + pairSync(deviceId, apId, apType, apModel); + } else { + mView.get().goTipPage(); + } + } + + @Override + public int getSelectedpos() { + return mSelectedPos; + } + + private void pairSync(final String deviceId, final String apId, String apType, String apModel) { + mView.get().showProgressDialog(); + LCBusinessHandler pairHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + mView.get().cancelProgressDialog(); + if (HandleMessageCode.HMC_SUCCESS == msg.what) { + boolean isSucceed = (boolean) msg.obj; + if (isSucceed) { + mView.get().goTipPage(); + return; + } + } + apPairFailed(msg.what); + } + } + }; + DeviceAddModel.newInstance().addApDevice(deviceId, apId, apType, apModel, pairHandler); + } + + private void apPairFailed(int errorCode) { + if(errorCode == BusinessErrorCode.BEC_DEVICE_ADD_AP_UPPER_LIMIT){ + mView.get().showToastInfo(R.string.add_device_add_ap_upper_limit); + } else { + mView.get().showToastInfo(R.string.add_device_config_failed); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HiddenWifiPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HiddenWifiPresenter.java new file mode 100644 index 0000000..eb35b0d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HiddenWifiPresenter.java @@ -0,0 +1,104 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.HiddenWifiPwdConstract; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class HiddenWifiPresenter implements HiddenWifiPwdConstract.Presenter { + + WeakReference mView; + DHWifiUtil mDHWifiUtil; + WlanInfo mCurWlanInfo; + protected String mDeviceId; + private boolean mIsNotNeedLogin; + protected boolean isSupport5G = false; + + public HiddenWifiPresenter(HiddenWifiPwdConstract.View view) { + mView = new WeakReference<>(view); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + mCurWlanInfo = new WlanInfo(); + + String wifiMode = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiTransferMode(); + if (!TextUtils.isEmpty(wifiMode)) { + isSupport5G = wifiMode.toUpperCase().contains("5GHZ"); + } + } + + @Override + public boolean isDevSupport5G() { + return isSupport5G; + } + + + @Override + public void setIsNotNeedLogin(boolean isNotNeedLogin){ + mIsNotNeedLogin = isNotNeedLogin; + } + + @Override + public String getCurWifiName() { + return mCurWlanInfo.getWlanSSID(); + } + + @Override + public void updateWifiCache() { + DeviceAddInfo.WifiInfo wifiInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiInfo(); + wifiInfo.setSsid(getCurWifiName()); + wifiInfo.setPwd(mView.get().getWifiPwd()); + + } + + + @Override + public void connectWifi() { + mCurWlanInfo.setWlanSSID(mView.get().getWifiSSID()); + mView.get().showProgressDialog(); + updateWifiCache();//更新wifi信息到缓存 + String gatwayip = mDHWifiUtil.getGatewayIp(); + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String pwd = deviceAddInfo.getDevicePwd(); + String wifiPwd = deviceAddInfo.getWifiInfo().getPwd(); + + LCBusinessHandler connectWifiHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + dispatchConnectResult(msg); + } + } else { + mView.get().showToastInfo(R.string.device_disturb_state_failed); + } + } + }; + + if(mIsNotNeedLogin) { + mCurWlanInfo.setWlanEncry(12); + DeviceAddModel.newInstance().connectWifi4Sc(gatwayip, mCurWlanInfo, wifiPwd, connectWifiHandler); + } else { + DeviceAddModel.newInstance().connectWifi4Hidden(gatwayip, pwd, mCurWlanInfo, wifiPwd, connectWifiHandler); + } + } + + private void dispatchConnectResult(Message message) { + mView.get().cancelProgressDialog(); + //恢复网络 + DeviceAddHelper.clearNetWork(); + DeviceAddHelper.connectPreviousWifi(); + mView.get().goCloudConnectPage(); + + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HubApGuide1Presenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HubApGuide1Presenter.java new file mode 100644 index 0000000..d62c3b2 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/HubApGuide1Presenter.java @@ -0,0 +1,72 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; + +import com.mm.android.deviceaddmodule.contract.HubApGuide1Constract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class HubApGuide1Presenter implements HubApGuide1Constract.Presenter { + + WeakReference mView; + + public HubApGuide1Presenter(HubApGuide1Constract.View view) { + mView = new WeakReference<>(view); + } + + + private void getDevIntroductionInfoSync(String deviceModel) { + LCBusinessHandler getDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + dispatchIntroductionResult(); + } + }; + DeviceAddModel.newInstance().getDevIntroductionInfo(deviceModel, getDevIntroductionHandler); + } + + @Override + public void checkDevIntroductionInfo(final String deviceModelName) { + mView.get().showProgressDialog(); + LCBusinessHandler checkDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + DeviceIntroductionInfo deviceIntroductionInfo = null; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + deviceIntroductionInfo = (DeviceIntroductionInfo) msg.obj; + } + if (deviceIntroductionInfo == null) { //表示需要更新 + getDevIntroductionInfoSync(deviceModelName); + } else { + dispatchIntroductionResult(); + } + } + }; + DeviceAddModel.newInstance().checkDevIntroductionInfo(deviceModelName, checkDevIntroductionHandler); + } + + private void dispatchIntroductionResult() { + mView.get().cancelProgressDialog(); + mView.get().showInfoView(); + DeviceIntroductionInfo deviceIntroductionInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + if (deviceIntroductionInfo != null) { + String tipTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_PAIR_OPERATION_INTRODUCTION); + String tipImg = deviceIntroductionInfo.getImageInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_PAIR_STATUS_IMAGE); + String helpTxt = deviceIntroductionInfo.getStrInfos().get(DeviceAddHelper.OMSKey.HUB_MODE_RESET_GUIDE_INTRODUCTION); + mView.get().updateTip(tipImg, tipTxt, helpTxt); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/InitPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/InitPresenter.java new file mode 100644 index 0000000..6eee1a9 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/InitPresenter.java @@ -0,0 +1,288 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Handler; +import android.os.Message; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.dahua.mobile.utility.music.DHMusicPlayer; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.contract.InitContract; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PasswordCheckRules; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +import static com.mm.android.deviceaddmodule.helper.Utils4AddDevice.checkDeviceVersion; +import static com.mm.android.deviceaddmodule.helper.Utils4AddDevice.checkEffectiveIP; + +public class InitPresenter implements InitContract.Presenter, SearchDeviceManager.ISearchDeviceListener { + private static final String TAG = "InitPresenter"; + private int SEARCH_DEVICE_WAIT_TIME = 5 * 1000; // 搜索设备时间 + private int NEW_V_SEARCH_DEVICE_WAIT_TIME = 10 * 1000; // 搜索设备时间 + private static final int SEARCH_SUCCESS = 1; //搜索成功 + private static final int SEARCH_FAILED = 2; //搜索不到设备 + + WeakReference mView; + DHMusicPlayer mDHMusicPlayer; + DEVICE_NET_INFO_EX mDeviceNetInfoEx; + String mDeviceSn; + boolean isBeginInit; //是否开始初始化,即是否点击初始化按钮 + private boolean isDeviceSearching = false; //是否在开始搜索设备 + boolean mIsDeviceNewVersion; //新程序设备,直接走单播 + boolean mIsHasInitbyMulicast = false; //是否已经尝试过组播 + boolean isSoftApAddType = false; //当前软AP添加设备(门铃、铃铛等)版本,不管新老设备,IP会一直无效,故软AP添加初始化走组播+单播流程,待后续设备程序更改后再进行优化。 + boolean mIsHasInitbyIp = false; //是否已经尝试过单播 + + public InitPresenter(InitContract.View view) { + mView = new WeakReference<>(view); + mDHMusicPlayer = new DHMusicPlayer(mView.get().getContextInfo(), true, mView.get().getMusicRes()); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType())) { + isSoftApAddType = true; + } + } + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (mView.get() != null && + mView.get().isViewActive()) { + switch (msg.what) { + case SEARCH_SUCCESS: + searchDevicesSuccess(); + break; + case SEARCH_FAILED: + stopSearchDevice(); + if (isBeginInit) { + errorAction(); + } + break; + + default: + break; + } + } + } + }; + + private void searchDevicesSuccess() { + stopSearchDevice(); + if (mDeviceNetInfoEx == null) { + return; + } + if (isOnlyNeedUnicast() || mIsHasInitbyMulicast) { + if (isBeginInit) { + LogUtil.debugLog(TAG, "searched device: initDevByIp"); + initDevAccountByIp(mDeviceNetInfoEx, mView.get().getInitPwd()); + } + } else { + LogUtil.debugLog(TAG, "searched device: initDev"); + startDevInit(); + } + } + + private Runnable mTimeOutRunnable = new Runnable() { + + @Override + public void run() { + mHandler.sendEmptyMessage(SEARCH_FAILED); + } + }; + + @Override + public void checkDevice() { + if (isOnlyNeedUnicast()) {//新设备,需检测ip是否有效 + //检测设备Ip是否有效,无效需要重新搜索设备 + boolean isValidIp = checkEffectiveIP(mDeviceNetInfoEx); + if (!isValidIp) { + startSearchDevice(); + } + } + + } + + private void startSearchDevice() { + isDeviceSearching = true; + SearchDeviceManager searchDeviceManager = SearchDeviceManager.getInstance(); + searchDeviceManager.registerListener(this); + searchDeviceManager.startSearch(); + mHandler.postDelayed(mTimeOutRunnable, isOnlyNeedUnicast() ? NEW_V_SEARCH_DEVICE_WAIT_TIME : SEARCH_DEVICE_WAIT_TIME); + } + + private void stopSearchDevice() { + isDeviceSearching = false; + SearchDeviceManager.getInstance().unRegisterListener(this); + mHandler.removeCallbacks(mTimeOutRunnable); + } + + private void errorAction() { + mView.get().cancelProgressDialog(); + mView.get().goErrorTipPage(); + } + + private void initDevAccountByIp(DEVICE_NET_INFO_EX devicNetInfo, final String password) { + mView.get().showProgressDialog(); + LCBusinessHandler initDevHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + isBeginInit = false; + mIsHasInitbyIp = true; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + boolean inited = (boolean) msg.obj; + if (inited) { + dispatchInitResult(); + } else { + // 初始化失败页面 + errorAction(); + } + } + } + }; + DeviceAddModel.newInstance().initDevByIp(devicNetInfo, password, initDevHandler); + } + + @Override + public void startDevInit() { + mView.get().showProgressDialog(); + LCBusinessHandler initDevHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + boolean inited = (boolean) msg.obj; + if (inited) { + dispatchInitResult(); + } else { + if(mIsHasInitbyIp) { + // 初始化失败页面 + errorAction(); + } else { + //组播失败,直接走单播 + DEVICE_NET_INFO_EX deviceNetInfoEx = SearchDeviceManager.getInstance().getDeviceNetInfo(mDeviceSn); + if (deviceNetInfoEx != null) { + mDeviceNetInfoEx = deviceNetInfoEx; + } + LogUtil.debugLog(TAG, "initDev failed,then try initDevByIp"); + initDevAccountByIp(mDeviceNetInfoEx, mView.get().getInitPwd()); + } + } + } + } + }; + DeviceAddModel.newInstance().initDev(mDeviceNetInfoEx, mView.get().getInitPwd(), initDevHandler); + } + + public void dispatchInitResult() { + mView.get().cancelProgressDialog(); + isBeginInit = false; + DeviceAddInfo.DeviceAddType deviceAddType = DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType(); + DeviceAddModel.newInstance().getDeviceInfoCache().setDevicePwd(mView.get().getInitPwd()); + + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddType)) { + mView.get().goSoftAPWifiListPage(); + } else { + // 初始化成功 开始接入乐橙云 + mView.get().goConnectCloudPage(); + } + } + + + @Override + public void setDeviceEX(DEVICE_NET_INFO_EX deviceEX) { + mDeviceNetInfoEx = deviceEX; + mIsDeviceNewVersion = checkDeviceVersion(mDeviceNetInfoEx); + } + + @Override + public void playTipSound() { + if (ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA)//海外版本不提示语音 + mDHMusicPlayer.playRing(false); + } + + @Override + public void startDevInitByIp() { + isBeginInit = true; + LogUtil.debugLog(TAG, "click init button..."); + if (isOnlyNeedUnicast()) { + boolean isEffectiveIp = checkEffectiveIP(mDeviceNetInfoEx); + if (isDeviceSearching) {//正在搜索 + LogUtil.debugLog(TAG, "please be wait, searching device ip now..."); + mView.get().showProgressDialog(); + } else if(isEffectiveIp) {//设备ip有效,不需重新搜索 + LogUtil.debugLog(TAG, "ip is effective: initDevByIp: " + new String(mDeviceNetInfoEx.szIP).trim()); + initDevAccountByIp(mDeviceNetInfoEx, mView.get().getInitPwd()); + } else { + LogUtil.debugLog(TAG, "ip is not effective: initDev"); + startDevInit(); + } + } else { + LogUtil.debugLog(TAG, "old device or DHCP is closed: initDev"); + startDevInit(); + } + } + + @Override + public boolean isPwdValid() { + int res = PasswordCheckRules.checkPasswordValidation(mView.get().getInitPwd(), mView.get().getInitPwd(), mView.get().getContextInfo()); + if (res == PasswordCheckRules.PASSWORD_NOT_MATCH) { + // mView.get().showToastInfo(R.string.add_device_pwd_rule_tip1); + return false; + } else if (res == PasswordCheckRules.PASSWORD_INVALID + || res == PasswordCheckRules.PASSWORD_NOT_SAFY + || res == PasswordCheckRules.PASSWORD_INVALID_LENGTH + || res == PasswordCheckRules.PASSWORD_INVALID_COMBINATION) { + mView.get().showToastInfo(R.string.mobile_common_password_too_simple); + return false; + } + + return true; + } + + + @Override + public void recyle() { + mDHMusicPlayer.release(); + stopSearchDevice(); + } + + @Override + public void onDeviceSearched(String sncode, DEVICE_NET_INFO_EX device_net_info_ex) { + if (device_net_info_ex == null) { + return; + } + String szSerialNo = new String(device_net_info_ex.szSerialNo).trim(); + if (isOnlyNeedUnicast()) { + if (szSerialNo.equalsIgnoreCase(mDeviceSn)) { + boolean isEffectiveIp = checkEffectiveIP(device_net_info_ex); + mDeviceNetInfoEx = device_net_info_ex; + if (isEffectiveIp) { + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } + } + } else { + if (device_net_info_ex != null && szSerialNo.equalsIgnoreCase(mDeviceSn) && device_net_info_ex.iIPVersion == 4) { + mDeviceNetInfoEx = device_net_info_ex; + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } + } + } + + //是否只需要进行单播 + private boolean isOnlyNeedUnicast() { + return mIsDeviceNewVersion && !isSoftApAddType; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ManualInputPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ManualInputPresenter.java new file mode 100644 index 0000000..b07c4b7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ManualInputPresenter.java @@ -0,0 +1,43 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.contract.ManualInputConstract; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +public class ManualInputPresenter extends ScanPresenter { + public ManualInputPresenter(ManualInputConstract.View view){ + super(view); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setManualInput(true); + } + + @Override + public ScanResult parseScanStr(String scanStr, String sc) { + return super.parseScanStr(scanStr, sc); + } + + @Override + public boolean isManualInputPage() { + return true; + } + + @Override + public boolean isSnInValid(String sn) { + if(TextUtils.isEmpty(sn)){ + return true; + }else{ + if(sn.length()<10){ + return true; + } + } + return false; + } + + @Override + public boolean isScCodeInValid(String scCode) { + return false; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/OfflineConfigPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/OfflineConfigPresenter.java new file mode 100644 index 0000000..a62e2b5 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/OfflineConfigPresenter.java @@ -0,0 +1,96 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; + +import com.mm.android.deviceaddmodule.contract.OfflineConfigConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +public class OfflineConfigPresenter implements OfflineConfigConstract.Presenter { + WeakReference mView; + + public OfflineConfigPresenter(OfflineConfigConstract.View view) { + mView = new WeakReference<>(view); + } + + @Override + public void resetCache() { + // 离线配网时需要将设备密码带入,故不适用clearCache方法清理缓存 + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.getWifiInfo().setPwd(null); + deviceAddInfo.getWifiInfo().setSsid(null); + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.WLAN); + } + + @Override + public void getDeviceInfo(String deviceSn, final String deviceModelName, String imeiCode) { + mView.get().showProgressDialog(); + LCBusinessHandler getDeviceHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + checkDevIntroductionInfo(deviceModelName); + }else { + mView.get().cancelProgressDialog(); + mView.get().showToastInfo( BusinessErrorTip.getErrorTip(msg)); + mView.get().onGetDeviceInfoError(); + } + } + }; + DeviceAddModel.newInstance().getDeviceInfo(deviceSn, "", deviceModelName, imeiCode, getDeviceHandler); + } + + private void checkDevIntroductionInfo(final String deviceModelName) { + LCBusinessHandler checkDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + DeviceIntroductionInfo deviceIntroductionInfo = null; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + deviceIntroductionInfo = (DeviceIntroductionInfo) msg.obj; + } + if (deviceIntroductionInfo == null) { //表示需要更新 + getDevIntroductionInfoSync(deviceModelName); + } else { + dispatchIntroctionResult(); + } + } + }; + DeviceAddModel.newInstance().checkDevIntroductionInfo(deviceModelName, checkDevIntroductionHandler); + } + + private void getDevIntroductionInfoSync(String deviceModel) { + LCBusinessHandler getDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + dispatchIntroctionResult(); + } + }; + DeviceAddModel.newInstance().getDevIntroductionInfo(deviceModel, getDevIntroductionHandler); + } + + private void dispatchIntroctionResult() { + mView.get().cancelProgressDialog(); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CONFIG_PAGE_NAVIGATION_ACTION)); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ScanPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ScanPresenter.java new file mode 100644 index 0000000..4ed8824 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/ScanPresenter.java @@ -0,0 +1,313 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.music.DHMusicPlayer; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.ScanContract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResult; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ScanResultFactory; +import com.mm.android.deviceaddmodule.mobilecommon.annotation.DeviceAbility; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +import static com.mm.android.deviceaddmodule.helper.Utils4AddDevice.isDeviceTypeBox; + +public class ScanPresenter implements ScanContract.Presenter { + WeakReference mView; + DHMusicPlayer mDHMusicPlayer; + + public ScanPresenter(ScanContract.View view) { + mView = new WeakReference<>(view); + mDHMusicPlayer = new DHMusicPlayer(mView.get().getContextInfo(), false, true, R.raw.beep); + mDHMusicPlayer.setSupportVibrate(true); + } + + @Override + public ScanResult parseScanStr(String scanStr, String sc) { + if (!isManualInputPage()) { + mDHMusicPlayer.playRing(false); + } + ScanResult scanResult = ScanResultFactory.scanResult(scanStr.trim()); + LogUtil.debugLog("ScanPresenter", "scanResult : " + scanResult); + // 手动输入的安全验证码 + if (!TextUtils.isEmpty(sc)) { + scanResult.setSc(sc); + } + if (!TextUtils.isEmpty(scanResult.getSn())) { + updateDeviceAddInfo(scanResult.getSn().trim(), scanResult.getMode(), scanResult.getRegcode(), scanResult.getNc(), scanResult.getSc(), scanResult.getImeiCode()); + } + return scanResult; + } + + /** + * 根据扫码的数据去平台查询设备信息 + * + * @param deviceSn + * @param deviceCodeModel + */ + @Override + public void getDeviceInfo(final String deviceSn, final String deviceCodeModel) { + if (isSnInValid(deviceSn)) { + mView.get().showToastInfo(R.string.add_device_scan_lechange_device_qr_code); + } else { + mView.get().showProgressDialog(); + LCBusinessHandler getDeviceHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + + } else { + String errorDesp = ((BusinessException) msg.obj).errorDescription; + if (errorDesp.contains("DV1037")) { + mView.get().showToastInfo(R.string.add_device_device_sn_or_imei_not_match); + return; + } + if (errorDesp.contains("DV1003")) { + mView.get().goMainbind(deviceSn, "", "ysz123456"); + mView.get().showToastInfo("添加成功"); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + return; + } + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + return; + } + dispatchResult(); + } + }; + DeviceAddModel.newInstance().getDeviceInfo(deviceSn, deviceCodeModel, "", "", getDeviceHandler); + } + } + + private void getDevIntroductionInfoSync(String deviceModel, final boolean isOnlineAction) { + LCBusinessHandler getDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + dispatchIntroductionResult(isOnlineAction); + } + }; + DeviceAddModel.newInstance().getDevIntroductionInfo(deviceModel, getDevIntroductionHandler); + } + + private void checkDevIntroductionInfo(final String deviceModelName, final boolean isOnlineAction) { + + mView.get().showProgressDialog(); + LCBusinessHandler checkDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + DeviceIntroductionInfo deviceIntroductionInfo = null; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + deviceIntroductionInfo = (DeviceIntroductionInfo) msg.obj; + } + if (deviceIntroductionInfo == null) { //表示需要更新 + getDevIntroductionInfoSync(deviceModelName, isOnlineAction); + } else { + dispatchIntroductionResult(isOnlineAction); + } + } + }; + DeviceAddModel.newInstance().checkDevIntroductionInfo(deviceModelName, checkDevIntroductionHandler); + } + + private void dispatchIntroductionResult(boolean isOnlineAction) { + mView.get().cancelProgressDialog(); + if (isOnlineAction) { + gotoPage(); + } else { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CONFIG_PAGE_NAVIGATION_ACTION)); + } + } + + //扫描出的二维码是否有效 + @Override + public boolean isSnInValid(String sn) { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { + return (sn.length() == 0 + || sn.getBytes().length > 64); + } else { + return TextUtils.isEmpty(sn); + } + } + + @Override + public boolean isScCodeInValid(String scCode) { + return false; + } + + + @Override + public void recyle() { + if (mDHMusicPlayer != null) { + mDHMusicPlayer.release(); + } + } + + @Override + public void resetCache() { + DeviceAddModel.newInstance().getDeviceInfoCache().clearCache(); + } + + @Override + public boolean isManualInputPage() { + return false; + } + + protected void updateDeviceAddInfo(final String deviceSn, final String model, String regCode, String nc, String sc, String imeiCode) { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setDeviceSn(deviceSn); + deviceAddInfo.setDeviceCodeModel(model); + deviceAddInfo.setDeviceModel(model); + deviceAddInfo.setRegCode(regCode); + deviceAddInfo.setSc(sc); + deviceAddInfo.setNc(nc); // 将16进制的字符串转换为数字 + // 支持SC码的设备,使用SC码作为设备密码 + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + deviceAddInfo.setDevicePwd(sc); + } + deviceAddInfo.setImeiCode(imeiCode); + } + + /** + * 处理服务返回的设备信息 + */ + private void dispatchResult() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (!deviceAddInfo.isSupport()) { + mView.get().goNotSupportBindTipPage(); + } else if (DeviceAddInfo.BindStatus.bindByMe.name().equals(deviceAddInfo.getBindStatus())) { //设备被当前帐户绑定 + mView.get().showToastInfo(R.string.add_device_device_bind_by_yourself); + } else if (DeviceAddInfo.BindStatus.bindByOther.name().equals(deviceAddInfo.getBindStatus())) { //设备被其他帐户绑定 + mView.get().goOtherUserBindTipPage(); + } else if (DeviceAddInfo.DeviceType.ap.name().equals(deviceAddInfo.getType())) { //配件 + checkDevIntroductionInfo(deviceAddInfo.getDeviceModel(), false); + } else { // 设备 + if (isManualInputPage() // 若二维码中无sc码处理成与ios一致 + && deviceAddInfo.hasAbility(DeviceAbility.SCCode) && (deviceAddInfo.getSc() == null || deviceAddInfo.getSc().length() != 8)) { // 已上平台有sc码能力但sc码输入错误 + mView.get().showToastInfo(R.string.add_device_input_corrent_sc_tip); + } else if (!deviceAddInfo.isDeviceInServer()) { //设备未在平台上注册 + //走设备离线添加流程 + deviceOfflineAction(); + } else if (DeviceAddInfo.Status.offline.name().equals(deviceAddInfo.getStatus())) { //设备离线 + deviceOfflineAction(); + } else if (DeviceAddInfo.Status.online.name().equals(deviceAddInfo.getStatus()) + || DeviceAddInfo.Status.sleep.name().equals(deviceAddInfo.getStatus()) + || DeviceAddInfo.Status.upgrading.name().equals(deviceAddInfo.getStatus())) { //设备在线/休眠/升级中 + deviceOnlineAction(); + } + } + + if (isManualInputPage()) { + deviceAddInfo.setStartTime(System.currentTimeMillis()); + } + } + + /** + *

    + * 获取设备信息失败,或者设备离线状态下,需要对结果进行处理 + *

    + */ + private void deviceOfflineAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (isDeviceTypeBox(deviceAddInfo.getDeviceCodeModel())) {// 如果是乐盒设备,直接提示设备不在线 + mView.get().showToastInfo(R.string.add_device_box_is_offline); + } else { + if ((!TextUtils.isEmpty(deviceAddInfo.getDeviceCodeModel()) + || !TextUtils.isEmpty(deviceAddInfo.getDeviceModel()))) { //扫码信息中存在设备类型 + String deviceModel = deviceAddInfo.getDeviceModel(); + if (TextUtils.isEmpty(deviceModel)) { + deviceModel = deviceAddInfo.getDeviceCodeModel(); + } + checkDevIntroductionInfo(deviceModel, false); + } else { + mView.get().goTypeChoosePage(); //设备选择 + } + } + } + + /** + *

    + * 获取到设备信息,并且设备在线,对结果进行处理 + *

    + */ + private void deviceOnlineAction() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if (isDeviceTypeBox(deviceAddInfo.getDeviceCodeModel())) { + // 盒子,不支持 + mView.get().showToastInfo(R.string.add_device_not_support_to_bind); + return; + } else {// 其他设备 + if (!TextUtils.isEmpty(deviceAddInfo.getDeviceCodeModel()) + || !TextUtils.isEmpty(deviceAddInfo.getDeviceModel())) { //扫码信息中存在设备类型 + String deviceModel = deviceAddInfo.getDeviceModel(); + if (TextUtils.isEmpty(deviceModel)) { + deviceModel = deviceAddInfo.getDeviceCodeModel(); + } + checkDevIntroductionInfo(deviceModel, true); + } else { + gotoPage(); + } + } + } + + private void gotoPage() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.ONLINE); + + if (deviceAddInfo.getConfigMode().contains(DeviceAddInfo.ConfigMode.NBIOT.name())) { //NB配网 + deviceAddInfo.setCurDeviceAddType(DeviceAddInfo.DeviceAddType.NBIOT); + if (TextUtils.isEmpty(deviceAddInfo.getImeiCode())) { + mView.get().goIMEIInputPage(); //NB配网需要输入IMEI号 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + } else if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + mView.get().goCloudConnectPage(); + } else { + if (ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA) { // 海外 + mView.get().goDeviceLoginPage(); + } else { + if (deviceAddInfo.hasAbility(DeviceAbility.Auth)) { + if (TextUtils.isEmpty(deviceAddInfo.getDevicePwd())) { + mView.get().goDeviceLoginPage();//输入设备密码 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + } else if (deviceAddInfo.hasAbility(DeviceAbility.RegCode)) { + if (TextUtils.isEmpty(deviceAddInfo.getRegCode())) { + mView.get().goSecCodePage();//输入安全码 + } else { + mView.get().goDeviceBindPage();//直接绑定 + } + } + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SecurityCheckPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SecurityCheckPresenter.java new file mode 100644 index 0000000..c18c6a8 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SecurityCheckPresenter.java @@ -0,0 +1,114 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.contract.SecurityCheckConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class SecurityCheckPresenter implements SecurityCheckConstract.Presenter, SearchDeviceManager.ISearchDeviceListener { + private static final int SEARCH_SUCCESS = 1; //搜索成功 + WeakReference mView; + String mDeviceSn; + DEVICE_NET_INFO_EX mDeviceNetInfoEx; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (mView.get() != null && + mView.get().isViewActive()) { + stopSearchDevice(); + switch (msg.what) { + case SEARCH_SUCCESS: + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + + if (DeviceAddHelper.isDeviceNeedInit(mDeviceNetInfoEx)) { + // 支持sc码的软ap,未初始化时,走netSDK不需要登陆的获取wifi列表和配网接口 + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo) && DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddInfo.getCurDeviceAddType())) { + mView.get().goSoftApWifiListPage(true); + } else { + mView.get().goInitPage(mDeviceNetInfoEx); + } + } else { + if (DeviceAddInfo.DeviceAddType.SOFTAP.equals(deviceAddInfo.getCurDeviceAddType())) { + String devPwd = DeviceAddModel.newInstance().getDeviceInfoCache().getDevicePwd(); + //不支持初始化的密码默认为admin(目前仅国内K5设备是不支持初始化,需要用admin登录) + if (ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA && !DeviceAddHelper.isDeviceSupportInit(mDeviceNetInfoEx)){ + devPwd = "admin"; + DeviceAddModel.newInstance().getDeviceInfoCache().setDevicePwd(devPwd); + } + if (TextUtils.isEmpty(devPwd)) { + mView.get().goDevLoginPage(); + } else { + mView.get().goSoftApWifiListPage(false); + } + } else { + mView.get().goCloudConnetPage(); + } + + } + break; + default: + break; + } + } + } + }; + + public SecurityCheckPresenter(SecurityCheckConstract.View view) { + mView = new WeakReference<>(view); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mDeviceNetInfoEx = SearchDeviceManager.getInstance().getDeviceNetInfo(mDeviceSn); + } + + @Override + public void checkDevice() { + startSearchDevice(); + if (mDeviceNetInfoEx == null + ||(mDeviceNetInfoEx!=null && Utils4AddDevice.checkDeviceVersion(mDeviceNetInfoEx) + &&!Utils4AddDevice.checkEffectiveIP(mDeviceNetInfoEx))) {//未搜索到设备或新设备且其IP无效,重新搜索 + startSearchDevice(); + } else { + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } + + } + + @Override + public void recyle() { + stopSearchDevice(); + } + + private void startSearchDevice() { + SearchDeviceManager searchDeviceManager = SearchDeviceManager.getInstance(); + searchDeviceManager.registerListener(this); + searchDeviceManager.startSearch(); + } + + private void stopSearchDevice() { + SearchDeviceManager searchDeviceManager = SearchDeviceManager.getInstance(); + searchDeviceManager.unRegisterListener(this); + } + + @Override + public void onDeviceSearched(String sncode, DEVICE_NET_INFO_EX device_net_info_ex) { + if (device_net_info_ex == null) { + return; + } + String szSerialNo = new String(device_net_info_ex.szSerialNo).trim(); + if (szSerialNo.equalsIgnoreCase(mDeviceSn)) { + mDeviceNetInfoEx = device_net_info_ex; + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SmartConfigPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SmartConfigPresenter.java new file mode 100644 index 0000000..e07ed87 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SmartConfigPresenter.java @@ -0,0 +1,362 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.media.MediaPlayer; +import android.net.wifi.ScanResult; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.lechange.common.configwifi.LCSmartConfig; +import com.lechange.opensdk.configwifi.LCOpenSDK_ConfigWifi; +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.contract.SmartConfigConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.lang.ref.WeakReference; + +public class SmartConfigPresenter implements SmartConfigConstract.Presenter, SearchDeviceManager.ISearchDeviceListener { + private int TIMER_TIMEOUT = 120 * 1000;// 120秒 连接路由 + private static final int TIME_OUT = 60 * 1000; //接收超时时间 + private static final int SEARCH_SUCCESS = 1; //搜索成功 + private static final int SEARCH_FAILED = 2; //搜索不到设备 + private static final int NOT_INIT = 3; //不需要初始化 + private static final int NEED_INIT = 4; //需要初始化 + + private static final String VOICE_CONFIG_FILE_NAME = "Audiopair.wav"; // 声波配对的音频文件 + + WeakReference mView; + DHWifiUtil mDHWifiUtil; + DEVICE_NET_INFO_EX mDeviceNetInfoEx; + String mDeviceSnCode; + boolean mIsSupportSoundWave; + boolean mIsSupportSoundWaveV2; // 是否支持声波新方案 + private boolean mIsRunningAudio = false; + private MediaPlayer mMediaPlayer = null; + private String tempDirectory; //smartconfig、声波文件临时存放路径 + + public SmartConfigPresenter(SmartConfigConstract.View view/*, boolean isQRCodeConfig*/) { + mView = new WeakReference<>(view); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + mDeviceSnCode = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + + initInfo(); + } + + private void initInfo() { + String configMode = DeviceAddModel.newInstance().getDeviceInfoCache().getConfigMode(); + mIsSupportSoundWave = configMode != null && configMode.contains(DeviceAddInfo.ConfigMode.SoundWave.name()); + mIsSupportSoundWaveV2 = DeviceAddHelper.isSupportSoundWaveV2(DeviceAddModel.newInstance().getDeviceInfoCache()); + + mView.get().updateTip2Txt(mIsSupportSoundWave, mIsSupportSoundWaveV2); + + mView.get().hideTipWifiPwdErrorTxt(ProviderManager.getAppProvider().getAppType() == LCConfiguration.APP_LECHANGE_OVERSEA); + + String userId = LCDeviceEngine.newInstance().userId; + tempDirectory = mView.get().getContextInfo().getFilesDir() + File.separator + userId + File.separator; + } + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + switch (msg.what) { + case SEARCH_SUCCESS: //搜索设备成功 + stopAudio(); + recyle(); + isDeviceNeedInit(); + break; + case NOT_INIT: //设备不需初始化 + mView.get().goConnectCloudPage(); + break; + case NEED_INIT: //设备未初始化 + mView.get().goDevInitPage(mDeviceNetInfoEx); + break; + } + + } + } + }; + + private void isDeviceNeedInit() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo) || !DeviceAddHelper.isDeviceNeedInit(mDeviceNetInfoEx)) { + mHandler.obtainMessage(NOT_INIT).sendToTarget(); + } else { + mHandler.obtainMessage(NEED_INIT).sendToTarget(); + } + } + + @Override + public void recyle() { + //关闭 +// LCOpenSDK_ConfigWifi.configWifiStop();//暂时先注释掉试试 + mView.get().stopCountDown(); + DeviceAddModel.newInstance().setLoop(false); + } + + @Override + public String getConfigMode() { + return DeviceAddModel.newInstance().getDeviceInfoCache().getConfigMode(); + } + + //开始smartconfig配对 + @Override + public void startSmartConfig() { + startConfig(); + initAudioPair(); + startSearchDevices(); + } + + /** + * SmartConfig + */ + private void startConfig() { + ScanResult scanResult = mDHWifiUtil.getScanResult(); + String encryptionCap = ""; + if (scanResult != null) { + encryptionCap = scanResult.capabilities == null ? "" : scanResult.capabilities; + } + DeviceAddInfo.WifiInfo wifiInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiInfo(); + String ssid = wifiInfo.getSsid() == null ? "" : wifiInfo.getSsid(); + String ssid_pwd = wifiInfo.getPwd() == null ? "" : wifiInfo.getPwd(); + + String directory = ProviderManager.getDeviceAddCustomProvider().getDevAddCachePath(); + LogUtil.debugLog("rrrrr","directory::"+directory); + File fileDir = new File(directory); + if(!fileDir.exists()){ + if(!fileDir.mkdirs()){ + return; + } + } + File fileAudio = new File(fileDir,VOICE_CONFIG_FILE_NAME); + if(fileAudio.exists()){ + fileAudio.delete(); + } + + /** + * cfgType:配网方式,1--组播,2--广播,4--声波,可按位或运算组合使用; + * voiceConfigFilePath:声波配对的音频文件的生成路径,由上层调用者传入; + * enableBgMusic:声波配对是否使用背景声,默认是布谷鸟叫声; + * freq:声波配对收发信号的基带频率; + * fsk_tx_mode:fsk发送方式,0--新的fsk发送方式,1--老的fsk发送方式,2--新的和老的fsk波形发送方式; + */ + int fskTxMode = 1; + boolean enableBgMusic = true; + if(mIsSupportSoundWaveV2) { + fskTxMode = 0; + enableBgMusic = false; + } + LCSmartConfig.startConfig(mDeviceSnCode, ssid, ssid_pwd, encryptionCap, LCSmartConfig.ConfigType.LCConfigWifi_Type_ALL, fileAudio.getAbsolutePath(),enableBgMusic,11000, fskTxMode); + + /** + * cfgType:配网方式,1--组播,2--广播,4--声波,可按位或运算组合使用; + * voiceConfigFilePath:声波配对的音频文件的生成路径,由上层调用者传入; + * enableBgMusic:声波配对是否使用背景声,默认是布谷鸟叫声; + * freq:声波配对收发信号的基带频率; + * fsk_tx_mode:fsk发送方式,0--新的fsk发送方式,1--老的fsk发送方式,2--新的和老的fsk波形发送方式; + * 不传本地的路径可能会走到smartConfig的配网方式去 + *//* + int fskTxMode = 1; + boolean enableBgMusic = true; + LCOpenSDK_ConfigWifi.configWifiStart(mDeviceSnCode, ssid, ssid_pwd, encryptionCap, LCSmartConfig.ConfigType.LCConfigWifi_Type_ALL, enableBgMusic,11000, fskTxMode);*/ + + } + + /** + * 声波配对 + */ + private void initAudioPair() { + if(!mIsSupportSoundWave && !mIsSupportSoundWaveV2) { + return; + } + + String directory = ProviderManager.getDeviceAddCustomProvider().getDevAddCachePath(); + File fileDir = new File(directory); + if (!fileDir.exists()) { + if (!fileDir.mkdirs()) { + return; + } + } + File fileAudio = new File(fileDir, VOICE_CONFIG_FILE_NAME); + if (fileAudio.exists() && !TextUtils.isEmpty(fileAudio.getAbsolutePath())) { + initAudio(fileAudio.getAbsolutePath()); + } + } + + + private void initAudio(String path) { + mMediaPlayer = new MediaPlayer(); + + try { + LogUtil.debugLog("AudioConfig : ", "setDataSource MediaPlayer : " + path); + mMediaPlayer.setDataSource(path); + LogUtil.debugLog("AudioConfig : ", "prepare MediaPlayer"); + mMediaPlayer.prepare(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 播放新声波方案的音频文件 + */ + @Override + public void playAudio() { + if(!mIsRunningAudio && mMediaPlayer != null) { + try { + mMediaPlayer.setLooping(true); + LogUtil.debugLog("AudioConfig : ", "start MediaPlayer"); + mMediaPlayer.start(); + mIsRunningAudio = true; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void pauseAudio() { + if(mMediaPlayer != null) { + LogUtil.debugLog("AudioConfig : ", "pause MediaPlayer"); + mMediaPlayer.pause(); + mIsRunningAudio = false; + } + } + + /** + * 停止播放新声波方案的音频文件 + */ + @Override + public void stopAudio() { + if(mIsRunningAudio && mMediaPlayer != null) { + try { + mMediaPlayer.stop(); + LogUtil.debugLog("AudioConfig : ", "prepare MediaPlayer"); + mMediaPlayer.prepare(); + mIsRunningAudio = false; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void releaseAudio() { + if (mMediaPlayer != null) { + mMediaPlayer.stop(); + LogUtil.debugLog("AudioConfig : ", "release MediaPlayer"); + mMediaPlayer.release(); + mMediaPlayer = null; + mIsRunningAudio = false; + } + } + + @Override + public void wifiPwdErrorClick() { + DeviceAddInfo.WifiInfo info = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiInfo(); + info.setPwd(""); + DHWifiUtil mDHWifiUtil=new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + String curWifiName = mDHWifiUtil.getCurrentWifiInfo().getSSID().replaceAll("\"", ""); + String WIFI_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_ADD_"; + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + curWifiName,""); + mView.get().goWfiPwdPage(); + } + + /** + * 搜索设备 + */ + private void startSearchDevices() { + final SearchDeviceManager manager = SearchDeviceManager.getInstance(); + mDeviceNetInfoEx = manager.getDeviceNetInfo(mDeviceSnCode); + if (mDeviceNetInfoEx != null) { + // 已经搜到 + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } else { + manager.registerListener(this); + manager.startSearch(); + + getDeviceInfo(); + } + } + + private void getDeviceInfo() { + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + // 第一次添加时使用二维码或用输入的sc码来判断,离线配网或者设备已在平台上线过则可以通过能力集进行判断 + if(DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + String deviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + String model = DeviceAddModel.newInstance().getDeviceInfoCache().getModelName(); + LCBusinessHandler getDeviceHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + dispatchResult(); + } else {//发生异常且倒计时未完成,重新查询 + getDeviceInfo(); + } + + } + }; + DeviceAddModel.newInstance().getDeviceInfoLoop(deviceSn, model, "", TIME_OUT, getDeviceHandler); + } + } + + private void dispatchResult() { + stopAudio(); + recyle(); + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String status=deviceAddInfo.getStatus(); + if(TextUtils.isEmpty(status)){ + status=DeviceAddInfo.Status.offline.name(); + } + if (DeviceAddInfo.Status.online.name().equals(status)) { + if (isWifiOfflineConfiMode()) {//wifi离线配置 + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.DESTROY_ACTION)); + ProviderManager.getDeviceAddCustomProvider().goHomePage(mView.get().getContextInfo()); + mView.get().showToastInfo(R.string.add_device_wifi_config_success); + } else { + mView.get().goBindDevicePage(); + } + } else { + if (isWifiOfflineConfiMode()) {//wifi离线配置 + mView.get().showToastInfo(R.string.add_device_config_failed); + mView.get().completeAction(); + } else { + mView.get().goConfigTimeoutPage(); + } + } + } + + public boolean isWifiOfflineConfiMode() { + return DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode(); + } + + @Override + public void onDeviceSearched(String sncode, DEVICE_NET_INFO_EX info) { + if (info != null && mDeviceSnCode.equalsIgnoreCase(sncode)) { + mDeviceNetInfoEx = info; + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + SearchDeviceManager.getInstance().unRegisterListener(this); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SoftApWifiPwdPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SoftApWifiPwdPresenter.java new file mode 100644 index 0000000..141eea3 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/SoftApWifiPwdPresenter.java @@ -0,0 +1,120 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.SoftApWifiPwdConstract; +import com.mm.android.deviceaddmodule.entity.WlanInfo; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class SoftApWifiPwdPresenter implements SoftApWifiPwdConstract.Presenter { + WeakReference mView; + WlanInfo mCurWlanInfo; + public String WIFI_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_ADD_"; + private String WIFI_CHECKBOX_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_CHECKBOX_ADD_"; + DHWifiUtil mDHWifiUtil; + private boolean mIsNotNeedLogin; + private boolean isSupport5G; + + public SoftApWifiPwdPresenter(SoftApWifiPwdConstract.View view) { + mView = new WeakReference<>(view); + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + String wifiMode = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiTransferMode(); + if (!TextUtils.isEmpty(wifiMode)) { + isSupport5G = wifiMode.toUpperCase().contains("5GHZ"); + } + } + + @Override + public void setWlanInfo(WlanInfo wlanInfo) { + mCurWlanInfo = wlanInfo; + } + + @Override + public void setIsNotNeedLogin(boolean isNotNeedLogin){ + mIsNotNeedLogin = isNotNeedLogin; + } + + @Override + public boolean isDevSupport5G() { + return isSupport5G; + } + + @Override + public String getCurWifiName() { + return mCurWlanInfo.getWlanSSID(); + } + + @Override + public void updateWifiCache() { + DeviceAddInfo.WifiInfo wifiInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiInfo(); + wifiInfo.setSsid(getCurWifiName()); + wifiInfo.setPwd(mView.get().getWifiPwd()); + if (mView.get().isSavePwdChecked()) { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + getCurWifiName(), mView.get().getWifiPwd()); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName(), true); + } else { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + getCurWifiName(), ""); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName(), false); + } + } + + @Override + public String getSavedWifiPwd() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getString(WIFI_SAVE_PREFIX + getCurWifiName()); + } + + @Override + public boolean getSavedWifiCheckBoxStatus() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getBoolean(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName()); + } + + @Override + public void connectWifi() { + mView.get().showProgressDialog(); + updateWifiCache();//更新wifi信息到缓存 + String gatwayip = mDHWifiUtil.getGatewayIp(); + final DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + String pwd = deviceAddInfo.getDevicePwd(); + String wifiPwd = deviceAddInfo.getWifiInfo().getPwd(); + + LCBusinessHandler connectWifiHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() != null && mView.get().isViewActive()) { + mView.get().cancelProgressDialog(); + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + dispatchConnectResult(msg); + } + } else { + mView.get().showToastInfo(R.string.device_disturb_state_failed); + } + } + }; + + if(mIsNotNeedLogin) { + DeviceAddModel.newInstance().connectWifi4Sc(gatwayip, mCurWlanInfo, wifiPwd, connectWifiHandler); + } else { + DeviceAddModel.newInstance().connectWifi(gatwayip, pwd, mCurWlanInfo, wifiPwd, /*type == DHDeviceExtra.DeviceLoginType.SafeMode.ordinal(), */connectWifiHandler); + } + } + + private void dispatchConnectResult(Message message) { + mView.get().cancelProgressDialog(); + //恢复网络 + DeviceAddHelper.clearNetWork(); + DeviceAddHelper.connectPreviousWifi(); + boolean connectResult = (boolean) message.obj; + mView.get().goCloudConnectPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TimeoutPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TimeoutPresenter.java new file mode 100644 index 0000000..6200b56 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TimeoutPresenter.java @@ -0,0 +1,32 @@ +package com.mm.android.deviceaddmodule.presenter; + +import com.mm.android.deviceaddmodule.contract.TimeoutConstract; + +import java.lang.ref.WeakReference; + +public class TimeoutPresenter implements TimeoutConstract.Presenter { + WeakReference mView; + int mErrorCode; + String mDevTypeModel = ""; + + public TimeoutPresenter(TimeoutConstract.View view) { + mView = new WeakReference<>(view); + } + + @Override + public void setErrorData(int errorCode, String devTypeModel) { + mErrorCode = errorCode; + mDevTypeModel = devTypeModel; + showTimeoutView(); + } + + private void showTimeoutView() { + mView.get().showAView(); + } + + //按钮1事件 + @Override + public void dispatchAction1() { + mView.get().goScanPage(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipSoftApConnectWifiPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipSoftApConnectWifiPresenter.java new file mode 100644 index 0000000..d3850c7 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipSoftApConnectWifiPresenter.java @@ -0,0 +1,237 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.net.wifi.SupplicantState; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.contract.TipSoftApConnectWifiConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.NetWorkChangeCheckEvent; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.utils.WifiUtil; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; + +public class TipSoftApConnectWifiPresenter implements TipSoftApConnectWifiConstract.Presenter { + private int TIME_OUT_TIME = 15 * 1000; //连接设备热点超时时间 + private static final int CONNECT_FAILED = 0; //连接热点失败 + WifiUtil mDHWifiUtil; + String mDeviceSn; + boolean mConnectResult; + boolean mBinding; //开始绑定了,防止绑定多次 + WeakReference mView; + DeviceIntroductionInfo mTips; + + + Runnable mTimeOutRunnable = new Runnable() { + @Override + public void run() { + mHandler.obtainMessage(CONNECT_FAILED).sendToTarget(); + } + }; + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (mView.get() != null && + mView.get().isViewActive()) { + connectHotFailed(); + } + } + }; + + Runnable mReconectWifiAgainRunnable = new Runnable() { + @Override + public void run() { + connectWifiAction(false); + } + }; + + + public TipSoftApConnectWifiPresenter(TipSoftApConnectWifiConstract.View view) { + mView = new WeakReference<>(view); + mDHWifiUtil = new WifiUtil(mView.get().getContextInfo().getApplicationContext()); + mTips = DeviceAddModel.newInstance().getDeviceInfoCache().getDevIntroductionInfo(); + mDeviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + mView.get().updateWifiName(getWifiName()); + } + + @Override + public void copyWifiPwd() { + ClipboardManager clipboardManager = (ClipboardManager) mView.get().getContextInfo().getSystemService(Context.CLIPBOARD_SERVICE); + + if (clipboardManager != null) { + String wifiPwd = ""; + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + // 支持sc码的软ap wifiw为加密的,需要密码进行连接,密码为SC码 + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + wifiPwd = deviceAddInfo.getSc(); + } + + clipboardManager.setPrimaryClip(ClipData.newPlainText(null, wifiPwd)); + mView.get().showToastInfo(R.string.common_copy_success); + } + } + + @Override + public void dispatchHotConnected() { + if (mDHWifiUtil.getCurrentWifiInfo() == null) + return; + LogUtil.debugLog("bz", "isConnectedDevHot(): " + isConnectedDevHot() + " mConnectResult: " + mConnectResult); + if (isConnectedDevHot() && !mBinding) { + mBinding = true; + //通知服务已连上热点 + EventBus.getDefault().post(new NetWorkChangeCheckEvent()); + DeviceAddHelper.bindNetwork(new DeviceAddHelper.BindNetworkListener() { + @Override + public void onBindWifiListener() { + mHandler.removeCallbacks(mTimeOutRunnable); + mHandler.removeCallbacks(mReconectWifiAgainRunnable); + mView.get().cancelProgressDialog(); + mView.get().goSecurityCheckPage(); + } + }); + } + } + + private void connectHotFailed() { + mView.get().cancelProgressDialog(); + mView.get().showToastInfo(R.string.common_connect_failed); + mConnectResult = false; + + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + // 支持sc码的软ap + boolean isSupportAddBySc = false; + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + isSupportAddBySc = true; + } + String wifiPwd = ""; + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + if (deviceAddInfo.isManualInput() || TextUtils.isEmpty(deviceAddInfo.getSc())) { + wifiPwd = mView.get().getContextInfo().getString(R.string.add_device_wait_to_connect_wifi_sc); + } else { + wifiPwd = deviceAddInfo.getSc(); + } + } + + mView.get().updateConnectFailedTipText(getHotSSID(), wifiPwd, isSupportAddBySc, deviceAddInfo.isManualInput() || TextUtils.isEmpty(deviceAddInfo.getSc())); + } + + public void connectWifiAction(boolean isFirst) { + mView.get().showProgressDialog(); + mConnectResult = false; + mBinding = false; + mDHWifiUtil.openWifi(); + if (isConnectedDevHot()) {//若已连上设备热点,不需要去连接了 + dispatchHotConnected(); + return; + } + String ssid = getHotSSID(); + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + //缓存设备热点ssid,用于中间热点断开重新连时,作为是否连上热点的判断依据,需要重新调用bindNetwork + deviceAddInfo.setSsid(ssid); + //缓存当前连接的wifi ssid,便于退出软ap时恢复网络 + WifiInfo wifiInfo = mDHWifiUtil.getCurrentWifiInfo(); + if (wifiInfo != null) { + WifiConfiguration currentConfig = mDHWifiUtil.IsExsits(wifiInfo.getSSID()); + if (currentConfig != null) { + deviceAddInfo.setPreviousSsid(currentConfig.SSID); + } + } + // 支持sc码的软ap wifiw为加密的,需要密码进行连接,密码为SC码 + if (DeviceAddHelper.isSupportAddBySc(deviceAddInfo)) { + final String wifiPwd = deviceAddInfo.getSc(); + mDHWifiUtil.openWifi(); + mDHWifiUtil.disconnectCurrentWifi(getHotSSID()); + mDHWifiUtil.startScan(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + WifiUtil.WifiCipherType type = mDHWifiUtil.getCipherType(getHotSSID()); + mConnectResult = mDHWifiUtil.connectWifiEx(getHotSSID(), wifiPwd, type); + } + }, 3000); + + } else { + isFirst = false; + mConnectResult = mDHWifiUtil.connectWifi(getHotSSID(), ""); + } + + LogUtil.debugLog("bz", "mConnectResult : " + mConnectResult); + if (isFirst) { + mHandler.postDelayed(mReconectWifiAgainRunnable, TIME_OUT_TIME); + } else { + mHandler.postDelayed(mTimeOutRunnable, TIME_OUT_TIME); + } + } + + private String getWifiName() { + String wifiName = ""; //默认空字符串,防止空指针 + if (mTips != null && mTips.getStrInfos() != null) { + wifiName = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_WIFI_NAME); + } + + String wifiVersion = ""; + if (mTips != null && mTips.getStrInfos() != null) { + wifiVersion = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_WIFI_VERSION); + } + + // wifiVersion为空,使用软Ap通用设备热点名称"DAP-XXXX" + if (TextUtils.isEmpty(wifiVersion)) { + return DeviceAddHelper.AP_WIFI_NAME_DAP; + } + + return TextUtils.isEmpty(wifiName) ? "" : wifiName; + } + + @Override + public String getHotSSID() { + int appType = ProviderManager.getAppProvider().getAppType(); + String wifiName = getWifiName(); //OMS后台配置的wifi名称例如“K5-xxxx” + String wifiNamePre = wifiName.substring(0, wifiName.lastIndexOf("-") + 1); //取前缀例如“K5-” + + String wifiVersion = ""; + if (mTips != null && mTips.getStrInfos() != null) { + wifiVersion = mTips.getStrInfos().get(DeviceAddHelper.OMSKey.SOFT_AP_MODE_WIFI_VERSION); + } + + String ssid = wifiNamePre + mDeviceSn; + if (!TextUtils.isEmpty(wifiVersion) && wifiVersion.equalsIgnoreCase(DeviceAddHelper.AP_WIFI_VERSION_V1)) { + if (appType == LCConfiguration.APP_LECHANGE_OVERSEA) { + ssid = wifiNamePre + mDeviceSn; + } else if (appType == LCConfiguration.APP_LECHANGE) { + ssid = wifiNamePre + mDeviceSn.substring(mDeviceSn.length() - 4); //国内,序列号后四位 + } + } + + return ssid; + } + + //是否已连上设备热点 + public boolean isConnectedDevHot() { + WifiInfo wifiInfo = mDHWifiUtil.getCurrentWifiInfo(); + LogUtil.debugLog("bz", " " + (wifiInfo == null ? "wifiInfo == null" : wifiInfo.getSupplicantState())); + + if (wifiInfo == null || (SupplicantState.ASSOCIATED != wifiInfo.getSupplicantState() && SupplicantState.COMPLETED != wifiInfo.getSupplicantState())) { + return false; + } else { + String ssid = getHotSSID(); + ssid = "\"" + ssid + "\""; + LogUtil.debugLog("bz", ssid + " " + wifiInfo.getSSID() + " " + wifiInfo.getSSID().equals(ssid)); + return wifiInfo.getSSID().contains(mDeviceSn); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipWifiConnectPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipWifiConnectPresenter.java new file mode 100644 index 0000000..648fb1e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TipWifiConnectPresenter.java @@ -0,0 +1,106 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Handler; +import android.os.Message; + +import com.company.NetSDK.DEVICE_NET_INFO_EX; +import com.mm.android.deviceaddmodule.SearchDeviceManager; +import com.mm.android.deviceaddmodule.contract.TipWifiConnectConstract; +import com.mm.android.deviceaddmodule.helper.DeviceAddHelper; +import com.mm.android.deviceaddmodule.helper.Utils4AddDevice; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class TipWifiConnectPresenter implements TipWifiConnectConstract.Presenter { + private static final int SEARCH_SUCCESS = 1; + private static final int SEARCH_FAILED = 2; + private static final int NEED_INIT = 3; + private static final long SEARCH_TIME=3*1000; //搜索时间 + private int searchIndex=0; //当前搜索次数 + private long searchIntervalTime=500; //搜索间隔时间 + + WeakReference mView; + DEVICE_NET_INFO_EX mDeviceNetInfoEx; + String mDeviceSn; + + public TipWifiConnectPresenter(TipWifiConnectConstract.View view) { + mView = new WeakReference<>(view); + mDeviceSn= DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + } + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + mView.get().cancelProgressDialog(); + stopSearchDevice(); + switch (msg.what) { + case SEARCH_SUCCESS: + mView.get().goCloudConnectPage(); + break; + case NEED_INIT: + mView.get().goDevInitPage(mDeviceNetInfoEx); + break; + case SEARCH_FAILED: + // 未搜到设备,进入配网流程 + mView.get().goWifiConfigPage(); + break; + } + + } + }; + + @Override + public void searchDevice() { + if (Utils4AddDevice.isWifi(mView.get().getContextInfo())) { + if(DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode()){//离线配网 + mView.get().goWifiConfigPage(); + return; + } + mView.get().showProgressDialog(); + startSearch(); + } + + } + + @Override + public void stopSearchDevice() { + mHandler.removeCallbacks(SearchRunnable); + searchIndex=0; + } + + @Override + public String getConfigMode() { + DeviceAddInfo deviceAddInfo= DeviceAddModel.newInstance().getDeviceInfoCache(); + return deviceAddInfo.getConfigMode(); + } + + private void startSearch(){ + stopSearchDevice(); + mHandler.post(SearchRunnable); + } + + private Runnable SearchRunnable=new Runnable() { + @Override + public void run() { + searchIndex++; + SearchDeviceManager manager = SearchDeviceManager.getInstance(); + mDeviceNetInfoEx = manager.getDeviceNetInfo(mDeviceSn); + if(mDeviceNetInfoEx!=null){ + if(DeviceAddHelper.isDeviceNeedInit(mDeviceNetInfoEx) && !DeviceAddHelper.isSupportAddBySc(DeviceAddModel.newInstance().getDeviceInfoCache())) { + mHandler.obtainMessage(NEED_INIT).sendToTarget(); + }else{ + mHandler.obtainMessage(SEARCH_SUCCESS).sendToTarget(); + } + }else{ + if(searchIndex<(SEARCH_TIME/searchIntervalTime)) + mHandler.postDelayed(this,searchIntervalTime); + else{ + mHandler.obtainMessage(SEARCH_FAILED).sendToTarget(); + } + } + + } + }; +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TypeChoosePresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TypeChoosePresenter.java new file mode 100644 index 0000000..e7b6e1c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/TypeChoosePresenter.java @@ -0,0 +1,112 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.os.Message; +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.contract.TypeChooseConstract; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.LCBusinessHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorTip; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceTypeInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; +import java.util.List; + +public class TypeChoosePresenter implements TypeChooseConstract.Presenter { + WeakReference mView; + private List mModelInfoList; //设备类型集合 + + public TypeChoosePresenter(TypeChooseConstract.View view) { + mView = new WeakReference<>(view); + } + + @Override + public void getDeviceInfoSync(final String deviceModelName) { + mView.get().showProgressDialog(); + String deviceSn = DeviceAddModel.newInstance().getDeviceInfoCache().getDeviceSn(); + LCBusinessHandler getDeviceHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + checkDevIntroductionInfo(deviceModelName); + } else { + mView.get().cancelProgressDialog(); + mView.get().showToastInfo(BusinessErrorTip.getErrorTip(msg)); + } + } + }; + DeviceAddModel.newInstance().getDeviceInfo(deviceSn, "", deviceModelName, "", getDeviceHandler); + } + + @Override + public void checkDevIntroductionInfo(final String deviceModelName) { + LCBusinessHandler checkDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + DeviceIntroductionInfo deviceIntroductionInfo = null; + if (msg.what == HandleMessageCode.HMC_SUCCESS) { + //TODO:获取失败也当做有更新 + deviceIntroductionInfo = (DeviceIntroductionInfo) msg.obj; + } + if (deviceIntroductionInfo == null) { //表示需要更新引导 + getDevIntroductionInfoSync(deviceModelName); + } else { + dispatchIntroctionResult(); + } + } + }; + DeviceAddModel.newInstance().checkDevIntroductionInfo(deviceModelName, checkDevIntroductionHandler); + } + + @Override + public void resetDevPwdCache() { + DeviceAddModel.newInstance().getDeviceInfoCache().clearCache(); + } + + //异步获取设备引导信息 + private void getDevIntroductionInfoSync(String deviceModel) { + LCBusinessHandler getDevIntroductionHandler = new LCBusinessHandler() { + @Override + public void handleBusiness(Message msg) { + if (mView.get() == null + || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + dispatchIntroctionResult(); + } + }; + DeviceAddModel.newInstance().getDevIntroductionInfo(deviceModel, getDevIntroductionHandler); + } + + + private void dispatchIntroctionResult() { + mView.get().cancelProgressDialog(); + // 设备选择页面清除imei号 + DeviceAddInfo deviceAddInfo = DeviceAddModel.newInstance().getDeviceInfoCache(); + deviceAddInfo.setImeiCode(null); + if (TextUtils.isEmpty(deviceAddInfo.getModelName()) && TextUtils.isEmpty(deviceAddInfo.getNc())) { + if (mView.get() == null || (mView.get() != null && !mView.get().isViewActive())) { + return; + } + mView.get().showSearchError(); + return; + } + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CONFIG_PAGE_NAVIGATION_ACTION)); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/WifiPwdPresenter.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/WifiPwdPresenter.java new file mode 100644 index 0000000..bd81a1d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/presenter/WifiPwdPresenter.java @@ -0,0 +1,74 @@ +package com.mm.android.deviceaddmodule.presenter; + +import android.text.TextUtils; + +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.contract.WifiPwdConstract; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import java.lang.ref.WeakReference; + +public class WifiPwdPresenter implements WifiPwdConstract.Presenter { + WeakReference mView; + private boolean isSupport5G; + DHWifiUtil mDHWifiUtil; + private String WIFI_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_ADD_"; + private String WIFI_CHECKBOX_SAVE_PREFIX = LCDeviceEngine.newInstance().userId + "_WIFI_CHECKBOX_ADD_"; + + public WifiPwdPresenter(WifiPwdConstract.View view) { + mView = new WeakReference<>(view); + String wifiMode = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiTransferMode(); + if (!TextUtils.isEmpty(wifiMode)) { + isSupport5G = wifiMode.toUpperCase().contains("5GHZ"); + } + mDHWifiUtil = new DHWifiUtil(mView.get().getContextInfo().getApplicationContext()); + } + + @Override + public boolean isDevSupport5G() { + return isSupport5G; + } + + @Override + public String getCurWifiName() { + String curWifiName = mDHWifiUtil.getCurrentWifiInfo().getSSID().replaceAll("\"", ""); + if(LCConfiguration.UNKNOWN_SSID.equals(curWifiName)){ + curWifiName = ""; + } + return curWifiName; + } + + @Override + public void updateWifiCache() { + DeviceAddInfo.WifiInfo wifiInfo = DeviceAddModel.newInstance().getDeviceInfoCache().getWifiInfo(); + wifiInfo.setSsid(getCurWifiName()); + wifiInfo.setPwd(mView.get().getWifiPwd()); + if (mView.get().isSavePwdChecked()) { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + getCurWifiName(), mView.get().getWifiPwd()); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName(), true); + } else { + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_SAVE_PREFIX + getCurWifiName(), ""); + PreferencesHelper.getInstance(mView.get().getContextInfo()).set(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName(), false); + } + } + + @Override + public String getSavedWifiPwd() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getString(WIFI_SAVE_PREFIX + getCurWifiName()); + } + + @Override + public boolean getSavedWifiCheckBoxStatus() { + return PreferencesHelper.getInstance(mView.get().getContextInfo()).getBoolean(WIFI_CHECKBOX_SAVE_PREFIX + getCurWifiName()); + } + + @Override + public String getConfigMode() { + return DeviceAddModel.newInstance().getDeviceInfoCache().getConfigMode(); + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/provider/DeviceAddProvider.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/provider/DeviceAddProvider.java new file mode 100644 index 0000000..8fd43af --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/provider/DeviceAddProvider.java @@ -0,0 +1,48 @@ +package com.mm.android.deviceaddmodule.provider; + +import com.company.NetSDK.INetSDK; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessRunnable; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.IDeviceAdd; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseHandler; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.HandleMessageCode; + +public class DeviceAddProvider implements IDeviceAdd { + + private volatile static DeviceAddProvider deviceAddProvider; + + public static DeviceAddProvider newInstance() { + if (deviceAddProvider == null) { + synchronized (DeviceAddProvider.class) { + if (deviceAddProvider == null) { + deviceAddProvider = new DeviceAddProvider(); + } + } + } + return deviceAddProvider; + } + + @Override + public void uninit() { + + } + + @Override + public void stopSearchDevicesAsync(final long ret, final BaseHandler handler) { + new BusinessRunnable(null) { + @Override + public void doBusiness() throws BusinessException { + boolean result = INetSDK.StopSearchDevices(ret); + if (handler != null) + handler.obtainMessage(HandleMessageCode.HMC_SUCCESS, result).sendToTarget(); + } + }; + } + + @Override + public boolean stopSearchDevices(long ret, String requestId) { + boolean result = INetSDK.StopSearchDevices(ret); + //搜索接口只报失败 + return result; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/SucceedClickReceiver.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/SucceedClickReceiver.java new file mode 100644 index 0000000..b2064b4 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/SucceedClickReceiver.java @@ -0,0 +1,40 @@ +package com.mm.android.deviceaddmodule.receiver; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import java.util.List; + +/** + * 热点连接成功后通知栏的点击接收 + */ + +public class SucceedClickReceiver extends BroadcastReceiver { + public static final String TAG = SucceedClickReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List recentTaskList = am.getRecentTasks(Integer.MAX_VALUE, + ActivityManager.RECENT_IGNORE_UNAVAILABLE); + int taskid = -1; + if (recentTaskList != null) { + for (ActivityManager.RecentTaskInfo r : recentTaskList) { + try { + String appName = context.getApplicationContext().getPackageName(); + if (appName.equals(r.baseIntent.getComponent().getPackageName())) {// 包名一致 + taskid = r.id; + break; + } + } catch (Exception e) { + } + } + } + + if (taskid != -1) {// 表示已启动过 + am.moveTaskToFront(taskid, ActivityManager.MOVE_TASK_WITH_HOME); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/TimeoutClickReceiver.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/TimeoutClickReceiver.java new file mode 100644 index 0000000..ecff69e --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/receiver/TimeoutClickReceiver.java @@ -0,0 +1,45 @@ +package com.mm.android.deviceaddmodule.receiver; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.NoticeToBackEvent; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +/** + * 热点链接超时的通知栏点击接收 + */ + +public class TimeoutClickReceiver extends BroadcastReceiver { + public static final String TAG = TimeoutClickReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List recentTaskList = am.getRecentTasks(Integer.MAX_VALUE, + ActivityManager.RECENT_IGNORE_UNAVAILABLE); + int taskid = -1; + if (recentTaskList != null) { + for (ActivityManager.RecentTaskInfo r : recentTaskList) { + try { + String appName = context.getApplicationContext().getPackageName(); + if (appName.equals(r.baseIntent.getComponent().getPackageName())) {// 包名一致 + taskid = r.id; + break; + } + } catch (Exception e) { + } + } + } + + if (taskid != -1) {// 表示已启动过 + EventBus.getDefault().post(new NoticeToBackEvent()); + am.moveTaskToFront(taskid, ActivityManager.MOVE_TASK_WITH_HOME); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddEntityChangeHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddEntityChangeHelper.java new file mode 100644 index 0000000..1955392 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddEntityChangeHelper.java @@ -0,0 +1,58 @@ +package com.mm.android.deviceaddmodule.service; + +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.openapi.data.DeviceInfoBeforeBindData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceLeadingInfoData; + +import java.util.HashMap; + +public class DeviceAddEntityChangeHelper { + + + public static DeviceAddInfo parse2DeviceAddInfo(DeviceInfoBeforeBindData.ResponseData data) { + DeviceAddInfo deviceAddInfo = new DeviceAddInfo(); + deviceAddInfo.setDeviceExist("exist".equals(data.deviceExist)); + deviceAddInfo.setBindStatus(data.bindStatus); + deviceAddInfo.setBindAcount(data.userAccount); + deviceAddInfo.setStatus(data.status); + deviceAddInfo.setDeviceModel(data.deviceCodeModel); + deviceAddInfo.setModelName(data.deviceModelName); + deviceAddInfo.setCatalog(data.catalog); + deviceAddInfo.setAbility(data.ability); + deviceAddInfo.setSupport(data.support); + String wifiConfigMode; + if (TextUtils.isEmpty(data.wifiConfigMode)) { // 若配网模式未返回,默认可进行有线无线切换 V5.1默认增加软AP + wifiConfigMode = DeviceAddInfo.ConfigMode.SmartConfig.name() + "," + + DeviceAddInfo.ConfigMode.LAN.name() + "," + + DeviceAddInfo.ConfigMode.SoundWave.name() + "," + + DeviceAddInfo.ConfigMode.SoftAP.name(); + } else { + wifiConfigMode = data.wifiConfigMode; + } + deviceAddInfo.setConfigMode(wifiConfigMode); + deviceAddInfo.setWifiConfigModeOptional(data.wifiConfigModeOptional); + deviceAddInfo.setWifiTransferMode(data.wifiTransferMode); + deviceAddInfo.setType(data.type); + return deviceAddInfo; + } + + public static DeviceIntroductionInfo parse2DeviceIntroductionInfo(DeviceLeadingInfoData.ResponseData data) { + DeviceIntroductionInfo deviceIntroductionInfo = new DeviceIntroductionInfo(); + HashMap imagesList = new HashMap<>(); + HashMap strList = new HashMap<>(); + for (DeviceLeadingInfoData.ResponseData.ImagesElement imageElement : data.images) { + imagesList.put(imageElement.imageName, imageElement.imageUrl); + } + for (DeviceLeadingInfoData.ResponseData.IntroductionsElement strElement : data.introductions) { + strList.put(strElement.introductionName, strElement.introductionContent); + } + + deviceIntroductionInfo.setUpdateTime(data.updateTime); + deviceIntroductionInfo.setImageInfos(imagesList); + deviceIntroductionInfo.setStrInfos(strList); + return deviceIntroductionInfo; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddService.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddService.java new file mode 100644 index 0000000..ad3b72c --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/DeviceAddService.java @@ -0,0 +1,147 @@ +package com.mm.android.deviceaddmodule.service; + +import android.text.TextUtils; + +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceBindResult; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.openapi.DeviceAddOpenApiManager; +import com.mm.android.deviceaddmodule.openapi.data.BindDeviceData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceInfoBeforeBindData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceLeadingInfoData; +import com.mm.android.deviceaddmodule.openapi.data.DeviceModelOrLeadingInfoCheckData; +import com.mm.android.deviceaddmodule.openapi.data.ModifyDeviceNameData; + +/** + * 设备添加模块网络协议栈 + */ +public class DeviceAddService{ + private static final String TAG = "DeviceAddService"; + + /** + * openApi + * + * 绑定设备前,获取设备信息 + * + * @param deviceId String 必须 设备序列号 + * @param deviceCodeModel String 必须 二维码型号 + * @param deviceModelName String 必须 APP展示的设备型号名称(产品称之为市场型号,用户自己选择设备类型时选的是市场型号) + * @param ncCode String 必须 用于标识设备配网能力 + * @param timeout + * @return + * @throws BusinessException + */ + public DeviceAddInfo deviceInfoBeforeBind( String deviceId, String deviceCodeModel, String deviceModelName, String ncCode, int timeout) throws BusinessException { + DeviceInfoBeforeBindData beforeBindData=new DeviceInfoBeforeBindData(); + beforeBindData.data.token= LCDeviceEngine.newInstance().accessToken; + beforeBindData.data.deviceId=deviceId; + beforeBindData.data.deviceCodeModel=deviceCodeModel; + beforeBindData.data.deviceModelName=deviceModelName; + beforeBindData.data.ncCode=ncCode; + DeviceInfoBeforeBindData.Response response = DeviceAddOpenApiManager.deviceInfoBeforeBind(beforeBindData); + return DeviceAddEntityChangeHelper.parse2DeviceAddInfo(response.data); + } + + /** + * openApi + * + * 校验设备型号或者设备引导信息配置信息是否更新 + * + * @param checkType String 必须 要校验的类型,DEVICE_MODEL:设备产品型号信息;DEVICE_LEADING_INFO:设备引导信息 + * @param deviceModelName String 可选 设备市场型号,checkType为DEVICE_LEADING_INFO时要传 + * @param updateTime String 必须 APP本地缓存了配置后,请求使用上次请求配置服务返回的时间,检查是否需要更新配置 + * @param timeout + * @return + * @throws BusinessException + */ + public String deviceModelOrLeadingInfoCheck(String checkType, String deviceModelName, String updateTime, int timeout) throws BusinessException { + DeviceModelOrLeadingInfoCheckData req=new DeviceModelOrLeadingInfoCheckData(); + req.data.token = LCDeviceEngine.newInstance().accessToken; + req.data.deviceModelName = deviceModelName; + req.data.updateTime = updateTime; + DeviceModelOrLeadingInfoCheckData.Response response = DeviceAddOpenApiManager.deviceModelOrLeadingInfoCheck(req); + return response.data.isUpdated + ""; + } + + /** + * openApi + * + * 根据设备市场型号获取设备添加流程引导页配置信息 以deviceModel_语言为索引 + * + * @param deviceModel String 必须 设备市场型号 + * @param timeout + * @return + * @throws BusinessException + */ + public DeviceIntroductionInfo deviceLeadingInfo(String deviceModel, int timeout) throws BusinessException { + DeviceLeadingInfoData req=new DeviceLeadingInfoData(); + req.data.token = LCDeviceEngine.newInstance().accessToken; + req.data.deviceModelName = deviceModel; + DeviceLeadingInfoData.Response response = DeviceAddOpenApiManager.deviceLeadingInfo(req); + FileSaveHelper.saveToJsonInfo(response.body, deviceModel + "_" + "zh_CN" + "_" + FileSaveHelper.INTRODUCTION_INFO_NAME); + return DeviceAddEntityChangeHelper.parse2DeviceIntroductionInfo(response.data); + } + + /** + * 根据设备市场型号获取设备添加流程引导页配置信息,从本地缓存获取 这个接口不属于网络交互,需要移出去,放到Model里面 + * + * @param deviceModel + * @return + * @throws BusinessException + */ + public DeviceIntroductionInfo introductionInfosGetCache(String deviceModel) throws BusinessException { + return FileSaveHelper.getIntroductionInfoCache(deviceModel, "zh_CN"); + } + + /** + * openApi + * + * @param deviceId String 必须 设备序列号 + * @param code 必须 设备验证码 + * code统称为设备验证码,但是针对不同的设备传的code值也会不一样。需要判断所需绑定设备是否有auth能力级: + * 1.如果该设备有auth能力级,code值传设备初始化后的设备密码; + * 2.如果该设备没有auth能力级但是设备底部标签中(或二维码中)有6为数字的安全码,code值传该6位数字; + * 3.如果该设备没有auth能力级并且设备底部标签中(或二维码中)没有6为数字的安全码,则code值传空即可; + * 只支持绑定paas设备,故code只会传设备密码或者SC码 + * @param timeout + * @return + * @throws BusinessException + */ + public DeviceBindResult userDeviceBind(String deviceId, String code, int timeout) throws BusinessException { + BindDeviceData req=new BindDeviceData(); + req.data.token= LCDeviceEngine.newInstance().accessToken; + req.data.deviceId = deviceId; + req.data.code = code; + BindDeviceData.Response response = DeviceAddOpenApiManager.userDeviceBind(req); + DeviceBindResult deviceBindResult = new DeviceBindResult(); + deviceBindResult.setBindStatus(response.data.bindStatus); + deviceBindResult.setDeviceName(response.data.deviceName); + deviceBindResult.setUserAccount(response.data.userAccount); + return deviceBindResult; + } + + /** + * openApi + * 修改设备或者通道名,channelId为空则为修改设备名,不为空为修改通道名 + * + * @param deviceId String 必须 设备序列号 + * @param channelId String 可选 设备通道号 + * @param name String 必须 设备名称 + * @param timeout + * @return + * @throws BusinessException + */ + public boolean modifyDeviceName(String deviceId, String channelId, String name, int timeout) throws BusinessException { + ModifyDeviceNameData req=new ModifyDeviceNameData(); + req.data.token = LCDeviceEngine.newInstance().accessToken; + req.data.deviceId = deviceId; + if (!TextUtils.isEmpty(channelId)) { + req.data.channelId = channelId; + } + req.data.name = name; + ModifyDeviceNameData.Response response = DeviceAddOpenApiManager.modifyDeviceName(req); + return response != null; + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/FileSaveHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/FileSaveHelper.java new file mode 100644 index 0000000..ee5a9bf --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/service/FileSaveHelper.java @@ -0,0 +1,116 @@ +package com.mm.android.deviceaddmodule.service; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.mm.android.deviceaddmodule.LCDeviceEngine; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.BusinessException; +import com.mm.android.deviceaddmodule.mobilecommon.businesstip.BusinessErrorCode; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceIntroductionInfo; +import com.mm.android.deviceaddmodule.openapi.data.DeviceLeadingInfoData; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +/** + * 用于将服务返回信息保存成文件 + **/ +public class FileSaveHelper { + public static String INTRODUCTION_INFO_NAME="introduction.json"; //设备引导 + + public static void saveToJsonInfo(String content, String fileName){ + String directory = getCachePath(); + FileSaveHelper.writeToFile(content, directory, fileName); + } + + + public static DeviceIntroductionInfo getIntroductionInfoCache(String model, String lan) throws BusinessException { + // 读缓存 + String directory = getCachePath(); + String contentJson = getJsonFromFile(directory, model+"_"+lan+"_"+ FileSaveHelper.INTRODUCTION_INFO_NAME); + if (TextUtils.isEmpty(contentJson)) { + throw new BusinessException(BusinessErrorCode.BEC_COMMON_NULL_POINT); + } + + DeviceLeadingInfoData.Response response = null; + try { + Gson gson = new Gson(); + response = gson.fromJson(contentJson, + DeviceLeadingInfoData.Response.class); + } catch (Exception e) { + e.printStackTrace(); + throw new BusinessException(BusinessErrorCode.BEC_COMMON_NULL_POINT); + } + + if (response == null || response.data == null + || response.data.introductions == null) { + throw new BusinessException(BusinessErrorCode.BEC_COMMON_NULL_POINT); + } + + return DeviceAddEntityChangeHelper.parse2DeviceIntroductionInfo(response.data); + } + + private static String getCachePath() { + String userId = LCDeviceEngine.newInstance().userId; + return LCDeviceEngine.newInstance().commonParam.getContext().getFilesDir() + File.separator + userId + File.separator; + } + + private static void writeToFile(String content, String directory, String fileName) { + // mobile SD card path +path + BufferedWriter os = null; + File file = new File(directory); + try { + if (!file.exists()) { + if (!file.mkdirs()) { + return; + } + } + file = new File(file, fileName); + os = new BufferedWriter(new FileWriter(file), 1024); + os.write(content); + os.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private static String getJsonFromFile(String dirctory, String fileName) { + // mobile SD card path +path + BufferedReader os = null; + StringBuffer stringBuffer = new StringBuffer(); + File file = new File(dirctory, fileName); + try { + if (!file.exists()) { + return ""; + } + os = new BufferedReader(new FileReader(file)); + String line = ""; + while ((line = os.readLine()) != null) { + stringBuffer.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return stringBuffer.toString().trim(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/services/TimeFilterService.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/services/TimeFilterService.java new file mode 100644 index 0000000..50807cc --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/services/TimeFilterService.java @@ -0,0 +1,159 @@ +package com.mm.android.deviceaddmodule.services; + +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.wifi.WifiInfo; +import android.os.Build; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; + +import com.dahua.mobile.utility.network.DHNetworkUtil; +import com.dahua.mobile.utility.network.DHWifiUtil; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.AppConsume.ProviderManager; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.CloseTimeFilterEvent; +import com.mm.android.deviceaddmodule.mobilecommon.eventbus.event.NetWorkChangeCheckEvent; +import com.mm.android.deviceaddmodule.receiver.SucceedClickReceiver; +import com.mm.android.deviceaddmodule.receiver.TimeoutClickReceiver; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.Timer; +import java.util.TimerTask; + +@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) +public class TimeFilterService extends IntentService { + private static final String TAG = TimeFilterService.class.getSimpleName(); + private final static int WIFI_STATE_NOTIFY_ID = 2222; //通知ID + private static final int MAX = 40 * 1000;//40秒 + private Timer timer = new Timer(); + private DHWifiUtil mDHWifiUtil; + private String mNetSsid; + + + public TimeFilterService() { + super(TAG); + } + + @Override + public void onCreate() { + super.onCreate(); + mDHWifiUtil = new DHWifiUtil(this.getApplicationContext()); + } + + + @Override + protected void onHandleIntent(@Nullable Intent intent) { + if (intent == null) + return; + mNetSsid = intent.getStringExtra(LCConfiguration.SSID); + + if(!EventBus.getDefault().isRegistered(this)){ + EventBus.getDefault().register(this); + } + + if (timer==null){ + timer = new Timer(); + } + timer.schedule(new TimerTask() { + @Override + public void run() { + Intent intent = new Intent(); + intent.setClass(TimeFilterService.this,TimeoutClickReceiver.class); + showNotification(getString(R.string.application_name), getString(R.string.add_device_time_filter_tip), intent); + } + }, MAX); + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void noticeTimeFilterListener(CloseTimeFilterEvent event) { + closeService(); + } + + private void closeService(){ + if (timer != null) { + timer.cancel(); + timer = null; + } + if (EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().unregister(this); + } + } + + @Subscribe(threadMode = ThreadMode.ASYNC) + public void checkNetWorkChange(NetWorkChangeCheckEvent event){ + if(isHotWifiConnect()){ + Intent intent = new Intent(); + intent.setClass(TimeFilterService.this,SucceedClickReceiver.class); + showNotification(getString(R.string.application_name), getString(R.string.add_device_connect_finish_to_next), intent); + closeService(); + } + } + + //是否已连上设备热点 + public boolean isHotWifiConnect() { + boolean isWifiConnected = DHNetworkUtil.NetworkType.NETWORK_WIFI.equals(DHNetworkUtil.getNetworkType(this.getApplicationContext())); + WifiInfo wifiInfo = mDHWifiUtil.getCurrentWifiInfo(); + return !(wifiInfo == null) && wifiInfo.getSSID().equals("\"" + mNetSsid + "\""); + } + + private void showNotification(String title, String context, Intent intent) { + if(ProviderManager.getAppProvider().getAppType() != LCConfiguration.APP_LECHANGE_OVERSEA){ + return; + } + + NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + PendingIntent mPendingIntent = PendingIntent.getBroadcast(this,0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + Notification.Builder builder = null; + Notification.BigTextStyle style = new Notification.BigTextStyle(); + style.setBigContentTitle(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? + title : "");//标题设置为消息推送带过来的消息类型 + style.bigText(context);//设置推送消息富文本 + + String notificationId = "TimeFilterId"; + String notificationName = "TimeFilter"; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //26以上,必须设置ChannelId + NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH); + notifyManager.createNotificationChannel(channel); + builder = new Notification.Builder(this) + .setStyle(style) + .setSmallIcon(R.drawable.small_icon) + .setAutoCancel(true) + .setWhen(System.currentTimeMillis()) + .setShowWhen(true) + .setContentTitle(title) + .setContentText(context) + .setContentIntent(mPendingIntent) + .setChannelId(notificationId); + + } else { + builder = new Notification.Builder(this) + .setStyle(style) + .setSmallIcon(R.drawable.small_icon) + .setAutoCancel(true) + .setContentTitle(title) + .setWhen(System.currentTimeMillis()) + .setContentText(context) + .setContentIntent(mPendingIntent); + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ + builder.setShowWhen(true); + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){ + notifyManager.notify(WIFI_STATE_NOTIFY_ID, builder.build()); + } + } + + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/FileHelper.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/FileHelper.java new file mode 100644 index 0000000..67e5b0d --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/FileHelper.java @@ -0,0 +1,57 @@ +package com.mm.android.deviceaddmodule.utils; + + +import android.content.Context; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Created by 32716 on 2017/5/19. + */ +public class FileHelper { + + + + public static boolean isMP4File(String path) { + if (path.toLowerCase().endsWith(".mp4") || + path.toLowerCase().contains(".mp4")) { + return true; + } + return false; + } + + /** + * 重命名文件 + * + * @param oldFile + * @param newFile + * @return + */ + public static boolean renameFile(File oldFile, File newFile) { + if (oldFile.exists()) { + if (newFile.exists()) { + newFile.delete(); + } + return oldFile.renameTo(newFile); + } else { + return false; + } + } + + private static File getDataBaseFile(Context context, String dataBaseName) { + String dataBasePath = context.getApplicationContext().getDatabasePath(dataBaseName).getPath(); + return new File(dataBasePath); + } + + public static boolean updateDataBaseName(Context context, String oldName, String newName) { + File oldDataBaseFile = getDataBaseFile(context, oldName); + File newDataBaseFile = getDataBaseFile(context, newName); + return renameFile(oldDataBaseFile, newDataBaseFile); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/MD5Utility.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/MD5Utility.java new file mode 100644 index 0000000..ee937ce --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/MD5Utility.java @@ -0,0 +1,23 @@ +package com.mm.android.deviceaddmodule.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Utility { + + public static String getMD5(String val) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("md5"); + StringBuilder buffer = new StringBuilder(); + byte[] result = digest.digest(val.getBytes()); + for (byte b : result) { + int number = b & 0xff;//不按标准加密 + //转换成16进制 + String numberStr = Integer.toHexString(number); + if (numberStr.length() == 1) { + buffer.append("0"); + } + buffer.append(numberStr); + } //MD5加密结果 + return buffer.toString().toUpperCase(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/SDsolutionUtility.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/SDsolutionUtility.java new file mode 100644 index 0000000..07bdb15 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/utils/SDsolutionUtility.java @@ -0,0 +1,84 @@ +package com.mm.android.deviceaddmodule.utils; + +import android.content.Context; +import android.os.Build; +import android.os.Environment; + +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; + +import java.io.File; +import java.security.NoSuchAlgorithmException; + + +public class SDsolutionUtility { + + private static String mUsername; + private static String md5name; + private static String[] dirFolder = {"snapshot", "video", "mp4", "thumb", "facedetection", "cache", "temp"}; + private static String ALBUM_PATH = Environment.getExternalStorageDirectory() + File.separator; + + + private static Context mContext; + + + public static void initContext(Context context) { + mContext = context; + /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ALBUM_PATH = mContext.getExternalFilesDir("demo").getAbsolutePath(); + LogUtil.debugLog("rrrrr","ALBUM_PATH::"+ALBUM_PATH); + }*/ + } + + public static void createDir(String username) { + mUsername = username.toLowerCase(); + try { + //由于服务器不区分大小写,先统一将所有名字转成小写,再转MD5 + md5name = MD5Utility.getMD5(username.toLowerCase()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + String userPath = ALBUM_PATH + md5name; + String newUserPath = ALBUM_PATH; + File dirUserFile = new File(userPath); + File newDirUserFile = new File(newUserPath); + if (dirUserFile.exists()) { + FileHelper.renameFile(dirUserFile, newDirUserFile); + } + + + /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + for (int i = 0; i < dirFolder.length; i++) { + String path = ALBUM_PATH+File.separator +dirFolder[i]+File.separator; + LogUtil.debugLog("rrrrr","path::"+path); + File dirEasy4ipFile = new File(path); + if (!dirEasy4ipFile.exists()) { + dirEasy4ipFile.mkdirs(); + } + } + + } else {*/ + boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); + if (!sdCardExist) { + // + } else { + for (int i = 0; i < dirFolder.length; i++) { + String path = ALBUM_PATH + File.separator + dirFolder[i] + File.separator; + File dirEasy4ipFile = new File(path); + if (!dirEasy4ipFile.exists()) { + dirEasy4ipFile.mkdirs(); + } + } + } +// } + } + + + public static String getCachePath() { + return ALBUM_PATH + dirFolder[5] + File.separator; + } + + public static String getTempPath() { + return ALBUM_PATH + dirFolder[6] + File.separator; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/AddBoxTipDialog.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/AddBoxTipDialog.java new file mode 100644 index 0000000..a1fdb4b --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/AddBoxTipDialog.java @@ -0,0 +1,72 @@ +package com.mm.android.deviceaddmodule.views; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.CheckBox; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.base.BaseDialogFragment; +import com.mm.android.deviceaddmodule.mobilecommon.common.LCConfiguration; +import com.mm.android.deviceaddmodule.mobilecommon.utils.PreferencesHelper; + +/** + * 乐盒扫描二维码添加时的提示页面 + */ +public class AddBoxTipDialog extends BaseDialogFragment { + private PreferencesHelper mPreferencesHelper = null; + + private CheckBox mViewNotShow = null; + + private TextView mViewClose = null; + + + private DialogInterface.OnDismissListener mDismissListener; + + public void setDismissListener(DialogInterface.OnDismissListener dismissListener) { + this.mDismissListener = dismissListener; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // TODO Auto-generated method stub + Dialog dialog = new Dialog(getActivity(), R.style.checks_dialog); + LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.box_add_tip, null, false); + init(view); + dialog.setContentView(view); + return dialog; + } + + private void init(View mView) { + mPreferencesHelper = PreferencesHelper.getInstance(getActivity()); + mViewNotShow = mView.findViewById(R.id.not_show); + mViewClose = mView.findViewById(R.id.close); + mViewNotShow.setChecked(mPreferencesHelper.getBoolean(LCConfiguration.SHOW_ADD_BOX_TIP)); + mViewClose.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mViewNotShow.isChecked()) { + mPreferencesHelper.set(LCConfiguration.SHOW_ADD_BOX_TIP, true); + } else { + mPreferencesHelper.set(LCConfiguration.SHOW_ADD_BOX_TIP, false); + } + dismiss(); + } + + }); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (mDismissListener != null) { + mDismissListener.onDismiss(dialog); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/ChooseNetDialog.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/ChooseNetDialog.java new file mode 100644 index 0000000..e1fb3b0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/ChooseNetDialog.java @@ -0,0 +1,79 @@ +package com.mm.android.deviceaddmodule.views; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import com.mm.android.deviceaddmodule.R; + +public class ChooseNetDialog extends Dialog { + + public ChooseNetDialog(@NonNull Context context) { + super(context, R.style.sign_dialog); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +// requestWindowFeature(Window.FEATURE_NO_TITLE); // must be called before set content + setContentView(R.layout.dialog_choose_net); + setCanceledOnTouchOutside(true); + setCancelable(true); + // 设置宽度为屏宽、靠近屏幕底部。 + Window window = getWindow(); + WindowManager.LayoutParams wlp = window.getAttributes(); + wlp.gravity = Gravity.BOTTOM; + wlp.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(wlp); + findViewById(R.id.tv_softap).setOnClickListener(new mClickListener()); + findViewById(R.id.tv_wlan).setOnClickListener(new mClickListener()); + findViewById(R.id.tv_lan).setOnClickListener(new mClickListener()); + findViewById(R.id.tv_cancel).setOnClickListener(new mClickListener()); + } + + + private class mClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + int i = v.getId(); + if (i == R.id.tv_softap) { + if (lisenter != null) { + lisenter.softap(); + } + dismiss(); + } else if (i == R.id.tv_wlan) { + if (lisenter != null) { + lisenter.wlan(); + } + dismiss(); + } else if (i == R.id.tv_lan) { + if (lisenter != null) { + lisenter.lan(); + } + dismiss(); + } else if (i == R.id.tv_cancel) { + dismiss(); + } + } + } + + public interface OnChooseNetLisenter { + void softap();//软AP + + void wlan();//无线 + + void lan();//有线 + } + + OnChooseNetLisenter lisenter; + + public void setOnChooseNetLisenter(OnChooseNetLisenter lisenter) { + this.lisenter = lisenter; + } + +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/CircleCountDownView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/CircleCountDownView.java new file mode 100644 index 0000000..ac24940 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/CircleCountDownView.java @@ -0,0 +1,187 @@ +package com.mm.android.deviceaddmodule.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.UIUtils; + +/** + * 圆形倒计时控件 + **/ +public class CircleCountDownView extends View { + private int mRingColor; //圆轮颜色 + private int mCirbgColor; //圆形背景色 + private float mRingWidth; //圆轮宽度 + private int mRingProgessTextSize; //圆轮进度值文本大小 + private int mWidth; //宽度 + private int mHeight; //高度 + private Paint mPaint; + private RectF mRectF; //圆环的矩形区域 + private int mProgessTextColor; + private int mCountdownTime; + private float mCurrentProgress; + private OnCountDownFinishListener mListener; + ValueAnimator mValueAnimator; + private int mMiddleTime; //设置中间提醒时间,即0-CountdownTime之间的时间 + private boolean mHasMiddleTimeUp=false; + + public CircleCountDownView(Context context) { + super(context); + init(); + } + + public CircleCountDownView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initAttrs(context, attrs); + init(); + } + + public CircleCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + init(); + } + Paint textPaint; + private void init() { + textPaint = new Paint(); + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setAntiAlias(true); + mPaint.setColor(mRingColor); //颜色 + mPaint.setStyle(Paint.Style.STROKE); //空心 + mPaint.setStrokeWidth(mRingWidth); //宽度 + mCirbgColor = getResources().getColor(R.color.c6); + this.setWillNotDraw(false); + } + + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleCountDownView); + mRingColor = a.getColor(R.styleable.CircleCountDownView_ringColor, mCirbgColor); + mCirbgColor=a.getColor(R.styleable.CircleCountDownView_ringbgColor,mCirbgColor); + mRingWidth = a.getDimensionPixelSize(R.styleable.CircleCountDownView_ringWidth, UIUtils.dp2px(context, 10)); + mRingProgessTextSize = a.getDimensionPixelSize(R.styleable.CircleCountDownView_progressTextSize, UIUtils.sp2px(context, 25)); + mProgessTextColor = a.getColor(R.styleable.CircleCountDownView_progressTextColor, mCirbgColor); + mCountdownTime = a.getInteger(R.styleable.CircleCountDownView_countdownTime, 60); + a.recycle(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mWidth = getMeasuredWidth(); + mHeight = getMeasuredHeight(); + if(mRectF == null){ + mRectF = new RectF(0 + mRingWidth / 2, 0 + mRingWidth / 2, + mWidth - mRingWidth / 2, mHeight - mRingWidth / 2); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + mPaint.setColor(mCirbgColor); //颜色 + canvas.drawArc(mRectF, -90, -360, false, mPaint); + mPaint.setColor(mRingColor); //颜色 + canvas.drawArc(mRectF, -90, mCurrentProgress - 360, false, mPaint); + //绘制文本 + String text = mCountdownTime - (int) (mCurrentProgress / 360f * mCountdownTime)+""; + + textPaint.setAntiAlias(true); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setTextSize(mRingProgessTextSize); + textPaint.setFakeBoldText(true); + textPaint.setColor(mProgessTextColor); + + //文字居中显示 + Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt(); + int baseline = (int) ((mRectF.bottom + mRectF.top ) / 2); + canvas.drawText(text, mRectF.centerX(), baseline, textPaint); + textPaint.setFakeBoldText(false); + canvas.drawText("s",mRectF.centerX(), baseline-fontMetrics.bottom-fontMetrics.top+10, textPaint); + } + + private ValueAnimator getValA(long countdownTime) { + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); + valueAnimator.setDuration(countdownTime); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setRepeatCount(0); + return valueAnimator; + } + + public void setCountdownTime(int mCountdownTime) { + this.mCountdownTime = mCountdownTime; + } + + public void setMiddleTime(int middleTime){ + this.mMiddleTime=middleTime; + } + + /** + * 开始倒计时 + */ + public void startCountDown() { + mHasMiddleTimeUp=false; + setClickable(false); + mValueAnimator = getValA((long)mCountdownTime * 1000); + mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float i = Float.valueOf(String.valueOf(animation.getAnimatedValue())); + mCurrentProgress = (int) (360 * (i / 100f)); + int curTime = (int) (mCurrentProgress / 360f * mCountdownTime); + if (mMiddleTime > 0 + && curTime >= mMiddleTime + && !mHasMiddleTimeUp + && mListener != null) { + mListener.middleTimeUp(); + mHasMiddleTimeUp = true; + } + invalidate(); + } + }); + mValueAnimator.start(); + mValueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + //倒计时结束回调 + if (mListener != null) { + mListener.countDownFinished(); + } + setClickable(true); + } + + }); + } + + public int getCurCountdownTime() { + return mCountdownTime - (int) (mCurrentProgress / 360f * mCountdownTime); + } + + public void stopCountDown(){ + mListener=null; + if(mValueAnimator!=null) { + mValueAnimator.cancel(); + } + } + + public void setCountDownListener(OnCountDownFinishListener mListener) { + this.mListener = mListener; + } + + public interface OnCountDownFinishListener { + void countDownFinished(); + void middleTimeUp(); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/DrawableCenterTextView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/DrawableCenterTextView.java new file mode 100644 index 0000000..8464acd --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/DrawableCenterTextView.java @@ -0,0 +1,53 @@ +package com.mm.android.deviceaddmodule.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.widget.TextView; + +@SuppressLint("AppCompatCustomView") +public class DrawableCenterTextView extends TextView { + public DrawableCenterTextView(Context context) { + super(context); + } + + public DrawableCenterTextView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public DrawableCenterTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onDraw(Canvas canvas) { + Drawable[] drawables = getCompoundDrawables(); + if (drawables == null) { + super.onDraw(canvas); + } + for (int i = 0; i < drawables.length; i++) { + Drawable drawable = drawables[i]; + if (drawable != null) { + if (i == 0 || i == 2) { + int drawableWidth = drawable.getIntrinsicWidth(); + int drawablePadding = getCompoundDrawablePadding(); + int textWidth = (int) getPaint().measureText(getText().toString().trim()); + int bodyWidth = drawableWidth + drawablePadding + textWidth; + canvas.save(); + canvas.translate((getWidth() - bodyWidth) / 2, 0); + } else if (i == 1 || i == 3) { + int drawableHeight = drawable.getIntrinsicHeight(); + int drawablePadding = getCompoundDrawablePadding(); + int textHeight = (int) getPaint().measureText(getText().toString().trim()); + int bodyHeight = textHeight + drawablePadding + drawableHeight; + canvas.save(); + canvas.translate(0, (getHeight() - bodyHeight) / 2); + } + } + } + super.onDraw(canvas); + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/PullToRefreshStickyGridView.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/PullToRefreshStickyGridView.java new file mode 100644 index 0000000..19bbec0 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/PullToRefreshStickyGridView.java @@ -0,0 +1,94 @@ +package com.mm.android.deviceaddmodule.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.view.View; + +import com.lechange.pulltorefreshlistview.Mode; +import com.lechange.pulltorefreshlistview.Orientation; +import com.lechange.pulltorefreshlistview.OverscrollHelper; +import com.lechange.pulltorefreshlistview.PullToRefreshAdapterViewBase; +import com.lechange.pulltorefreshlistview.extras.ScrollChangedListener; +import com.lechange.pulltorefreshlistview.internal.EmptyViewMethodAccessor; +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.widget.sticky.stickygridheaders.StickyGridHeadersGridView; + +/** + * 带header的可下拉刷新的gridview + **/ +public class PullToRefreshStickyGridView extends PullToRefreshAdapterViewBase { + private ScrollChangedListener mScrollChangedListener; + + public PullToRefreshStickyGridView(Context context) { + super(context); + } + + public PullToRefreshStickyGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public PullToRefreshStickyGridView(Context context, Mode mode) { + super(context, mode); + } + + public PullToRefreshStickyGridView(Context context, Mode mode, AnimationStyle style) { + super(context, mode, style); + } + + public void setOnScrollChangedListener(ScrollChangedListener mScrollChangedListener) { + this.mScrollChangedListener = mScrollChangedListener; + } + + public final Orientation getPullToRefreshScrollDirection() { + return Orientation.VERTICAL; + } + + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + if (this.mScrollChangedListener != null) { + this.mScrollChangedListener.onScrollChanged(l, t, oldl, oldt); + } + + } + + protected final StickyGridHeadersGridView createRefreshableView(Context context, AttributeSet attrs) { + Object gv; + if (Build.VERSION.SDK_INT >= 9) { + gv = new PullToRefreshStickyGridView.InternalGridViewSDK9(context, attrs); + } else { + gv = new PullToRefreshStickyGridView.InternalGridView(context, attrs); + } + + ((StickyGridHeadersGridView)gv).setId(R.id.gridview); + return (StickyGridHeadersGridView)gv; + } + + @TargetApi(9) + final class InternalGridViewSDK9 extends PullToRefreshStickyGridView.InternalGridView { + public InternalGridViewSDK9(Context context, AttributeSet attrs) { + super(context, attrs); + } + + protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { + boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); + OverscrollHelper.overScrollBy(PullToRefreshStickyGridView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent); + return returnValue; + } + } + + class InternalGridView extends StickyGridHeadersGridView implements EmptyViewMethodAccessor { + public InternalGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setEmptyView(View emptyView) { + PullToRefreshStickyGridView.this.setEmptyView(emptyView); + } + + public void setEmptyViewInternal(View emptyView) { + super.setEmptyView(emptyView); + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/BasePopWindow.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/BasePopWindow.java new file mode 100644 index 0000000..036d2ef --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/BasePopWindow.java @@ -0,0 +1,37 @@ +package com.mm.android.deviceaddmodule.views.popwindow; + +import android.app.Activity; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.view.WindowManager; +import android.widget.PopupWindow; + +/** + * 弹出框基类 + */ +public abstract class BasePopWindow extends PopupWindow { + BasePopWindow(View view, int width, int height){ + super(view,width,height); + setFocusable(true); + setOutsideTouchable(true); + setBackgroundDrawable(new ColorDrawable(0)); + setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + + /** + * 绘制弹出框内容 + * @param activity + */ + public abstract void drawContent(Activity activity); + + public void drawContent(Activity activity,boolean isPort){ + + } + + + /** + * 更新弹出框 + * @param activity + */ + public abstract void updateContent(Activity activity,boolean isPort); +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/ChoseTypePopWindow.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/ChoseTypePopWindow.java new file mode 100644 index 0000000..035e473 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/ChoseTypePopWindow.java @@ -0,0 +1,102 @@ +package com.mm.android.deviceaddmodule.views.popwindow; + +import android.app.Activity; +import android.content.Context; +import android.support.v4.app.FragmentActivity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.adapter.CommonAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.List; + +public class ChoseTypePopWindow extends BasePopWindow implements AdapterView.OnItemClickListener { + ListView mOptionList; + OptionsAdapter mAdapter; + PopWindowFactory.PopWindowType mType; + List mData; + FragmentActivity mParent; + + ChoseTypePopWindow(View view, int width, int height) { + super(view, width, height); + mData = new ArrayList<>(); + } + + public void setType(PopWindowFactory.PopWindowType type) { + this.mType = type; + switch (type) { + case CHOSETYPE: + mData.add(R.string.add_device_add_by_wired); + mData.add(R.string.add_device_add_by_sound_wave); + mData.add(R.string.add_device_add_by_soft_ap); + mData.add(R.string.common_cancel); + break; + } + } + + @Override + public void drawContent(Activity activity) { + mParent = (FragmentActivity) activity; + View view = getContentView(); + mOptionList = view.findViewById(R.id.option_list); + + mAdapter = new OptionsAdapter(R.layout.option_item, mData, activity); + mOptionList.setAdapter(mAdapter); + mOptionList.setOnItemClickListener(this); + } + + @Override + public void updateContent(Activity activity, boolean isPort) { +} + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (position == 0) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRED_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + } else if (position == 1) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRELESS_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.WLAN); + } else if (position == 2) { + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_SOFTAP_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.SOFTAP); + } + dismiss(); +} + + class OptionsAdapter extends CommonAdapter { + + public OptionsAdapter(int layout, List list, Context mContext) { + super(layout, list, mContext); + } + + @Override + public void convert(ViewHolder viewHolder, Integer item, int position, ViewGroup parent) { + TextView optionName = (TextView) viewHolder.findViewById(R.id.option_name); + optionName.setText(item); + if (position == getCount() - 1) { + optionName.setTextColor(mContext.getResources().getColor(R.color.c12)); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)optionName.getLayoutParams(); + layoutParams.topMargin = 15; + optionName.setLayoutParams(layoutParams); + } else { + optionName.setTextColor(mContext.getResources().getColor(R.color.c2)); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)optionName.getLayoutParams(); + layoutParams.topMargin = 0; + optionName.setLayoutParams(layoutParams); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/LoadingPopWindow.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/LoadingPopWindow.java new file mode 100644 index 0000000..6256a99 --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/LoadingPopWindow.java @@ -0,0 +1,21 @@ +package com.mm.android.deviceaddmodule.views.popwindow; + +import android.app.Activity; +import android.view.View; + +public class LoadingPopWindow extends BasePopWindow { + LoadingPopWindow(View view, int width, int height) { + super(view, width, height); + setOutsideTouchable(false); + setFocusable(false); + } + + @Override + public void drawContent(Activity activity) { + } + + @Override + public void updateContent(Activity activity, boolean isPort) { + + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/MoreOptionsPopWindow.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/MoreOptionsPopWindow.java new file mode 100644 index 0000000..d2aefea --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/MoreOptionsPopWindow.java @@ -0,0 +1,151 @@ +package com.mm.android.deviceaddmodule.views.popwindow; + +import android.app.Activity; +import android.content.Context; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.event.DeviceAddEvent; +import com.mm.android.deviceaddmodule.mobilecommon.base.adapter.CommonAdapter; +import com.mm.android.deviceaddmodule.mobilecommon.common.ViewHolder; +import com.mm.android.deviceaddmodule.mobilecommon.entity.deviceadd.DeviceAddInfo; +import com.mm.android.deviceaddmodule.model.DeviceAddModel; +import com.mm.android.deviceaddmodule.p_inputsn.DeviceDispatchHelper; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.List; + +import static com.mm.android.deviceaddmodule.helper.PageNavigationHelper.SOFT_AP_TIP_TAG; +import static com.mm.android.deviceaddmodule.helper.PageNavigationHelper.TIP_POWER_FRAGMENT_TAG; + +public class MoreOptionsPopWindow extends BasePopWindow implements AdapterView.OnItemClickListener { + ListView mOptionList; + OptionsAdapter mAdapter; + PopWindowFactory.PopWindowType mType; + List mData; + FragmentActivity mParent; + + MoreOptionsPopWindow(View view, int width, int height) { + super(view, width, height); + mData = new ArrayList<>(); + } + + public void setType(PopWindowFactory.PopWindowType type) { + this.mType = type; + switch (type) { + case OPTION1: + mData.add(R.string.add_device_restart); + mData.add(R.string.common_cancel); + break; + case OPTION2: + mData.add(R.string.add_device_restart); + mData.add(R.string.add_device_switch_to_wired_add); + mData.add(R.string.common_cancel); + break; + case OPTION3: + mData.add(R.string.add_device_restart); + mData.add(R.string.add_device_switch_to_wireless_add); + mData.add(R.string.common_cancel); + break; + case OPTION4: + mData.add(R.string.add_device_restart); + mData.add(R.string.add_device_switch_to_soft_ap_add); + mData.add(R.string.common_cancel); + break; + } + } + + @Override + public void drawContent(Activity activity) { + mParent = (FragmentActivity) activity; + View view = getContentView(); + mOptionList = view.findViewById(R.id.option_list); + + mAdapter = new OptionsAdapter(R.layout.option_item, mData, activity); + mOptionList.setAdapter(mAdapter); + mOptionList.setOnItemClickListener(this); + } + + @Override + public void updateContent(Activity activity, boolean isPort) { + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (position == 0) { + if (DeviceAddModel.newInstance().getDeviceInfoCache().isWifiOfflineMode() + || DeviceAddInfo.DeviceAddType.HUB.equals(DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType())) { + mParent.finish(); //离线配网模式,重新开始直接退出 + } else { + DeviceDispatchHelper.setReAdd(true); + mParent.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + } else { + switch (mType) { + case OPTION2: + if (position == 1) { + DeviceDispatchHelper.setReAdd(true); + if(DeviceAddModel.newInstance().getDeviceInfoCache().getCurDeviceAddType() == DeviceAddInfo.DeviceAddType.SOFTAP){ + mParent.getSupportFragmentManager().popBackStackImmediate(SOFT_AP_TIP_TAG,1); + } else { + mParent.getSupportFragmentManager().popBackStackImmediate(TIP_POWER_FRAGMENT_TAG,1); + } + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRED_ACTION)); + + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.LAN); + } + break; + case OPTION3: + if (position == 1) { + DeviceDispatchHelper.setReAdd(true); + mParent.getSupportFragmentManager().popBackStackImmediate(TIP_POWER_FRAGMENT_TAG,1); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_WIRELESS_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.WLAN); + } + break; + case OPTION4: + if (position == 1) { + DeviceDispatchHelper.setReAdd(true); + mParent.getSupportFragmentManager().popBackStackImmediate(TIP_POWER_FRAGMENT_TAG,1); + EventBus.getDefault().post(new DeviceAddEvent(DeviceAddEvent.CHANGE_TO_SOFTAP_ACTION)); + DeviceAddModel.newInstance().getDeviceInfoCache().setCurDeviceAddType(DeviceAddInfo.DeviceAddType.SOFTAP); + } + break; + } + } + dismiss(); + } + + class OptionsAdapter extends CommonAdapter { + + public OptionsAdapter(int layout, List list, Context mContext) { + super(layout, list, mContext); + } + + @Override + public void convert(ViewHolder viewHolder, Integer item, int position, ViewGroup parent) { + TextView optionName = (TextView) viewHolder.findViewById(R.id.option_name); + optionName.setText(item); + if(position==getCount()-1){ + optionName.setTextColor(mContext.getResources().getColor(R.color.c12)); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)optionName.getLayoutParams(); + layoutParams.topMargin = 15; + optionName.setLayoutParams(layoutParams); + }else{ + optionName.setTextColor(mContext.getResources().getColor(R.color.c2)); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)optionName.getLayoutParams(); + layoutParams.topMargin = 0; + optionName.setLayoutParams(layoutParams); + } + } + } +} diff --git a/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/PopWindowFactory.java b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/PopWindowFactory.java new file mode 100644 index 0000000..4c9ff0a --- /dev/null +++ b/DeviceAddModule/src/main/java/com/mm/android/deviceaddmodule/views/popwindow/PopWindowFactory.java @@ -0,0 +1,135 @@ +package com.mm.android.deviceaddmodule.views.popwindow; + +import android.app.Activity; +import android.graphics.Rect; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.PopupWindow; +import android.widget.RelativeLayout; + +import com.mm.android.deviceaddmodule.R; +import com.mm.android.deviceaddmodule.mobilecommon.utils.LogUtil; +import com.mm.android.deviceaddmodule.mobilecommon.widget.CommonTitle; + +public class PopWindowFactory { + + private final String TAG=PopWindowFactory.this.getClass().getSimpleName(); + + public enum PopWindowType { + LOADING, //加载框 + OPTION1, //更多选项 + OPTION2, //切换有线 + OPTION3, //切换无线 + OPTION4, //切换软AP + OPTION5, //手动选择配网方式 + CHOSETYPE, //手动选择 + } + + public BasePopWindow createPopWindow(final Activity context, CommonTitle commonTitle, PopWindowType type) { + BasePopWindow popupWindow = null; + final WindowManager.LayoutParams params = context.getWindow().getAttributes(); + if (type != PopWindowType.LOADING) { + params.alpha = 0.5f;//设置popwindow弹出时背景 + context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);//兼容华为手机 + context.getWindow().setAttributes(params); + } + switch (type) { + case LOADING: + popupWindow = createLoadingPop(context, commonTitle); + break; + case OPTION1: + case OPTION2: + case OPTION3: + case OPTION4: + popupWindow = createOptionPop(context, type); + break; + case CHOSETYPE: + popupWindow = createTypeChosePop(context, type); + break; + default: + break; + } + + if (popupWindow != null) { + popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { + @Override + public void onDismiss() { + params.alpha = 1.0f; + context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + context.getWindow().setAttributes(params); + } + }); + } + return popupWindow; + } + + public BasePopWindow createLoadingPopWindow(final Activity context, View title) { + final WindowManager.LayoutParams params = context.getWindow().getAttributes(); + BasePopWindow popupWindow = createLoadingPop(context, (CommonTitle) title); + if (popupWindow != null) { + popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { + @Override + public void onDismiss() { + params.alpha = 1.0f; + context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + context.getWindow().setAttributes(params); + } + }); + } + return popupWindow; + } + + /** + * 加载框 + * + * @param context + * @return + */ + private BasePopWindow createLoadingPop(final Activity context, final CommonTitle commonTitle) { + View view = LayoutInflater.from(context).inflate(R.layout.common_progressdialog_layout1, null); + final BasePopWindow popupWindow = new LoadingPopWindow(view, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); + LogUtil.debugLog(TAG,"createLoadingPop--->" + popupWindow); + int[] location = new int[2]; + View decorView = context.getWindow().getDecorView(); + Rect rect = new Rect(); + decorView.getWindowVisibleDisplayFrame(rect); + int screenHeight = rect.bottom; + commonTitle.getLocationOnScreen(location); + int height = screenHeight - location[1] - commonTitle.getMeasuredHeight(); + popupWindow.setHeight(height); + popupWindow.showAsDropDown(commonTitle); + return popupWindow; + } + + /** + * 选项框 + * + * @param context + * @return + */ + private BasePopWindow createOptionPop(Activity context, PopWindowType type) { + View view = LayoutInflater.from(context).inflate(R.layout.more_options_layout, null); + BasePopWindow popupWindow = new MoreOptionsPopWindow(view, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + ((MoreOptionsPopWindow) popupWindow).setType(type); + popupWindow.showAtLocation(context.getWindow().getDecorView(), Gravity.BOTTOM, 0, 0); + popupWindow.drawContent(context); + return popupWindow; + } + + /** + * 选项框 + * + * @param context + * @return + */ + private BasePopWindow createTypeChosePop(Activity context, PopWindowType type) { + View view = LayoutInflater.from(context).inflate(R.layout.chose_type_layout, null); + BasePopWindow popupWindow = new ChoseTypePopWindow(view, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + ((ChoseTypePopWindow) popupWindow).setType(type); + popupWindow.showAtLocation(context.getWindow().getDecorView(), Gravity.BOTTOM, 0, 0); + popupWindow.drawContent(context); + return popupWindow; + } +} diff --git a/DeviceAddModule/src/main/res/anim/slide_in_from_bottom.xml b/DeviceAddModule/src/main/res/anim/slide_in_from_bottom.xml new file mode 100644 index 0000000..d68f21c --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_in_from_bottom.xml @@ -0,0 +1,7 @@ + + + + diff --git a/DeviceAddModule/src/main/res/anim/slide_in_from_top.xml b/DeviceAddModule/src/main/res/anim/slide_in_from_top.xml new file mode 100644 index 0000000..50214d9 --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_in_from_top.xml @@ -0,0 +1,7 @@ + + + + diff --git a/DeviceAddModule/src/main/res/anim/slide_in_right.xml b/DeviceAddModule/src/main/res/anim/slide_in_right.xml new file mode 100644 index 0000000..7f39cef --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/anim/slide_left_back_in.xml b/DeviceAddModule/src/main/res/anim/slide_left_back_in.xml new file mode 100644 index 0000000..df6979b --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_left_back_in.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/anim/slide_out_left.xml b/DeviceAddModule/src/main/res/anim/slide_out_left.xml new file mode 100644 index 0000000..b940d48 --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_out_left.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/anim/slide_out_to_bottom.xml b/DeviceAddModule/src/main/res/anim/slide_out_to_bottom.xml new file mode 100644 index 0000000..066ddcc --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_out_to_bottom.xml @@ -0,0 +1,7 @@ + + + + diff --git a/DeviceAddModule/src/main/res/anim/slide_out_to_top.xml b/DeviceAddModule/src/main/res/anim/slide_out_to_top.xml new file mode 100644 index 0000000..893a871 --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_out_to_top.xml @@ -0,0 +1,7 @@ + + + + diff --git a/DeviceAddModule/src/main/res/anim/slide_right_back_out.xml b/DeviceAddModule/src/main/res/anim/slide_right_back_out.xml new file mode 100644 index 0000000..0b967d0 --- /dev/null +++ b/DeviceAddModule/src/main/res/anim/slide_right_back_out.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/color/common_title_text_color.xml b/DeviceAddModule/src/main/res/color/common_title_text_color.xml new file mode 100644 index 0000000..e8d742f --- /dev/null +++ b/DeviceAddModule/src/main/res/color/common_title_text_color.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_flip.png b/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_flip.png new file mode 100644 index 0000000..0a2c0bd Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_flip.png differ diff --git a/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_rotate.png b/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_rotate.png new file mode 100644 index 0000000..dc641b7 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-hdpi/default_ptr_rotate.png differ diff --git a/DeviceAddModule/src/main/res/drawable-hdpi/indicator_arrow.png b/DeviceAddModule/src/main/res/drawable-hdpi/indicator_arrow.png new file mode 100644 index 0000000..8ae7977 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-hdpi/indicator_arrow.png differ diff --git a/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_flip.png b/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_flip.png new file mode 100644 index 0000000..be696c1 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_flip.png differ diff --git a/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_rotate.png b/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_rotate.png new file mode 100644 index 0000000..95b22bd Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-mdpi/default_ptr_rotate.png differ diff --git a/DeviceAddModule/src/main/res/drawable-mdpi/indicator_arrow.png b/DeviceAddModule/src/main/res/drawable-mdpi/indicator_arrow.png new file mode 100644 index 0000000..20fe2c1 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-mdpi/indicator_arrow.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/adddevice_icon_success_default.png b/DeviceAddModule/src/main/res/drawable-xhdpi/adddevice_icon_success_default.png new file mode 100644 index 0000000..922b7e0 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/adddevice_icon_success_default.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_flip.png b/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_flip.png new file mode 100644 index 0000000..3e6ddba Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_flip.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_rotate.png b/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_rotate.png new file mode 100644 index 0000000..00225c9 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/default_ptr_rotate.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/device_body_wifi_list_lock.png b/DeviceAddModule/src/main/res/drawable-xhdpi/device_body_wifi_list_lock.png new file mode 100644 index 0000000..a22f19f Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/device_body_wifi_list_lock.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal.png new file mode 100644 index 0000000..08b0d05 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal_lock.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal_lock.png new file mode 100644 index 0000000..05347ac Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_1singal_lock.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal.png new file mode 100644 index 0000000..16e488b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal_lock.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal_lock.png new file mode 100644 index 0000000..573d456 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_2singal_lock.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal.png new file mode 100644 index 0000000..c3052cc Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal_lock.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal_lock.png new file mode 100644 index 0000000..577af04 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_3singal_lock.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal.png new file mode 100644 index 0000000..145c3e5 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal_lock.png b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal_lock.png new file mode 100644 index 0000000..39901dc Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/devicedetail_wifi_nosingal_lock.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xhdpi/indicator_arrow.png b/DeviceAddModule/src/main/res/drawable-xhdpi/indicator_arrow.png new file mode 100644 index 0000000..810ff59 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xhdpi/indicator_arrow.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox.png new file mode 100644 index 0000000..2284f24 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox_checked.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox_checked.png new file mode 100644 index 0000000..0f27d8b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_box_checkbox_checked.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_default.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_default.png new file mode 100644 index 0000000..2b3a807 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_default.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_configurationfailure.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_configurationfailure.png new file mode 100644 index 0000000..fc4b0c7 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_configurationfailure.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_rest.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_rest.png new file mode 100644 index 0000000..af01f26 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_rest.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_undetectable.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_undetectable.png new file mode 100644 index 0000000..54f83bb Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_fail_undetectable.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_failhrlp_g1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_failhrlp_g1.png new file mode 100644 index 0000000..0032461 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_failhrlp_g1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_device_default.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_device_default.png new file mode 100644 index 0000000..9390c8c Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_device_default.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_devicepassword.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_devicepassword.png new file mode 100644 index 0000000..515c824 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_devicepassword.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_h.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_h.png new file mode 100644 index 0000000..68d934b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_h.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_n.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_n.png new file mode 100644 index 0000000..4b70b56 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_falshlight_n.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_help.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_help.png new file mode 100644 index 0000000..86771fe Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_help.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_hotspotexplain_fail.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_hotspotexplain_fail.png new file mode 100644 index 0000000..72ab5e0 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_hotspotexplain_fail.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_number.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_number.png new file mode 100644 index 0000000..5406894 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_number.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_photoalbum.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_photoalbum.png new file mode 100644 index 0000000..8c22180 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_photoalbum.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success.png new file mode 100644 index 0000000..06d7662 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success_background.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success_background.png new file mode 100644 index 0000000..25e7546 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_success_background.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_switchwifi.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_switchwifi.png new file mode 100644 index 0000000..49aca51 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_switchwifi.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain.png new file mode 100644 index 0000000..9a23d9b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain_choosewifi.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain_choosewifi.png new file mode 100644 index 0000000..1e12956 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifiexplain_choosewifi.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword.png new file mode 100644 index 0000000..09c9c7a Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_no5g.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_no5g.png new file mode 100644 index 0000000..deea453 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_no5g.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_nosupport5g.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_nosupport5g.png new file mode 100644 index 0000000..519fd13 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_icon_wifipassword_nosupport5g.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_battery.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_battery.png new file mode 100644 index 0000000..1d0f3b9 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_battery.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_closeto.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_closeto.png new file mode 100644 index 0000000..4dc93fb Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_closeto.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_cloudserver.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_cloudserver.png new file mode 100644 index 0000000..42641aa Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_cloudserver.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_1.png new file mode 100644 index 0000000..e32be8d Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_2.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_2.png new file mode 100644 index 0000000..e03be2a Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_2.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_3.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_3.png new file mode 100644 index 0000000..7b9d554 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_3.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud1.png new file mode 100644 index 0000000..e1e8da3 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud2.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud2.png new file mode 100644 index 0000000..ec2fa20 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectcloud_cloud2.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter.png new file mode 100644 index 0000000..3fb1ab9 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_1.png new file mode 100644 index 0000000..fc24dea Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_2.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_2.png new file mode 100644 index 0000000..39b9abd Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_2.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_3.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_3.png new file mode 100644 index 0000000..01e841b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_3.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_4.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_4.png new file mode 100644 index 0000000..dc6bbe1 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectrouter_4.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi.png new file mode 100644 index 0000000..08392e8 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi_config.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi_config.png new file mode 100644 index 0000000..d95f8be Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_connectwifi_config.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection.png new file mode 100644 index 0000000..37a258d Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection_1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection_1.png new file mode 100644 index 0000000..368c3c0 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_detection_1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_near.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_near.png new file mode 100644 index 0000000..3e02abe Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_near.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_networkcable.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_networkcable.png new file mode 100644 index 0000000..358ba1c Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_networkcable.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing.png new file mode 100644 index 0000000..914190e Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_1.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_1.png new file mode 100644 index 0000000..69c5034 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_1.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_2.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_2.png new file mode 100644 index 0000000..ed5deb3 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_netsetting_pairing_2.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_imei.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_imei.png new file mode 100644 index 0000000..3f13367 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_imei.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_qrcode.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_qrcode.png new file mode 100644 index 0000000..8536c72 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_qrcode.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_safetycode.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_safetycode.png new file mode 100644 index 0000000..ae517b7 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_safetycode.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_scanqrcode.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_scanqrcode.png new file mode 100644 index 0000000..b622a7e Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_scanqrcode.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_serialnumber.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_serialnumber.png new file mode 100644 index 0000000..4e34262 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_pic_serialnumber.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_qrcode_scanline.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_qrcode_scanline.png new file mode 100644 index 0000000..a35bd24 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_qrcode_scanline.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_samenet.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_samenet.png new file mode 100644 index 0000000..6308f43 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_samenet.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_setting_icon_copy.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_setting_icon_copy.png new file mode 100644 index 0000000..d3bacf8 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_setting_icon_copy.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_supportsoftap.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_supportsoftap.png new file mode 100644 index 0000000..b40cc6b Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/adddevice_supportsoftap.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_back.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_back.png new file mode 100644 index 0000000..4d9da30 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_back.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_more.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_more.png new file mode 100644 index 0000000..3c7a974 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_icon_nav_more.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/common_nullpic_nonetwork.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_nullpic_nonetwork.png new file mode 100644 index 0000000..23d9e0f Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/common_nullpic_nonetwork.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_clear.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_clear.png new file mode 100644 index 0000000..a8a76d5 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_clear.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_invisible.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_invisible.png new file mode 100644 index 0000000..f6f6977 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_invisible.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_visible.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_visible.png new file mode 100644 index 0000000..e4119fb Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/ic_password_visible.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/icon_floors.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/icon_floors.png new file mode 100644 index 0000000..19aee4c Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/icon_floors.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/lc_operation_step.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/lc_operation_step.png new file mode 100644 index 0000000..347a3c9 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/lc_operation_step.png differ diff --git a/DeviceAddModule/src/main/res/drawable-xxhdpi/mobile_common_common_pic_nointernet.png b/DeviceAddModule/src/main/res/drawable-xxhdpi/mobile_common_common_pic_nointernet.png new file mode 100644 index 0000000..f4d0289 Binary files /dev/null and b/DeviceAddModule/src/main/res/drawable-xxhdpi/mobile_common_common_pic_nointernet.png differ diff --git a/DeviceAddModule/src/main/res/drawable/adddevice_icon_wifipassword_nosupport5g_layer.xml b/DeviceAddModule/src/main/res/drawable/adddevice_icon_wifipassword_nosupport5g_layer.xml new file mode 100644 index 0000000..f369026 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/adddevice_icon_wifipassword_nosupport5g_layer.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/checkbox_btn_addbox_tip_selector.xml b/DeviceAddModule/src/main/res/drawable/checkbox_btn_addbox_tip_selector.xml new file mode 100644 index 0000000..a898729 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/checkbox_btn_addbox_tip_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/checkbox_btn_message_selector.xml b/DeviceAddModule/src/main/res/drawable/checkbox_btn_message_selector.xml new file mode 100644 index 0000000..a898729 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/checkbox_btn_message_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/checkbox_btn_wifi_selector.xml b/DeviceAddModule/src/main/res/drawable/checkbox_btn_wifi_selector.xml new file mode 100644 index 0000000..52a158c --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/checkbox_btn_wifi_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/cloud_connecting.xml b/DeviceAddModule/src/main/res/drawable/cloud_connecting.xml new file mode 100644 index 0000000..38cb333 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/cloud_connecting.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/common_border_bg.xml b/DeviceAddModule/src/main/res/drawable/common_border_bg.xml new file mode 100644 index 0000000..8564cbe --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_border_bg.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/common_border_bg_normal.xml b/DeviceAddModule/src/main/res/drawable/common_border_bg_normal.xml new file mode 100644 index 0000000..fac9732 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_border_bg_normal.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_gray.xml b/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_gray.xml new file mode 100644 index 0000000..fd399be --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_gray.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_white.xml b/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_white.xml new file mode 100644 index 0000000..ade5ed1 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_btn_bg_shape_white.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_image_nav_refresh_selector.xml b/DeviceAddModule/src/main/res/drawable/common_image_nav_refresh_selector.xml new file mode 100644 index 0000000..1e99f80 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_image_nav_refresh_selector.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_list_item_bg_h.xml b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_h.xml new file mode 100644 index 0000000..694925c --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_h.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/common_list_item_bg_n.xml b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_n.xml new file mode 100644 index 0000000..9f413c6 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_n.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/common_list_item_bg_selector.xml b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_selector.xml new file mode 100644 index 0000000..e606aa1 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_list_item_bg_selector.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_switch_btn_selector.xml b/DeviceAddModule/src/main/res/drawable/common_switch_btn_selector.xml new file mode 100644 index 0000000..3975168 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_switch_btn_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/common_title_refresh_selector.xml b/DeviceAddModule/src/main/res/drawable/common_title_refresh_selector.xml new file mode 100644 index 0000000..c1f9bdb --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/common_title_refresh_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/icon_wifipassword_nosupport5g.xml b/DeviceAddModule/src/main/res/drawable/icon_wifipassword_nosupport5g.xml new file mode 100644 index 0000000..f369026 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/icon_wifipassword_nosupport5g.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/indicator_bg_bottom.xml b/DeviceAddModule/src/main/res/drawable/indicator_bg_bottom.xml new file mode 100644 index 0000000..7c2c0eb --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/indicator_bg_bottom.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/indicator_bg_top.xml b/DeviceAddModule/src/main/res/drawable/indicator_bg_top.xml new file mode 100644 index 0000000..85a322d --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/indicator_bg_top.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_disabled_bg.xml b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_disabled_bg.xml new file mode 100644 index 0000000..0bf8841 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_disabled_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_normal_bg.xml b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_normal_bg.xml new file mode 100644 index 0000000..302bcbb --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_normal_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_pressed_bg.xml b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_pressed_bg.xml new file mode 100644 index 0000000..0bf8841 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_pressed_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_selector.xml b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_selector.xml new file mode 100644 index 0000000..4912f4c --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/lc_standard_big_btn_selector.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/leba_bg_single_unselected.xml b/DeviceAddModule/src/main/res/drawable/leba_bg_single_unselected.xml new file mode 100644 index 0000000..9f413c6 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/leba_bg_single_unselected.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/message_system_list_item_divider.xml b/DeviceAddModule/src/main/res/drawable/message_system_list_item_divider.xml new file mode 100644 index 0000000..6f688b2 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/message_system_list_item_divider.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_bg_btn_border_shape.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_bg_btn_border_shape.xml new file mode 100644 index 0000000..47fb7f0 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_bg_btn_border_shape.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_next_btn_selector.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_next_btn_selector.xml new file mode 100644 index 0000000..8720258 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_next_btn_selector.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_progress_style.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_progress_style.xml new file mode 100644 index 0000000..aa10feb --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_progress_style.xml @@ -0,0 +1,7 @@ + + + diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_radius_5dp_white_bg.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_radius_5dp_white_bg.xml new file mode 100644 index 0000000..357a04f --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_radius_5dp_white_bg.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_share_selector.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_share_selector.xml new file mode 100644 index 0000000..c55fae4 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_share_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/mobile_common_title_back.xml b/DeviceAddModule/src/main/res/drawable/mobile_common_title_back.xml new file mode 100644 index 0000000..2721a26 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/mobile_common_title_back.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/progress_style.xml b/DeviceAddModule/src/main/res/drawable/progress_style.xml new file mode 100644 index 0000000..aa10feb --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/progress_style.xml @@ -0,0 +1,7 @@ + + + diff --git a/DeviceAddModule/src/main/res/drawable/selector_orange_textview.xml b/DeviceAddModule/src/main/res/drawable/selector_orange_textview.xml new file mode 100644 index 0000000..668c668 --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/selector_orange_textview.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/shape_corners_edittext_1dp_normal.xml b/DeviceAddModule/src/main/res/drawable/shape_corners_edittext_1dp_normal.xml new file mode 100644 index 0000000..348ffdf --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/shape_corners_edittext_1dp_normal.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/drawable/text_cursor_drawable.xml b/DeviceAddModule/src/main/res/drawable/text_cursor_drawable.xml new file mode 100644 index 0000000..839eada --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/text_cursor_drawable.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/DeviceAddModule/src/main/res/drawable/wifi_connecting.xml b/DeviceAddModule/src/main/res/drawable/wifi_connecting.xml new file mode 100644 index 0000000..433290e --- /dev/null +++ b/DeviceAddModule/src/main/res/drawable/wifi_connecting.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/DeviceAddModule/src/main/res/layout/activity_device_hidden_wifi.xml b/DeviceAddModule/src/main/res/layout/activity_device_hidden_wifi.xml new file mode 100644 index 0000000..003c22e --- /dev/null +++ b/DeviceAddModule/src/main/res/layout/activity_device_hidden_wifi.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/layout/activity_device_lcadd.xml b/DeviceAddModule/src/main/res/layout/activity_device_lcadd.xml new file mode 100644 index 0000000..e4664cd --- /dev/null +++ b/DeviceAddModule/src/main/res/layout/activity_device_lcadd.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/layout/activity_device_wifi_list.xml b/DeviceAddModule/src/main/res/layout/activity_device_wifi_list.xml new file mode 100644 index 0000000..fa4f307 --- /dev/null +++ b/DeviceAddModule/src/main/res/layout/activity_device_wifi_list.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DeviceAddModule/src/main/res/layout/activity_device_wifi_password.xml b/DeviceAddModule/src/main/res/layout/activity_device_wifi_password.xml new file mode 100644 index 0000000..cc9fd52 --- /dev/null +++ b/DeviceAddModule/src/main/res/layout/activity_device_wifi_password.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +