Просмотр исходного кода

feat:支持用户名+密码登录+布局优化

yingjian.wu 3 месяцев назад
Родитель
Сommit
44d1ac6287

+ 40 - 1
app/src/main/java/com/paul/drone/MainActivity.java

@@ -6,6 +6,7 @@ import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -13,6 +14,7 @@ import android.os.Looper;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -39,6 +41,11 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
 /**
  * 主界面 - 钢塔无人机控制系统
  */
+// 在文件顶部的import部分添加以下导入
+import android.view.WindowManager;
+import android.view.ViewGroup;
+import android.graphics.Color;
+
 public class MainActivity extends AppCompatActivity implements DeviceConnectionManager.ConnectionStateCallback, MqttService.OnMqttConnectionStatusChangedListener {
 
     private static final String TAG = "MainActivity";
@@ -135,6 +142,30 @@ public class MainActivity extends AppCompatActivity implements DeviceConnectionM
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        
+        // 设置状态栏颜色为蓝色#1088F2
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            getWindow().setStatusBarColor(Color.parseColor("#1088F2"));
+            // 确保状态栏文字为白色,提高可读性
+            getWindow().getDecorView().setSystemUiVisibility(0);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            // 旧版Android兼容处理
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            // 创建一个与状态栏高度相同的View并设置背景色
+            View statusBarView = new View(this);
+            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.MATCH_PARENT,
+                    getStatusBarHeight()
+            );
+            statusBarView.setBackgroundColor(Color.parseColor("#1088F2"));
+            // 添加到布局顶部
+            ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
+            decorView.addView(statusBarView, params);
+            // 确保内容不被状态栏遮挡
+            ViewGroup rootView = findViewById(android.R.id.content);
+            rootView.setPadding(0, getStatusBarHeight(), 0, 0);
+        }
+
         setContentView(R.layout.activity_main);
 
         initViews();
@@ -146,7 +177,6 @@ public class MainActivity extends AppCompatActivity implements DeviceConnectionM
 
         intent = new Intent(this, MqttService.class);
         bindService(intent, mqttConnection, Context.BIND_AUTO_CREATE);
-
     }
 
     /**
@@ -674,4 +704,13 @@ public class MainActivity extends AppCompatActivity implements DeviceConnectionM
         Log.i(TAG, "MainActivity 销毁");
     }
 
+    // 添加获取状态栏高度的辅助方法
+    private int getStatusBarHeight() {
+        int result = 0;
+        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+        if (resourceId > 0) {
+            result = getResources().getDimensionPixelSize(resourceId);
+        }
+        return result;
+    }
 }

+ 145 - 14
app/src/main/java/com/paul/drone/activity/LoginActivity.java

@@ -1,12 +1,16 @@
 package com.paul.drone.activity;
-
+// 在文件顶部添加导入
+import android.view.WindowManager;
+import android.view.ViewGroup;
 import android.annotation.SuppressLint;
 import android.app.DownloadManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.ColorStateList;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -32,6 +36,7 @@ import com.paul.drone.data.UpdateInfoResponse;
 import com.paul.drone.manager.DJISDKManager;
 import com.paul.drone.network.SessionManager;
 import com.paul.drone.repository.NetworkRepository;
+import com.paul.drone.util.AESHelper;
 import com.paul.drone.util.VersionUpdateUtil;
 
 import java.io.File;
@@ -77,33 +82,107 @@ public class LoginActivity extends AppCompatActivity {
 
     // 切换到短信登录
     private void switchToSmsLogin() {
+        // 显示短信登录界面,隐藏密码登录界面
         layoutSmsLogin.setVisibility(View.VISIBLE);
         layoutPasswordLogin.setVisibility(View.GONE);
-        btnSwitchSms.setEnabled(false);
-        btnSwitchPassword.setEnabled(true);
+    
+        // 给按钮背景上色
+        // 短信按钮设为蓝色背景
+        int blueColor = Color.parseColor("#1088F2");
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            btnSwitchSms.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchSms.setTextColor(Color.WHITE);
+            btnSwitchSms2.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchSms2.setTextColor(Color.WHITE);
+    
+            // 密码按钮设为默认背景(灰色)
+            btnSwitchPassword.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchPassword.setTextColor(Color.BLACK);
+            btnSwitchPassword2.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchPassword2.setTextColor(Color.BLACK);
+        } else {
+            // 旧版本Android兼容处理
+            btnSwitchSms.setBackgroundColor(blueColor);
+            btnSwitchSms.setTextColor(Color.WHITE);
+            btnSwitchSms2.setBackgroundColor(blueColor);
+            btnSwitchSms2.setTextColor(Color.WHITE);
+    
+            btnSwitchPassword.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchPassword.setTextColor(Color.BLACK);
+            btnSwitchPassword2.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchPassword2.setTextColor(Color.BLACK);
+        }
     }
 
-    // 切换到密码登录
+    // 修改switchToPasswordLogin方法
     private void switchToPasswordLogin() {
+        // 显示密码登录界面,隐藏短信登录界面
         layoutSmsLogin.setVisibility(View.GONE);
         layoutPasswordLogin.setVisibility(View.VISIBLE);
-        btnSwitchSms.setEnabled(true);
-        btnSwitchPassword.setEnabled(false);
+        // 给按钮背景上色
+        // 密码按钮设为蓝色背景
+        int blueColor = Color.parseColor("#1088F2");
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            btnSwitchPassword.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchPassword.setTextColor(Color.WHITE);
+            btnSwitchPassword2.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchPassword2.setTextColor(Color.WHITE);
+    
+            // 短信按钮设为默认背景(灰色)
+            btnSwitchSms.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchSms.setTextColor(Color.BLACK);
+            btnSwitchSms2.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchSms2.setTextColor(Color.BLACK);
+        } else {
+            // 旧版本Android兼容处理
+            btnSwitchPassword.setBackgroundColor(blueColor);
+            btnSwitchPassword.setTextColor(Color.WHITE);
+            btnSwitchPassword2.setBackgroundColor(blueColor);
+            btnSwitchPassword2.setTextColor(Color.WHITE);
+    
+            btnSwitchSms.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchSms.setTextColor(Color.BLACK);
+            btnSwitchSms2.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchSms2.setTextColor(Color.BLACK);
+        }
     }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
+        
+        // 设置状态栏颜色为蓝色#1088F2
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            getWindow().setStatusBarColor(Color.parseColor("#1088F2"));
+            // 确保状态栏文字为白色,提高可读性
+            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            // 旧版Android兼容处理
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            // 创建一个与状态栏高度相同的View并设置背景色
+            View statusBarView = new View(this);
+            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.MATCH_PARENT,
+                    getStatusBarHeight()
+            );
+            statusBarView.setBackgroundColor(Color.parseColor("#1088F2"));
+            // 添加到布局顶部
+            ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
+            decorView.addView(statusBarView, params);
+            // 确保内容不被状态栏遮挡
+            ViewGroup rootView = findViewById(android.R.id.content);
+            rootView.setPadding(0, getStatusBarHeight(), 0, 0);
+        }
+    
         // 初始化 NetworkRepository
         networkRepository = NetworkRepository.getInstance();
         sessionManager = new SessionManager(this);
-
+    
         updateUtil = VersionUpdateUtil.getInstance(this);
-
+    
         String currentVersion = updateUtil.getCurrentVersion();
         Single<UpdateInfoResponse> updateInfoResponseSingle = updateUtil.checkLatestVersion();
-
+    
         disposables.add(updateInfoResponseSingle.subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
                 .subscribe(
@@ -123,7 +202,7 @@ public class LoginActivity extends AppCompatActivity {
                             checkLoginStatus(sessionManager);
                         }
                 ));
-
+    
         // 注意:不要在这里添加其他逻辑,所有后续操作应该在subscribe回调中处理
     }
 
@@ -166,6 +245,48 @@ public class LoginActivity extends AppCompatActivity {
         etUsername = findViewById(R.id.et_username);
         etPassword = findViewById(R.id.et_password);
         btnPasswordLogin = findViewById(R.id.btn_password_login);
+        
+        // 设置按钮默认背景色为#1088F2
+        int blueColor = Color.parseColor("#1088F2");
+        
+        // 登录按钮
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            buttonLogin.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnPasswordLogin.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            // 为验证码按钮设置背景色
+            buttonSendSms.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+        } else {
+            buttonLogin.setBackgroundColor(blueColor);
+            btnPasswordLogin.setBackgroundColor(blueColor);
+            // 为验证码按钮设置背景色
+            buttonSendSms.setBackgroundColor(blueColor);
+        }
+        buttonLogin.setTextColor(Color.WHITE);
+        btnPasswordLogin.setTextColor(Color.WHITE);
+        buttonSendSms.setTextColor(Color.WHITE);
+        
+        // 登录方式切换按钮 - 初始状态(短信登录为蓝色,密码登录为灰色)
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            btnSwitchSms.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchSms2.setBackgroundTintList(ColorStateList.valueOf(blueColor));
+            btnSwitchSms.setTextColor(Color.WHITE);
+            btnSwitchSms2.setTextColor(Color.WHITE);
+            
+            btnSwitchPassword.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchPassword2.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
+            btnSwitchPassword.setTextColor(Color.BLACK);
+            btnSwitchPassword2.setTextColor(Color.BLACK);
+        } else {
+            btnSwitchSms.setBackgroundColor(blueColor);
+            btnSwitchSms2.setBackgroundColor(blueColor);
+            btnSwitchSms.setTextColor(Color.WHITE);
+            btnSwitchSms2.setTextColor(Color.WHITE);
+            
+            btnSwitchPassword.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchPassword2.setBackgroundColor(Color.parseColor("#E0E0E0"));
+            btnSwitchPassword.setTextColor(Color.BLACK);
+            btnSwitchPassword2.setTextColor(Color.BLACK);
+        }
     }
 
     private void setupListeners() {
@@ -313,13 +434,15 @@ public class LoginActivity extends AppCompatActivity {
      */
     private void performPasswordLogin(String phoneNumber, String password) {
         Log.i(TAG, "登录: " + phoneNumber + ", 密码: " + password);
+        // 加密密码
+        String encryptedPassword = AESHelper.encrypt("hntt,sddn,-cloud",password);
 
         // 禁用登录按钮
         buttonLogin.setEnabled(false);
         buttonLogin.setText("登录中...");
 
         // 使用 NetworkRepository 执行登录
-        disposables.add(networkRepository.loginWithPassword(phoneNumber,password)
+        disposables.add(networkRepository.loginWithPassword(phoneNumber,encryptedPassword)
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
                 .subscribe(
@@ -737,5 +860,13 @@ public class LoginActivity extends AppCompatActivity {
     }
 
 
-
-}
+    // 添加获取状态栏高度的辅助方法
+    private int getStatusBarHeight() {
+        int result = 0;
+        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+        if (resourceId > 0) {
+            result = getResources().getDimensionPixelSize(resourceId);
+        }
+        return result;
+    }
+}

+ 1 - 1
app/src/main/java/com/paul/drone/repository/NetworkRepository.java

@@ -231,7 +231,7 @@ public class NetworkRepository {
         return Single.fromCallable(() -> {
                     try {
                         retrofit2.Response<OAuth2TokenResponse> response = chinaTowerApiService.getOAuth2TokenByPassword(
-                                "Basic c2VydmVyOjEyMzQ1Ng==", // 默认Basic Auth
+                                AuthUtil.generateDefaultBasicAuth(), // 默认Basic Auth
                                 username,
                                 password,
                                 "password",

+ 167 - 0
app/src/main/java/com/paul/drone/util/AESHelper.java

@@ -0,0 +1,167 @@
+package com.paul.drone.util;
+
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class AESHelper {
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String CIPHER_ALGORITHM = "AES/CFB/NoPadding";
+    private static final String TAG = "AESHelper";
+    
+    /**
+     * AES加密
+     * @param key 密钥字符串(自动处理为16字节)
+     * @param data 要加密的数据
+     * @return 十六进制格式的加密结果
+     */
+    public static String encrypt(String key, String data) {
+        try {
+            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+            SecretKeySpec secretKey = generateSecretKey(key);
+            IvParameterSpec iv = generateIV(key);
+
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
+            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
+            return bytesToHex(encrypted);
+        } catch (Exception e) {
+            Log.e(TAG, "加密错误: " + e.getMessage(), e);
+            return "";
+        }
+    }
+
+    /**
+     * AES解密
+     * @param key 密钥字符串(自动处理为16字节)
+     * @param encryptedData 十六进制格式的加密数据
+     * @return 解密后的原始字符串
+     */
+    public static String decrypt(String key, String encryptedData) {
+        try {
+            if (encryptedData.isEmpty() || encryptedData.length() % 2 != 0) {
+                Log.w("AESHelper", "无效的加密数据长度: " + encryptedData.length());
+                return "";
+            }
+
+            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+            SecretKeySpec secretKey = generateSecretKey(key);
+            IvParameterSpec iv = generateIV(key);
+
+            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
+            byte[] decrypted = cipher.doFinal(hexToBytes(encryptedData));
+            return new String(decrypted, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            Log.e(TAG, "解密错误: " + e.getMessage(), e);
+            return "";
+        }
+    }
+
+    /**
+     * 生成安全的16字节密钥
+     */
+    private static SecretKeySpec generateSecretKey(String key) {
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        byte[] key16 = new byte[16];
+
+        // 确保密钥长度为16字节
+        if (keyBytes.length >= 16) {
+            System.arraycopy(keyBytes, 0, key16, 0, 16);
+        } else {
+            System.arraycopy(keyBytes, 0, key16, 0, keyBytes.length);
+            // 填充剩余部分
+            for (int i = keyBytes.length; i < 16; i++) {
+                key16[i] = 0;
+            }
+        }
+
+        return new SecretKeySpec(key16, KEY_ALGORITHM);
+    }
+
+    /**
+     * 生成初始化向量(IV)
+     */
+    private static IvParameterSpec generateIV(String key) {
+        byte[] ivBytes = key.getBytes(StandardCharsets.UTF_8);
+        byte[] iv16 = new byte[16];
+
+        // 确保IV长度为16字节
+        if (ivBytes.length >= 16) {
+            System.arraycopy(ivBytes, 0, iv16, 0, 16);
+        } else {
+            System.arraycopy(ivBytes, 0, iv16, 0, ivBytes.length);
+            for (int i = ivBytes.length; i < 16; i++) {
+                iv16[i] = 0;
+            }
+        }
+
+        return new IvParameterSpec(iv16);
+    }
+
+    /**
+     * 字节数组转十六进制字符串(修复数组越界问题)
+     */
+    private static String bytesToHex(byte[] bytes) {
+        char[] hexChars = new char[bytes.length * 2];
+        for (int i = 0; i < bytes.length; i++) {
+            int v = bytes[i] & 0xFF;
+            hexChars[i * 2] = "0123456789ABCDEF".charAt(v >>> 4);
+            hexChars[i * 2 + 1] = "0123456789ABCDEF".charAt(v & 0x0F);
+        }
+        return new String(hexChars);
+    }
+
+    /**
+     * 十六进制字符串转字节数组(修复长度检查)
+     */
+    private static byte[] hexToBytes(String hex) {
+        if (hex.isEmpty()) return new byte[0];
+
+        String cleanHex = hex.replaceAll("[^0-9A-Fa-f]", "");
+        if (cleanHex.length() % 2 != 0) {
+            Log.w(TAG, "十六进制字符串长度无效: " + cleanHex.length());
+            return new byte[0];
+        }
+
+        int len = cleanHex.length();
+        byte[] data = new byte[len / 2];
+
+        try {
+            for (int i = 0; i < len; i += 2) {
+                int high = Character.digit(cleanHex.charAt(i), 16);
+                int low = Character.digit(cleanHex.charAt(i + 1), 16);
+                if (high == -1 || low == -1) {
+                    Log.w(TAG, "无效的十六进制字符");
+                    return new byte[0];
+                }
+                data[i / 2] = (byte) ((high << 4) + low);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "十六进制转换错误: " + e.getMessage());
+            return new byte[0];
+        }
+
+        return data;
+    }
+}
+
+/**
+ * 使用示例
+ */
+class AESEncryptionExample {
+    public void demonstrateUsage() {
+        String key = "hntt,sddn,-cloud";
+        String password = "your_password_here";
+        
+        // 加密
+        String encryptedPassword = AESHelper.encrypt(key, password);
+        System.out.println("加密后的密码: " + encryptedPassword);
+        
+        // 解密
+        String decryptedPassword = AESHelper.decrypt(key, encryptedPassword);
+        System.out.println("解密后的密码: " + decryptedPassword);
+    }
+}