├── .gitignore ├── .idea ├── .name ├── codeStyles │ └── Project.xml ├── dictionaries │ └── Caffreyfans.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── activeandroid-3.1.0-SNAPSHOT.jar ├── proguard-rules.pro ├── release-key │ └── irbaby.jks ├── release │ └── output.json └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── caffreyfans │ │ └── irbaby │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── litepal.xml │ ├── ic_launcher-web.png │ ├── java │ │ └── top │ │ │ └── caffreyfans │ │ │ └── irbaby │ │ │ ├── IRApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── adapter │ │ │ ├── ApplianceListAdapter.java │ │ │ ├── AppliancesSelectAdapter.java │ │ │ ├── DeviceAdapter.java │ │ │ └── InfoAdapter.java │ │ │ ├── firmware_api │ │ │ ├── Api.java │ │ │ ├── IRbabyApi.java │ │ │ ├── MqttApi.java │ │ │ └── UdpApi.java │ │ │ ├── helper │ │ │ ├── ApplianceContract.java │ │ │ ├── NotifyMsgEntity.java │ │ │ ├── UIUtils.java │ │ │ ├── UdpNotifyManager.java │ │ │ ├── UdpReceiveThread.java │ │ │ └── UdpSendThread.java │ │ │ ├── model │ │ │ ├── ApplianceInfo.java │ │ │ └── DeviceInfo.java │ │ │ └── ui │ │ │ ├── about │ │ │ └── AboutFragment.java │ │ │ ├── appliances │ │ │ ├── ACControlActivity.java │ │ │ ├── ApplianceFragment.java │ │ │ ├── ApplianceSelectActivity.java │ │ │ ├── DIYControlActivity.java │ │ │ └── ExportActivity.java │ │ │ ├── devices │ │ │ ├── DeviceFragment.java │ │ │ ├── DeviceInfoActivity.java │ │ │ ├── DeviceSelectActivity.java │ │ │ └── DeviceSettingsActivity.java │ │ │ ├── record │ │ │ ├── RecordActivity.java │ │ │ └── RecordFragment.java │ │ │ └── share │ │ │ ├── ShareFragment.java │ │ │ └── ShareViewModel.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ac_button_selected_background.xml │ │ ├── ic_air_conditioner.xml │ │ ├── ic_appliance.xml │ │ ├── ic_auto.xml │ │ ├── ic_box.xml │ │ ├── ic_cool.xml │ │ ├── ic_cpu.xml │ │ ├── ic_device.xml │ │ ├── ic_diy.xml │ │ ├── ic_dvd.xml │ │ ├── ic_fan.xml │ │ ├── ic_heat.xml │ │ ├── ic_info.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_menu_about.xml │ │ ├── ic_menu_camera.xml │ │ ├── ic_menu_gallery.xml │ │ ├── ic_menu_manage.xml │ │ ├── ic_menu_share.xml │ │ ├── ic_pen.xml │ │ ├── ic_power.xml │ │ ├── ic_record_ir.xml │ │ ├── ic_trash.xml │ │ ├── ic_tv.xml │ │ ├── ic_water.xml │ │ └── side_nav_bar.xml │ │ ├── font │ │ └── sriracha.xml │ │ ├── layout │ │ ├── activity_appliance_ac_control.xml │ │ ├── activity_appliance_select.xml │ │ ├── activity_device_info.xml │ │ ├── activity_device_settings.xml │ │ ├── activity_diycontrol.xml │ │ ├── activity_export.xml │ │ ├── activity_main.xml │ │ ├── activity_record.xml │ │ ├── app_bar_main.xml │ │ ├── appliance_list_item.xml │ │ ├── appliance_select_item.xml │ │ ├── content_main.xml │ │ ├── device_list_item.xml │ │ ├── fragment_about.xml │ │ ├── fragment_appliance.xml │ │ ├── fragment_device.xml │ │ ├── fragment_share.xml │ │ ├── fragment_slideshow.xml │ │ ├── fragment_tools.xml │ │ ├── info_list_item.xml │ │ └── nav_header_main.xml │ │ ├── menu │ │ ├── activity_main_drawer.xml │ │ ├── appliance_control.xml │ │ └── main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── mobile_navigation.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── font_certs.xml │ │ ├── ic_launcher_background.xml │ │ ├── preloaded_fonts.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── top │ └── caffreyfans │ └── irbaby │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── licenses ├── android-sdk-arm-dbt-license ├── android-sdk-license └── android-sdk-preview-license ├── settings.gradle └── web-api ├── .gitignore ├── README.md ├── build.gradle ├── libs ├── gson-2.8.0.jar ├── okhttp-3.7.0.jar └── okio-1.12.0.jar ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java └── net └── irext └── webapi ├── WebAPICallbacks.java ├── WebAPIs.java ├── bean ├── ACStatus.java └── TemperatureRange.java ├── model ├── Brand.java ├── Category.java ├── City.java ├── RemoteIndex.java ├── StbOperator.java └── UserApp.java ├── request ├── AppSignInRequest.java ├── BaseRequest.java ├── DecodeRequest.java ├── DownloadBinaryRequest.java ├── ListBrandsRequest.java ├── ListCategoriesRequest.java ├── ListCitiesRequest.java ├── ListIndexesRequest.java └── ListOperatorsRequest.java ├── response ├── BrandsResponse.java ├── CategoriesResponse.java ├── CitiesResponse.java ├── DecodeResponse.java ├── IndexesResponse.java ├── LoginResponse.java ├── OperatorsResponse.java ├── ServiceResponse.java └── Status.java └── utils ├── Constants.java ├── MD5Digest.java └── PackageUtils.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | IRbaby -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/dictionaries/Caffreyfans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | android: 3 | compenents: 4 | - build-tools-29.0.3 5 | - android-29 6 | - extra-android-m2repository 7 | - extra-android-support 8 | 9 | before_install: 10 | - chmod +x gradlew 11 | - curl https://gist.githubusercontent.com/noamtamim/b04ef67239d2b43638aa5a9a024a1937/raw/56f1a38dd88a3774b71a063822444f3961d61873/android-sdk-license.sh | sh 12 | 13 | script: 14 | - ./gradlew assembleRelease 15 | - cp ./app/build/outputs/apk/release/app-release.apk ./IRbaby.apk 16 | 17 | deploy: 18 | provider: releases 19 | api_key: "$TOKEN" 20 | file: ./IRbaby.apk 21 | skip_cleanup: true 22 | on: 23 | tags: true 24 | all_branches: true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Caffreyfans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IRbaby-android 2 | 3 | IRbaby Android client for matching infrared appliances and setting module information -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion 29 6 | buildToolsVersion '29.0.3' 7 | defaultConfig { 8 | applicationId "top.caffreyfans.irbaby" 9 | minSdkVersion 19 10 | targetSdkVersion 29 11 | versionCode 9 12 | versionName "v0.9" 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | 16 | signingConfigs { 17 | release { 18 | storeFile file("release-key/irbaby.jks") 19 | keyAlias("key0") 20 | keyPassword("as13348848836") 21 | storePassword("as13348848836") 22 | } 23 | } 24 | 25 | buildTypes { 26 | debug { 27 | debuggable = true 28 | jniDebuggable = true 29 | } 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 33 | signingConfig signingConfigs.release 34 | } 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | implementation 'androidx.appcompat:appcompat:1.1.0' 41 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 42 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 43 | implementation 'com.google.android.material:material:1.1.0' 44 | implementation 'androidx.navigation:navigation-fragment:2.2.1' 45 | implementation 'androidx.navigation:navigation-ui:2.2.1' 46 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 47 | implementation 'androidx.gridlayout:gridlayout:1.0.0' 48 | implementation project(path: ':web-api') 49 | implementation "com.daimajia.swipelayout:library:1.2.0@aar" 50 | implementation 'org.litepal.android:java:3.0.0' 51 | implementation files('libs/activeandroid-3.1.0-SNAPSHOT.jar') 52 | implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.1' 53 | implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' 54 | implementation 'org.jetbrains:annotations-java5:15.0' 55 | } 56 | -------------------------------------------------------------------------------- /app/libs/activeandroid-3.1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caffreyfans/IRbaby-android/244c764feed6cfe876b6563d29c6567bb40a11b4/app/libs/activeandroid-3.1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/release-key/irbaby.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caffreyfans/IRbaby-android/244c764feed6cfe876b6563d29c6567bb40a11b4/app/release-key/irbaby.jks -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":4,"versionName":"v0.4","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/androidTest/java/top/caffreyfans/irbaby/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("top.caffreyfans.irbaby", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 44 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/assets/litepal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caffreyfans/IRbaby-android/244c764feed6cfe876b6563d29c6567bb40a11b4/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/IRApplication.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby; 2 | 3 | import android.util.Log; 4 | 5 | import com.activeandroid.ActiveAndroid; 6 | import net.irext.webapi.WebAPIs; 7 | import net.irext.webapi.utils.PackageUtils; 8 | 9 | import org.litepal.LitePal; 10 | 11 | import top.caffreyfans.irbaby.helper.UdpReceiveThread; 12 | 13 | public class IRApplication extends com.activeandroid.app.Application { 14 | 15 | private static final String TAG = IRApplication.class.getSimpleName(); 16 | private static final String ADDRESS = "http://irext.net"; 17 | private static final String APP_NAME = "/irext-server"; 18 | 19 | public WebAPIs mWeAPIs = WebAPIs.getInstance(ADDRESS, APP_NAME); 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | 25 | // initialize ActiveAndroid 26 | ActiveAndroid.initialize(this); 27 | LitePal.initialize(this); 28 | 29 | 30 | // login with guest-admin account 31 | new Thread() { 32 | @Override 33 | public void run() { 34 | mWeAPIs.signIn(IRApplication.this); 35 | } 36 | }.start(); 37 | 38 | new UdpReceiveThread().start(); 39 | 40 | Log.d(TAG, "onCreate: " + PackageUtils.getCertificateSHA1Fingerprint(this)); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/MainActivity.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.navigation.NavController; 6 | import androidx.navigation.Navigation; 7 | import androidx.navigation.ui.AppBarConfiguration; 8 | import androidx.navigation.ui.NavigationUI; 9 | 10 | import com.google.android.material.navigation.NavigationView; 11 | 12 | import androidx.drawerlayout.widget.DrawerLayout; 13 | 14 | import androidx.appcompat.app.AppCompatActivity; 15 | import androidx.appcompat.widget.Toolbar; 16 | 17 | import android.os.Handler; 18 | import android.view.Menu; 19 | 20 | import org.litepal.LitePal; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | 24 | private AppBarConfiguration mAppBarConfiguration; 25 | private static Handler handler; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | Toolbar toolbar = findViewById(R.id.toolbar); 32 | setSupportActionBar(toolbar); 33 | 34 | DrawerLayout drawer = findViewById(R.id.drawer_layout); 35 | NavigationView navigationView = findViewById(R.id.nav_view); 36 | // Passing each menu ID as a set of Ids because each 37 | // menu should be considered as top level destinations. 38 | mAppBarConfiguration = new AppBarConfiguration.Builder( 39 | R.id.nav_appliance, R.id.nav_device, R.id.nav_ir_record, 40 | R.id.nav_share, R.id.nav_about) 41 | .setDrawerLayout(drawer) 42 | .build(); 43 | NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); 44 | NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); 45 | NavigationUI.setupWithNavController(navigationView, navController); 46 | 47 | /* main activity handler */ 48 | handler = new Handler(); 49 | 50 | LitePal.getDatabase(); 51 | } 52 | 53 | @Override 54 | public boolean onCreateOptionsMenu(Menu menu) { 55 | // Inflate the menu; this adds items to the action bar if it is present. 56 | // getMenuInflater().inflate(R.menu.main, menu); 57 | return true; 58 | } 59 | 60 | @Override 61 | public boolean onSupportNavigateUp() { 62 | NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); 63 | return NavigationUI.navigateUp(navController, mAppBarConfiguration) 64 | || super.onSupportNavigateUp(); 65 | } 66 | 67 | public static int getMainThreadId(){ 68 | return android.os.Process.myPid(); 69 | } 70 | 71 | public static Handler getHandler(){ 72 | return handler; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/adapter/ApplianceListAdapter.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageButton; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.daimajia.swipe.SwipeLayout; 13 | import com.daimajia.swipe.adapters.BaseSwipeAdapter; 14 | import net.irext.webapi.utils.Constants.CategoryID; 15 | import org.litepal.LitePal; 16 | import java.io.Serializable; 17 | import java.util.List; 18 | import top.caffreyfans.irbaby.R; 19 | import top.caffreyfans.irbaby.firmware_api.IRbabyApi; 20 | import top.caffreyfans.irbaby.helper.ApplianceContract; 21 | import top.caffreyfans.irbaby.model.ApplianceInfo; 22 | import top.caffreyfans.irbaby.ui.appliances.ACControlActivity; 23 | import top.caffreyfans.irbaby.ui.appliances.DIYControlActivity; 24 | 25 | public class ApplianceListAdapter extends BaseSwipeAdapter { 26 | private final String TAG = ApplianceListAdapter.class.getSimpleName(); 27 | private List mAppliancesInfoList; 28 | private Context mContext; 29 | public ApplianceListAdapter(Context context, List applianceInfos) { 30 | 31 | mContext = context; 32 | mAppliancesInfoList = applianceInfos; 33 | } 34 | 35 | @Override 36 | public int getSwipeLayoutResourceId(int position) { 37 | return R.id.swipe; 38 | } 39 | 40 | @Override 41 | public View generateView(int position, ViewGroup parent) { 42 | View v = LayoutInflater.from(mContext).inflate(R.layout.appliance_list_item, null); 43 | return v; 44 | } 45 | 46 | @Override 47 | public void fillValues(final int position, View convertView) { 48 | 49 | TextView textView = (TextView) convertView.findViewById(R.id.item_ip_tv); 50 | ImageView imageView = (ImageView) convertView.findViewById(R.id.item_icon_img); 51 | textView.setText(mAppliancesInfoList.get(position).getName()); 52 | int i = mAppliancesInfoList.get(position).getCategory() - 1; 53 | CategoryID categoryID = CategoryID.values()[i]; 54 | switch (categoryID) { 55 | case AIR_CONDITIONER: 56 | imageView.setImageResource(R.drawable.ic_air_conditioner); 57 | break; 58 | 59 | case TV: 60 | imageView.setImageResource(R.drawable.ic_tv); 61 | break; 62 | 63 | case FAN: 64 | imageView.setImageResource(R.drawable.ic_fan); 65 | break; 66 | case DIY: 67 | imageView.setImageResource(R.drawable.ic_diy); 68 | break; 69 | } 70 | final SwipeLayout swipeLayout = (SwipeLayout) convertView.findViewById(R.id.swipe); 71 | swipeLayout.getSurfaceView().setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | int i = mAppliancesInfoList.get(position).getCategory() - 1; 75 | CategoryID categoryID = CategoryID.values()[i]; 76 | Intent intent; 77 | switch (categoryID) { 78 | case AIR_CONDITIONER: 79 | intent = new Intent(mContext, ACControlActivity.class); 80 | break; 81 | case DIY: 82 | intent = new Intent(mContext, DIYControlActivity.class); 83 | break; 84 | default: 85 | throw new IllegalStateException("Unexpected value: " + categoryID); 86 | } 87 | intent.putExtra(ApplianceContract.Control.APPLIANCE_INFO, 88 | (Serializable) mAppliancesInfoList.get(position)); 89 | mContext.startActivity(intent); 90 | } 91 | }); 92 | 93 | ImageButton imageButton = convertView.findViewById(R.id.trash); 94 | imageButton.setOnClickListener(new View.OnClickListener() { 95 | @Override 96 | public void onClick(View v) { 97 | LitePal.delete(ApplianceInfo.class, mAppliancesInfoList.get(position).getId()); 98 | IRbabyApi iRbabyApi = new IRbabyApi(mContext, null, mAppliancesInfoList.get(position)); 99 | iRbabyApi.registerDevice(mAppliancesInfoList.get(position).getFile(), CategoryID.AIR_CONDITIONER, false); 100 | mAppliancesInfoList.remove(position); 101 | swipeLayout.close(); 102 | notifyDataSetChanged(); 103 | } 104 | }); 105 | } 106 | 107 | @Override 108 | public int getCount() { 109 | return mAppliancesInfoList.size(); 110 | } 111 | 112 | @Override 113 | public Object getItem(int position) { 114 | return null; 115 | } 116 | 117 | @Override 118 | public long getItemId(int position) { 119 | return position; 120 | } 121 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/adapter/AppliancesSelectAdapter.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.adapter; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.BaseAdapter; 9 | import android.widget.TextView; 10 | 11 | import java.util.List; 12 | 13 | import top.caffreyfans.irbaby.R; 14 | 15 | public class AppliancesSelectAdapter extends BaseAdapter { 16 | 17 | private List mStringList; 18 | private LayoutInflater mInflater; 19 | private final String TAG = AppliancesSelectAdapter.class.getSimpleName(); 20 | 21 | public AppliancesSelectAdapter(Context context, List list) { 22 | mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 23 | mStringList = list; 24 | } 25 | 26 | @Override 27 | public int getCount() { 28 | return mStringList.size(); 29 | } 30 | 31 | @Override 32 | public Object getItem(int position) { 33 | return mStringList.get(position); 34 | } 35 | 36 | @Override 37 | public long getItemId(int position) { 38 | return position; 39 | } 40 | 41 | @Override 42 | public View getView(int position, View convertView, ViewGroup parent) { 43 | View v = mInflater.inflate(R.layout.appliance_select_item, null); 44 | TextView textView = (TextView) v.findViewById(R.id.item_ip_tv); 45 | textView.setText(mStringList.get(position)); 46 | return v; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/adapter/InfoAdapter.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import java.util.List; 11 | 12 | import top.caffreyfans.irbaby.R; 13 | 14 | public class InfoAdapter extends BaseAdapter { 15 | 16 | private List mList; 17 | private LayoutInflater mInflater; 18 | 19 | public InfoAdapter(Context context, List list) { 20 | mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 21 | mList = list; 22 | } 23 | 24 | @Override 25 | public int getCount() { 26 | return mList.size(); 27 | } 28 | 29 | @Override 30 | public Object getItem(int position) { 31 | return mList.get(position); 32 | } 33 | 34 | @Override 35 | public long getItemId(int position) { 36 | return position; 37 | } 38 | 39 | @Override 40 | public View getView(int position, View convertView, ViewGroup parent) { 41 | View v = mInflater.inflate(R.layout.info_list_item, null); 42 | TextView key_tv = (TextView) v.findViewById(R.id.key_tv); 43 | TextView value_tv = (TextView) v.findViewById(R.id.value_tv); 44 | String key = mList.get(position)[0]; 45 | String value = mList.get(position)[1]; 46 | key_tv.setText(key); 47 | value_tv.setText(value); 48 | return v; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/firmware_api/Api.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.firmware_api; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.WifiInfo; 5 | import android.net.wifi.WifiManager; 6 | import android.util.Log; 7 | 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | import org.litepal.LitePal; 11 | 12 | import java.util.List; 13 | import java.util.Observable; 14 | 15 | import top.caffreyfans.irbaby.helper.NotifyMsgEntity; 16 | import top.caffreyfans.irbaby.helper.UdpNotifyManager; 17 | import top.caffreyfans.irbaby.helper.UdpSendThread; 18 | import top.caffreyfans.irbaby.model.ApplianceInfo; 19 | import top.caffreyfans.irbaby.model.DeviceInfo; 20 | 21 | public abstract class Api { 22 | abstract void send(JSONObject msg); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/firmware_api/MqttApi.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.firmware_api; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import org.eclipse.paho.android.service.MqttAndroidClient; 7 | import org.eclipse.paho.client.mqttv3.IMqttActionListener; 8 | import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; 9 | import org.eclipse.paho.client.mqttv3.IMqttToken; 10 | import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; 11 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions; 12 | import org.eclipse.paho.client.mqttv3.MqttException; 13 | import org.eclipse.paho.client.mqttv3.MqttMessage; 14 | import org.json.JSONObject; 15 | 16 | import java.util.Observable; 17 | 18 | import top.caffreyfans.irbaby.helper.NotifyMsgEntity; 19 | import top.caffreyfans.irbaby.model.ApplianceInfo; 20 | import top.caffreyfans.irbaby.model.DeviceInfo; 21 | 22 | public class MqttApi extends Api { 23 | 24 | private static final String TAG = MqttApi.class.getSimpleName(); 25 | private MqttAndroidClient mMqttClient; 26 | private DeviceInfo mDeviceInfo; 27 | private ApplianceInfo mApplianceInfo; 28 | 29 | private MqttCallbackExtended mMqttCallback = new MqttCallbackExtended() { 30 | @Override 31 | public void connectComplete(boolean reconnect, String serverURI) { 32 | } 33 | 34 | @Override 35 | public void connectionLost(Throwable cause) { 36 | } 37 | 38 | @Override 39 | public void messageArrived(String topic, MqttMessage message) throws Exception { 40 | Log.d(TAG, "messageArrived: " + topic + " " + message); 41 | } 42 | 43 | @Override 44 | public void deliveryComplete(IMqttDeliveryToken token) { 45 | } 46 | }; 47 | 48 | private IMqttActionListener mIMqttActionListener; 49 | 50 | public MqttApi(Context context, final DeviceInfo deviceInfo, final ApplianceInfo applianceInfo) { 51 | super(); 52 | mDeviceInfo = deviceInfo; 53 | mApplianceInfo = applianceInfo; 54 | mIMqttActionListener = new IMqttActionListener() { 55 | 56 | @Override 57 | public void onSuccess(IMqttToken asyncActionToken) { 58 | String topic = "/IRbaby/" + deviceInfo.getMac() 59 | + "/set/" + applianceInfo.getFile() + "/#"; 60 | try { 61 | mMqttClient.subscribe(topic, 0); 62 | Log.d(TAG, "onSuccess: subscribe " + topic); 63 | } catch (MqttException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | @Override 69 | public void onFailure(IMqttToken asyncActionToken, Throwable exception) { 70 | 71 | } 72 | }; 73 | 74 | if (deviceInfo.getMqttAddress() != null && deviceInfo.getMqttPort() != 0) { 75 | try { 76 | String host = "tcp://"; 77 | host += deviceInfo.getMqttAddress() + ":"; 78 | host += deviceInfo.getMqttPort(); 79 | Log.d(TAG, "mqttInit: " + deviceInfo.getMqttAddress()); 80 | mMqttClient = new MqttAndroidClient(context, host, "IRbaby"); 81 | MqttConnectOptions options = new MqttConnectOptions(); 82 | if (deviceInfo.getMqttUser() != null && !deviceInfo.getMqttUser().trim().equals("") 83 | && deviceInfo.getMqttPassword() != null) { 84 | options.setUserName(deviceInfo.getMqttUser()); 85 | options.setPassword(deviceInfo.getMqttPassword().toCharArray()); 86 | } 87 | options.setConnectionTimeout(20); 88 | options.setAutomaticReconnect(true); 89 | options.setKeepAliveInterval(20); 90 | mMqttClient.setCallback(mMqttCallback); 91 | mMqttClient.connect(options, null, mIMqttActionListener); 92 | } catch (MqttException e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | } 97 | 98 | public void free() { 99 | if (mMqttClient != null) { 100 | mMqttClient.unregisterResources(); 101 | mMqttClient.close(); 102 | mMqttClient = null; 103 | } 104 | } 105 | 106 | @Override 107 | void send(JSONObject msg) { 108 | String topic = "/IRbaby/" + mApplianceInfo.getMac() 109 | + "/set/" + mApplianceInfo.getFile() + "/status"; 110 | String payload = msg.toString(); 111 | MqttMessage mqttMessage = new MqttMessage(); 112 | mqttMessage.setQos(0); 113 | mqttMessage.setRetained(false); 114 | mqttMessage.setPayload(payload.getBytes()); 115 | if (mMqttClient.isConnected()) { 116 | try { 117 | mMqttClient.publish(topic, mqttMessage); 118 | } catch (MqttException e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/firmware_api/UdpApi.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.firmware_api; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.WifiInfo; 5 | import android.net.wifi.WifiManager; 6 | import android.widget.Toast; 7 | 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | 11 | import java.net.Inet4Address; 12 | import java.net.InterfaceAddress; 13 | import java.net.NetworkInterface; 14 | import java.net.SocketException; 15 | import java.util.Enumeration; 16 | 17 | import top.caffreyfans.irbaby.helper.UdpSendThread; 18 | import top.caffreyfans.irbaby.model.ApplianceInfo; 19 | import top.caffreyfans.irbaby.model.DeviceInfo; 20 | 21 | public class UdpApi extends Api { 22 | 23 | private final static String TAG = UdpApi.class.getSimpleName(); 24 | private Context mContext; 25 | private String mLocalIP; 26 | private String mRemoteIP; 27 | private int mIP; 28 | 29 | public UdpApi(Context context, String remoteIP) { 30 | mContext = context; 31 | mIP = getLocalIP(); 32 | mRemoteIP = remoteIP; 33 | mLocalIP = String.format( 34 | "%d.%d.%d.%d", (mIP & 0xff), 35 | (mIP >> 8 & 0xff), (mIP >> 16 & 0xff), 36 | (mIP >> 24 & 0xff)); 37 | } 38 | 39 | 40 | public UdpApi(Context context) { 41 | mContext = context; 42 | mIP = getLocalIP(); 43 | mLocalIP = String.format( 44 | "%d.%d.%d.%d", (mIP & 0xff), 45 | (mIP >> 8 & 0xff), (mIP >> 16 & 0xff), 46 | (mIP >> 24 & 0xff)); 47 | } 48 | 49 | public String fetchBroadcastAddressByIP(String ip) { 50 | try { 51 | Enumeration networkInterfaceEnumeration = NetworkInterface.getNetworkInterfaces(); 52 | while (networkInterfaceEnumeration.hasMoreElements()) { 53 | NetworkInterface networkInterface = (NetworkInterface) networkInterfaceEnumeration.nextElement(); 54 | if (!networkInterface.isUp()) { 55 | continue; 56 | } 57 | for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) { 58 | if (interfaceAddress.getAddress() instanceof Inet4Address 59 | && interfaceAddress.getAddress().getHostAddress().equals(ip) 60 | ) { 61 | return interfaceAddress.getBroadcast().getHostAddress(); 62 | } 63 | } 64 | } 65 | } catch (SocketException e) { 66 | e.printStackTrace(); 67 | } 68 | Toast.makeText(mContext, "没有找到合适的广播地址", Toast.LENGTH_SHORT).show(); 69 | return "0.0.0.0"; 70 | } 71 | 72 | public void discoverDevice() { 73 | JSONObject msg = new JSONObject(); 74 | JSONObject params = new JSONObject(); 75 | String broadcast = fetchBroadcastAddressByIP(mLocalIP); 76 | try { 77 | msg.put("cmd", "query"); 78 | params.put("ip", mLocalIP); 79 | params.put("type", "discovery"); 80 | msg.put("params", params); 81 | } catch (JSONException e) { 82 | e.printStackTrace(); 83 | } 84 | new UdpSendThread(broadcast, msg).start(); 85 | } 86 | 87 | public int getLocalIP(){ 88 | WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 89 | if (wifiManager.isWifiEnabled()) { 90 | WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 91 | int ipAddress = wifiInfo.getIpAddress(); 92 | return ipAddress; 93 | } 94 | return 0; 95 | } 96 | 97 | public String getStrIP() { 98 | return mLocalIP; 99 | } 100 | 101 | @Override 102 | void send(JSONObject msg) { 103 | new UdpSendThread(mRemoteIP, msg).start(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/ApplianceContract.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | /* 设备联系表 */ 4 | public class ApplianceContract { 5 | 6 | public static final class Control { 7 | public static final String IS_PARSE = "is_parse"; 8 | public static final String APPLIANCE_INFO = "appliance_info"; 9 | public static final String EXPORT_TYPE = "export_type"; 10 | } 11 | 12 | public static final class Select { 13 | public static final String TITLE = "title"; 14 | public static final String CONTENT_ID = "content_id"; 15 | public static final String APPLIANCE_INFO = "appliance_info"; 16 | } 17 | 18 | public static final class DeviceSetting { 19 | public static final String TITLE = "title"; 20 | public static final String DEVICE_INFO = "device_info"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/NotifyMsgEntity.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | public class NotifyMsgEntity { 4 | 5 | private int code;// 消息类别代码 6 | private Object data;// 消息数据实体 7 | 8 | private Object content; 9 | 10 | 11 | public NotifyMsgEntity() { 12 | super(); 13 | } 14 | 15 | public NotifyMsgEntity(int code, Object data) { 16 | super(); 17 | this.code = code; 18 | this.data = data; 19 | } 20 | 21 | public NotifyMsgEntity(int code, Object data, Object content) { 22 | this.code = code; 23 | this.data = data; 24 | this.content = content; 25 | } 26 | 27 | public int getCode() { 28 | return code; 29 | } 30 | 31 | public void setCode(int code) { 32 | this.code = code; 33 | } 34 | 35 | public Object getData() { 36 | return data; 37 | } 38 | 39 | public void setData(Object data) { 40 | this.data = data; 41 | } 42 | 43 | 44 | public Object getContent() { 45 | return content; 46 | } 47 | 48 | public void setContent(Object content) { 49 | this.content = content; 50 | } 51 | 52 | 53 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/UIUtils.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | import android.os.Handler; 4 | 5 | import top.caffreyfans.irbaby.MainActivity; 6 | 7 | public class UIUtils { 8 | 9 | public static int getMainThreadId() { 10 | return MainActivity.getMainThreadId(); 11 | } 12 | 13 | public static Handler getHandler() { 14 | return MainActivity.getHandler(); 15 | } 16 | 17 | // 判断是否是主线的方法 18 | public static boolean isRunInMainThread() { 19 | return getMainThreadId() == android.os.Process.myTid(); 20 | } 21 | 22 | // 保证当前的UI操作在主线程里面运行 23 | public static void runInMainThread(Runnable runnable) { 24 | if (isRunInMainThread()) { 25 | // 如果现在就是在珠现场中,就直接运行run方法 26 | runnable.run(); 27 | } else { 28 | // 否则将其传到主线程中运行 29 | getHandler().post(runnable); 30 | } 31 | } 32 | 33 | 34 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/UdpNotifyManager.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | import java.util.Observable; 4 | 5 | public class UdpNotifyManager extends Observable { 6 | public static final int MSG_HANDLE = 0; 7 | public static final int DISCOVERY = 1; 8 | public static final int SAVE_CONFIG = 2; 9 | public static final int RECORD_RT = 3; 10 | public static final int INFO_RT = 4; 11 | 12 | private static UdpNotifyManager mUdpNotifyManager; 13 | 14 | public static UdpNotifyManager getUdpNotifyManager() { 15 | if (mUdpNotifyManager == null) { 16 | mUdpNotifyManager = new UdpNotifyManager(); 17 | } 18 | return mUdpNotifyManager; 19 | } 20 | 21 | /** 22 | * 事件发生后通知监听者 23 | * 24 | * @param code :事件代码号 25 | */ 26 | public void notifyChange(int code) { 27 | NotifyMsgEntity msgEntity = new NotifyMsgEntity(); 28 | msgEntity.setCode(code); 29 | notifyChange(msgEntity); 30 | } 31 | 32 | /** 33 | * 事件发生后通知监听者 34 | * 35 | * @param msgEntity 需要发送的消息数据 36 | */ 37 | public void notifyChange(final NotifyMsgEntity msgEntity) { 38 | UIUtils.runInMainThread(new Runnable() { 39 | @Override 40 | public void run() { 41 | setChanged(); 42 | notifyObservers(msgEntity); 43 | } 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/UdpReceiveThread.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | import android.util.Log; 4 | 5 | import com.google.gson.JsonObject; 6 | 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.io.IOException; 11 | import java.net.DatagramPacket; 12 | import java.net.DatagramSocket; 13 | import java.net.SocketException; 14 | 15 | public class UdpReceiveThread extends Thread { 16 | private static final String TAG = UdpReceiveThread.class.getSimpleName(); 17 | private int mPort = 4210; 18 | private static byte[] buffer = new byte[2048]; 19 | private DatagramSocket ds; 20 | public UdpReceiveThread() { 21 | try { 22 | ds = new DatagramSocket(mPort); 23 | } catch (SocketException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | @Override 29 | public void run() { 30 | while (true) { 31 | DatagramPacket dp = new DatagramPacket(buffer, buffer.length); 32 | try { 33 | if (ds != null) { 34 | ds.receive(dp); 35 | } 36 | if (dp.getLength() > 0){ 37 | String msg = new String(dp.getData(), 0, dp.getLength()); 38 | Log.d(TAG, "run: " + msg); 39 | NotifyMsgEntity msgEntity; 40 | msgEntity = new NotifyMsgEntity(UdpNotifyManager.MSG_HANDLE, msg); 41 | UdpNotifyManager.getUdpNotifyManager().notifyChange(msgEntity); 42 | } 43 | } catch (IOException e){ 44 | e.printStackTrace(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/helper/UdpSendThread.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.helper; 2 | 3 | import org.json.JSONObject; 4 | import java.io.IOException; 5 | import java.net.DatagramPacket; 6 | import java.net.DatagramSocket; 7 | import java.net.InetAddress; 8 | 9 | public class UdpSendThread extends Thread { 10 | 11 | private int mPort = 4210; 12 | private String mAddr; 13 | private JSONObject mSendMsg; 14 | 15 | public UdpSendThread(String addr, JSONObject sendMsg) { 16 | mAddr = addr; 17 | mSendMsg = sendMsg; 18 | } 19 | 20 | @Override 21 | public void run() { 22 | 23 | DatagramSocket mSocket; 24 | try { 25 | InetAddress ip = InetAddress.getByName(mAddr); 26 | mSocket = new DatagramSocket(); 27 | byte[] tmp = mSendMsg.toString().getBytes(); 28 | mSocket.send(new DatagramPacket(tmp, tmp.length, ip, mPort)); 29 | mSocket.close(); 30 | } catch (IOException e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/model/ApplianceInfo.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.model; 2 | 3 | import org.litepal.crud.LitePalSupport; 4 | 5 | import java.io.Serializable; 6 | 7 | public class ApplianceInfo extends LitePalSupport implements Serializable { 8 | 9 | private int id; 10 | private String file; 11 | private String name; 12 | private String mac; 13 | private String ip; 14 | private String signal; 15 | private int brand = -1; 16 | private int category = -1; 17 | 18 | public int getId() { 19 | return id; 20 | } 21 | 22 | public void setId(int id) { 23 | this.id = id; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { this.name = name; } 31 | 32 | public int getCategory() { 33 | return category; 34 | } 35 | 36 | public void setCategory(int cotegory) { 37 | this.category = cotegory; 38 | } 39 | 40 | public String getFile() { 41 | return file; 42 | } 43 | 44 | public void setFile(String file) { this.file = file; } 45 | 46 | public String getMac() { 47 | return mac; 48 | } 49 | 50 | public void setMac(String mac) { 51 | this.mac = mac; 52 | } 53 | 54 | public int getBrand() { 55 | return brand; 56 | } 57 | 58 | public void setBrand(int brand) { 59 | this.brand = brand; 60 | } 61 | 62 | public String getIp() { 63 | return ip; 64 | } 65 | 66 | public void setIp(String ip) { 67 | this.ip = ip; 68 | } 69 | 70 | public String getSignal() { return signal; } 71 | 72 | public void setSignal(String signal) { this.signal = signal; } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/model/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.model; 2 | 3 | import org.litepal.annotation.Column; 4 | import org.litepal.crud.LitePalSupport; 5 | 6 | import java.io.Serializable; 7 | 8 | public class DeviceInfo extends LitePalSupport implements Serializable { 9 | 10 | private int id; 11 | private String version; 12 | private String ip; 13 | private String mac; 14 | private String mqttAddress; 15 | private int mqttPort; 16 | private String mqttUser; 17 | private String mqttPassword; 18 | private int irSendPin; 19 | private int irReceivePin; 20 | 21 | public int getId() { 22 | return id; 23 | } 24 | 25 | public void setId(int id) { 26 | this.id = id; 27 | } 28 | 29 | public String getVersion() { 30 | return version; 31 | } 32 | 33 | public void setVersion(String version) { 34 | this.version = version; 35 | } 36 | 37 | public String getIp() { 38 | return ip; 39 | } 40 | 41 | public void setIp(String ip) { 42 | this.ip = ip; 43 | } 44 | 45 | public String getMac() { 46 | return mac; 47 | } 48 | 49 | public void setMac(String mac) { 50 | this.mac = mac; 51 | } 52 | 53 | public String getMqttAddress() { 54 | return mqttAddress; 55 | } 56 | 57 | public void setMqttAddress(String mqttAddress) { 58 | this.mqttAddress = mqttAddress; 59 | } 60 | 61 | public int getMqttPort() { 62 | return mqttPort; 63 | } 64 | 65 | public void setMqttPort(int mqttPort) { 66 | this.mqttPort = mqttPort; 67 | } 68 | 69 | public String getMqttUser() { 70 | return mqttUser; 71 | } 72 | 73 | public void setMqttUser(String mqttUser) { 74 | this.mqttUser = mqttUser; 75 | } 76 | 77 | public String getMqttPassword() { 78 | return mqttPassword; 79 | } 80 | 81 | public void setMqttPassword(String mqttPassword) { 82 | this.mqttPassword = mqttPassword; 83 | } 84 | 85 | public int getIrSendPin() { 86 | return irSendPin; 87 | } 88 | 89 | public void setIrSendPin(int irSendPin) { 90 | this.irSendPin = irSendPin; 91 | } 92 | 93 | public int getIrReceivePin() { 94 | return irReceivePin; 95 | } 96 | 97 | public void setIrReceivePin(int irReceivePin) { 98 | this.irReceivePin = irReceivePin; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/appliances/ApplianceFragment.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.appliances; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ListView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.fragment.app.Fragment; 13 | 14 | import com.daimajia.swipe.util.Attributes; 15 | import com.google.android.material.floatingactionbutton.FloatingActionButton; 16 | import org.litepal.LitePal; 17 | import java.util.List; 18 | import top.caffreyfans.irbaby.R; 19 | import top.caffreyfans.irbaby.adapter.ApplianceListAdapter; 20 | import top.caffreyfans.irbaby.model.ApplianceInfo; 21 | import top.caffreyfans.irbaby.ui.devices.DeviceSelectActivity; 22 | 23 | public class ApplianceFragment extends Fragment { 24 | private ListView mListView; 25 | private ApplianceListAdapter mApplianceAdapter; 26 | private View root; 27 | private Context mContext; 28 | 29 | private final String TAG = ApplianceFragment.class.getSimpleName(); 30 | 31 | public View onCreateView(@NonNull LayoutInflater inflater, 32 | ViewGroup container, Bundle savedInstanceState) { 33 | 34 | 35 | root = inflater.inflate(R.layout.fragment_appliance, container, false); 36 | mContext = getContext(); 37 | 38 | mListView = (ListView) root.findViewById(R.id.appliance_lv); 39 | 40 | /* fab settings */ 41 | FloatingActionButton fab = root.findViewById(R.id.fab); 42 | 43 | fab.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View view) { 46 | // Snackbar.make(view, "In ApplianceFragment", Snackbar.LENGTH_LONG) 47 | // .setAction("Action", null).show(); 48 | Intent intent = new Intent(getContext(), DeviceSelectActivity.class); 49 | startActivity(intent); 50 | } 51 | }); 52 | 53 | return root; 54 | } 55 | 56 | @Override 57 | public void onResume() { 58 | List applianceInfos = LitePal.findAll(ApplianceInfo.class); 59 | mApplianceAdapter = new ApplianceListAdapter(mContext, applianceInfos); 60 | mListView.setAdapter(mApplianceAdapter); 61 | super.onResume(); 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/appliances/DIYControlActivity.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.appliances; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.ActionBar; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.widget.Button; 13 | 14 | import net.irext.webapi.utils.Constants; 15 | 16 | import org.litepal.LitePal; 17 | 18 | import java.util.List; 19 | 20 | import top.caffreyfans.irbaby.R; 21 | import top.caffreyfans.irbaby.firmware_api.IRbabyApi; 22 | import top.caffreyfans.irbaby.helper.ApplianceContract; 23 | import top.caffreyfans.irbaby.model.ApplianceInfo; 24 | import top.caffreyfans.irbaby.model.DeviceInfo; 25 | 26 | public class DIYControlActivity extends AppCompatActivity { 27 | 28 | private ApplianceInfo mApplianceInfo; 29 | private IRbabyApi mIRbabyApi; 30 | private DeviceInfo mDeviceInfo; 31 | private Button send_btn; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_diycontrol); 37 | 38 | ActionBar actionBar = getSupportActionBar(); 39 | if (actionBar != null) { 40 | actionBar.setHomeButtonEnabled(true); 41 | actionBar.setDisplayHomeAsUpEnabled(true); 42 | } 43 | 44 | Intent intent = getIntent(); 45 | if (intent.hasExtra(ApplianceContract.Control.APPLIANCE_INFO)) { 46 | mApplianceInfo = (ApplianceInfo) intent.getSerializableExtra(ApplianceContract.Control.APPLIANCE_INFO); 47 | this.setTitle(mApplianceInfo.getName()); 48 | List deviceInfos = LitePal.findAll(DeviceInfo.class); 49 | for (DeviceInfo deviceInfo : deviceInfos) { 50 | if (deviceInfo.getMac().equals(mApplianceInfo.getMac())) { 51 | mDeviceInfo = deviceInfo; 52 | mIRbabyApi = new IRbabyApi(this, mDeviceInfo, mApplianceInfo); 53 | } 54 | } 55 | } 56 | 57 | send_btn = (Button) findViewById(R.id.send_bt); 58 | send_btn.setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | mIRbabyApi.sendSignal(mApplianceInfo.getFile(), mApplianceInfo.getSignal(), "file"); 62 | } 63 | }); 64 | } 65 | 66 | @Override 67 | public boolean onCreateOptionsMenu(Menu menu) { 68 | // Inflate the menu; this adds items to the action bar if it is present. 69 | getMenuInflater().inflate(R.menu.appliance_control, menu); 70 | return true; 71 | } 72 | 73 | @Override 74 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 75 | switch (item.getItemId()) { 76 | case android.R.id.home: 77 | this.finish(); 78 | return true; 79 | case R.id.action_export: 80 | Intent intent = new Intent(this, ExportActivity.class); 81 | intent.putExtra(ApplianceContract.Control.APPLIANCE_INFO, mApplianceInfo); 82 | intent.putExtra(ApplianceContract.Control.EXPORT_TYPE, Constants.CategoryID.DIY); 83 | startActivity(intent); 84 | break; 85 | } 86 | return super.onOptionsItemSelected(item); 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/appliances/ExportActivity.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.appliances; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.ActionBar; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.view.MenuItem; 10 | import android.widget.TextView; 11 | 12 | import net.irext.webapi.utils.Constants; 13 | 14 | import top.caffreyfans.irbaby.R; 15 | import top.caffreyfans.irbaby.helper.ApplianceContract; 16 | import top.caffreyfans.irbaby.model.ApplianceInfo; 17 | 18 | public class ExportActivity extends AppCompatActivity { 19 | 20 | private ApplianceInfo mApplianceInfo; 21 | private String MAC; 22 | private String File; 23 | private String Config; 24 | private Constants.CategoryID categoryID; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_export); 30 | 31 | ActionBar actionBar = getSupportActionBar(); 32 | if (actionBar != null) { 33 | actionBar.setHomeButtonEnabled(true); 34 | actionBar.setDisplayHomeAsUpEnabled(true); 35 | } 36 | 37 | Intent intent = getIntent(); 38 | 39 | if (intent.hasExtra(ApplianceContract.Control.APPLIANCE_INFO)) { 40 | mApplianceInfo = (ApplianceInfo) intent.getSerializableExtra(ApplianceContract.Control.APPLIANCE_INFO); 41 | MAC = mApplianceInfo.getMac(); 42 | File = mApplianceInfo.getFile(); 43 | } 44 | 45 | if (intent.hasExtra(ApplianceContract.Control.EXPORT_TYPE)) { 46 | categoryID = (Constants.CategoryID) intent.getSerializableExtra(ApplianceContract.Control.EXPORT_TYPE); 47 | switch (categoryID) { 48 | case AIR_CONDITIONER: 49 | Config = getACConfig(); 50 | break; 51 | case DIY: 52 | Config = getDIYConfig(); 53 | break; 54 | default: 55 | break; 56 | 57 | } 58 | } 59 | 60 | TextView mqttTV = (TextView) findViewById(R.id.mqtt_tv); 61 | mqttTV.setText(Config); 62 | } 63 | 64 | private String getACConfig() { 65 | String output = String.format( 66 | "climate:\n" + 67 | " - platform: mqtt\n" + 68 | " name: just you like!\n" + 69 | " modes:\n" + 70 | " - \"auto\"\n" + 71 | " - \"heat\"\n" + 72 | " - \"cool\"\n" + 73 | " - \"fan_only\"\n" + 74 | " - \"dry\"\n" + 75 | " - \"off\"\n" + 76 | " swing_modes:\n" + 77 | " - \"on\"\n" + 78 | " - \"off\"\n" + 79 | " max_temp: 30\n" + 80 | " min_temp: 16\n" + 81 | " fan_modes:\n" + 82 | " - \"auto\"\n" + 83 | " - \"low\"\n" + 84 | " - \"medium\"\n" + 85 | " - \"high\"\n" + 86 | String.format(" mode_command_topic: \"/IRbaby/%s/send/ir/local/%s/mode\"\n", MAC, File) + 87 | String.format(" mode_state_topic: \"/IRbaby/%s/state/%s/mode\"\n", MAC, File) + 88 | String.format(" temperature_command_topic: \"/IRbaby/%s/send/ir/local/%s/temperature\"\n", MAC, File) + 89 | String.format(" temperature_state_topic: \"/IRbaby/%s/state/%s/temperature\"\n", MAC, File) + 90 | String.format(" fan_mode_command_topic: \"/IRbaby/%s/send/ir/local/%s/fan\"\n", MAC, File) + 91 | String.format(" fan_mode_state_topic: \"/IRbaby/%s/state/%s/fan\"\n", MAC, File) + 92 | String.format(" swing_mode_command_topic: \"/IRbaby/%s/send/ir/local/%s/swing\"\n", MAC, File) + 93 | String.format(" swing_mode_state_topic: \"/IRbaby/%s/state/%s/swing\"\n", MAC, File) + 94 | " precision: 1.0"); 95 | return output; 96 | } 97 | 98 | private String getDIYConfig() { 99 | String output = "switch:\n" + 100 | " - platform: mqtt\n" + 101 | String.format(" command_topic: \"/IRbaby/%s/send/ir/file/%s/skr\"", MAC, File); 102 | return output; 103 | } 104 | 105 | @Override 106 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 107 | switch (item.getItemId()) { 108 | case android.R.id.home: 109 | this.finish(); 110 | return true; 111 | } 112 | return super.onOptionsItemSelected(item); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/devices/DeviceFragment.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.devices; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ListView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.fragment.app.Fragment; 12 | 13 | import org.litepal.LitePal; 14 | 15 | import java.util.List; 16 | import java.util.Observable; 17 | import java.util.Observer; 18 | import java.util.Timer; 19 | import java.util.TimerTask; 20 | 21 | import top.caffreyfans.irbaby.R; 22 | import top.caffreyfans.irbaby.adapter.DeviceAdapter; 23 | import top.caffreyfans.irbaby.firmware_api.IRbabyApi; 24 | import top.caffreyfans.irbaby.helper.NotifyMsgEntity; 25 | import top.caffreyfans.irbaby.helper.UdpNotifyManager; 26 | import top.caffreyfans.irbaby.model.DeviceInfo; 27 | 28 | public class DeviceFragment extends Fragment implements Observer { 29 | 30 | private static final String TAG = DeviceFragment.class.getSimpleName(); 31 | private ListView mListView; 32 | private DeviceAdapter mDeviceAdapter; 33 | private List mDeviceInfos; 34 | private Context mContext; 35 | private Timer mTimer; 36 | private IRbabyApi mCommonApi; 37 | 38 | public View onCreateView(@NonNull LayoutInflater inflater, 39 | ViewGroup container, Bundle savedInstanceState) { 40 | View root = inflater.inflate(R.layout.fragment_device, container, false); 41 | mContext = getContext(); 42 | mListView = root.findViewById(R.id.device_lv); 43 | mCommonApi = new IRbabyApi(getContext().getApplicationContext()); 44 | mTimer = new Timer(); 45 | UdpNotifyManager.getUdpNotifyManager().addObserver(this); 46 | return root; 47 | } 48 | 49 | @Override 50 | public void onResume() { 51 | super.onResume(); 52 | TimerTask timerTask = new TimerTask() { 53 | @Override 54 | public void run() { 55 | mCommonApi.discoverDevices(); 56 | } 57 | }; 58 | if (mTimer == null) { 59 | mTimer = new Timer(); 60 | } 61 | mTimer.schedule(timerTask, 0, 5000); 62 | } 63 | 64 | @Override 65 | public void onPause() { 66 | super.onPause(); 67 | mTimer.cancel(); 68 | mTimer.purge(); 69 | mTimer = null; 70 | } 71 | 72 | @Override 73 | public void update(Observable o, Object arg) { 74 | NotifyMsgEntity entity = (NotifyMsgEntity)arg; 75 | int code = (int)entity.getCode(); 76 | if (code == UdpNotifyManager.DISCOVERY) { 77 | mDeviceInfos = LitePal.findAll(DeviceInfo.class); 78 | mDeviceAdapter = new DeviceAdapter(mContext, mDeviceInfos, 1); 79 | mListView.setAdapter(mDeviceAdapter); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/devices/DeviceSelectActivity.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.devices; 2 | 3 | import android.app.NotificationManager; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.view.MenuItem; 7 | import android.widget.ListView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.ActionBar; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import org.litepal.LitePal; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.Observable; 19 | import java.util.Observer; 20 | import java.util.Timer; 21 | import java.util.TimerTask; 22 | 23 | import top.caffreyfans.irbaby.R; 24 | import top.caffreyfans.irbaby.adapter.DeviceAdapter; 25 | import top.caffreyfans.irbaby.firmware_api.IRbabyApi; 26 | import top.caffreyfans.irbaby.helper.NotifyMsgEntity; 27 | import top.caffreyfans.irbaby.helper.UdpNotifyManager; 28 | import top.caffreyfans.irbaby.model.DeviceInfo; 29 | 30 | public class DeviceSelectActivity extends AppCompatActivity implements Observer { 31 | 32 | private final static String TAG = DeviceSelectActivity.class.getSimpleName(); 33 | private ListView mListView; 34 | private List mDeviceInfos; 35 | private Context mContext; 36 | private DeviceAdapter mDeviceAdapter; 37 | private Timer mTimer; 38 | private IRbabyApi mCommonApi; 39 | 40 | @Override 41 | protected void onCreate(@Nullable Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.fragment_device); 44 | 45 | ActionBar actionBar = getSupportActionBar(); 46 | if (actionBar != null) { 47 | actionBar.setHomeButtonEnabled(true); 48 | actionBar.setDisplayHomeAsUpEnabled(true); 49 | } 50 | 51 | mContext = this; 52 | mListView = findViewById(R.id.device_lv); 53 | mDeviceInfos = new ArrayList<>(); 54 | mTimer = new Timer(); 55 | 56 | UdpNotifyManager.getUdpNotifyManager().addObserver(this); 57 | mCommonApi = new IRbabyApi(this); 58 | } 59 | 60 | @Override 61 | public void onResume() { 62 | super.onResume(); 63 | TimerTask timerTask = new TimerTask() { 64 | @Override 65 | public void run() { 66 | mCommonApi.discoverDevices(); 67 | } 68 | }; 69 | if (mTimer == null) { 70 | mTimer = new Timer(); 71 | } 72 | mTimer.schedule(timerTask, 0, 5000); 73 | } 74 | 75 | @Override 76 | public void onPause() { 77 | super.onPause(); 78 | mTimer.cancel(); 79 | mTimer.purge(); 80 | mTimer = null; 81 | } 82 | 83 | @Override 84 | public void update(Observable o, Object arg) { 85 | 86 | NotifyMsgEntity entity = (NotifyMsgEntity) arg; 87 | int code = (int)entity.getCode(); 88 | if (code == UdpNotifyManager.DISCOVERY) { 89 | mDeviceInfos = LitePal.findAll(DeviceInfo.class); 90 | mDeviceAdapter = new DeviceAdapter(mContext, mDeviceInfos, 2); 91 | mListView.setAdapter(mDeviceAdapter); 92 | } 93 | } 94 | 95 | @Override 96 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 97 | switch (item.getItemId()) { 98 | case android.R.id.home: 99 | this.finish(); 100 | return true; 101 | } 102 | return super.onOptionsItemSelected(item); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/record/RecordFragment.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.record; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ListView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.fragment.app.Fragment; 12 | 13 | import org.litepal.LitePal; 14 | 15 | import java.util.List; 16 | import java.util.Observable; 17 | import java.util.Observer; 18 | import java.util.Timer; 19 | import java.util.TimerTask; 20 | 21 | import top.caffreyfans.irbaby.R; 22 | import top.caffreyfans.irbaby.adapter.DeviceAdapter; 23 | import top.caffreyfans.irbaby.firmware_api.IRbabyApi; 24 | import top.caffreyfans.irbaby.helper.NotifyMsgEntity; 25 | import top.caffreyfans.irbaby.helper.UdpNotifyManager; 26 | import top.caffreyfans.irbaby.model.DeviceInfo; 27 | 28 | public class RecordFragment extends Fragment implements Observer { 29 | 30 | private static final String TAG = RecordFragment.class.getSimpleName(); 31 | private ListView mListView; 32 | private DeviceAdapter mDeviceAdapter; 33 | private List mDeviceInfos; 34 | private Context mContext; 35 | private Timer mTimer; 36 | private IRbabyApi mCommonApi; 37 | 38 | public View onCreateView(@NonNull LayoutInflater inflater, 39 | ViewGroup container, Bundle savedInstanceState) { 40 | View root = inflater.inflate(R.layout.fragment_device, container, false); 41 | mContext = getContext(); 42 | mListView = root.findViewById(R.id.device_lv); 43 | mCommonApi = new IRbabyApi(getContext().getApplicationContext()); 44 | mTimer = new Timer(); 45 | UdpNotifyManager.getUdpNotifyManager().addObserver(this); 46 | return root; 47 | } 48 | 49 | @Override 50 | public void onResume() { 51 | super.onResume(); 52 | TimerTask timerTask = new TimerTask() { 53 | @Override 54 | public void run() { 55 | mCommonApi.discoverDevices(); 56 | } 57 | }; 58 | if (mTimer == null) { 59 | mTimer = new Timer(); 60 | } 61 | mTimer.schedule(timerTask, 0, 5000); 62 | } 63 | 64 | @Override 65 | public void onPause() { 66 | super.onPause(); 67 | mTimer.cancel(); 68 | mTimer.purge(); 69 | mTimer = null; 70 | } 71 | 72 | @Override 73 | public void update(Observable o, Object arg) { 74 | NotifyMsgEntity entity = (NotifyMsgEntity)arg; 75 | int code = (int)entity.getCode(); 76 | if (code == UdpNotifyManager.DISCOVERY) { 77 | mDeviceInfos = LitePal.findAll(DeviceInfo.class); 78 | mDeviceAdapter = new DeviceAdapter(mContext, mDeviceInfos, 3); 79 | mListView.setAdapter(mDeviceAdapter); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/share/ShareFragment.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.share; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.Nullable; 10 | import androidx.annotation.NonNull; 11 | import androidx.fragment.app.Fragment; 12 | import androidx.lifecycle.Observer; 13 | import androidx.lifecycle.ViewModelProviders; 14 | 15 | import top.caffreyfans.irbaby.R; 16 | 17 | public class ShareFragment extends Fragment { 18 | 19 | private ShareViewModel shareViewModel; 20 | 21 | public View onCreateView(@NonNull LayoutInflater inflater, 22 | ViewGroup container, Bundle savedInstanceState) { 23 | shareViewModel = 24 | ViewModelProviders.of(this).get(ShareViewModel.class); 25 | View root = inflater.inflate(R.layout.fragment_share, container, false); 26 | final TextView textView = root.findViewById(R.id.text_share); 27 | shareViewModel.getText().observe(this, new Observer() { 28 | @Override 29 | public void onChanged(@Nullable String s) { 30 | textView.setText(s); 31 | } 32 | }); 33 | return root; 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/top/caffreyfans/irbaby/ui/share/ShareViewModel.java: -------------------------------------------------------------------------------- 1 | package top.caffreyfans.irbaby.ui.share; 2 | 3 | import androidx.lifecycle.LiveData; 4 | import androidx.lifecycle.MutableLiveData; 5 | import androidx.lifecycle.ViewModel; 6 | 7 | public class ShareViewModel extends ViewModel { 8 | 9 | private MutableLiveData mText; 10 | 11 | public ShareViewModel() { 12 | mText = new MutableLiveData<>(); 13 | mText.setValue("This is share fragment"); 14 | } 15 | 16 | public LiveData getText() { 17 | return mText; 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ac_button_selected_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_air_conditioner.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_appliance.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_auto.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_box.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cool.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cpu.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_device.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_diy.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dvd.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fan.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_heat.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_gallery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_manage.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pen.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_power.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_record_ir.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_trash.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tv.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_water.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/sriracha.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_appliance_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_device_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 |