diff --git a/app/build.gradle b/app/build.gradle index 8d5d453..4a5fe01 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdk 28 targetSdk 28 versionCode 1 - versionName "2.14" + versionName "2.15" // 1.0 IDATA广播模式处理 // 1.1 霍尼韦尔的监听修改(扫描网站二维码跳出程序,监听失效,调整)、斑马PDA广播模式设置 @@ -50,6 +50,7 @@ android { // 2.13 取消监听旋转角度,使用系统自带的旋转(根据配置初始化,旋转方向:横、竖、随意) // 瑞芯适配器 接入 新的型号,使用的是 ttyS8;而不是ttyS1;并且只有一个接口。 // 2.14 适配 AIFUU 陈安良:陆军特色中心医院 + // 2.15 添加文件选择和相机拍照功能 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ndk { abiFilters 'armeabi-v7a' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e048d10..8c84540 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/demo/file_test.html b/app/src/main/assets/demo/file_test.html new file mode 100644 index 0000000..6fd737a --- /dev/null +++ b/app/src/main/assets/demo/file_test.html @@ -0,0 +1,175 @@ + + + + + + 文件选择测试 + + + +

文件选择和相机测试

+ + +
+

1. 选择任意文件

+ + +
+ + +
+

2. 选择图片(支持相机)

+ + + +
+
+ + +
+

3. 仅使用相机拍照

+ + + +
+
+ + + + + \ No newline at end of file diff --git a/app/src/main/java/chaoran/business/activity/FileTestActivity.java b/app/src/main/java/chaoran/business/activity/FileTestActivity.java new file mode 100644 index 0000000..90ce92c --- /dev/null +++ b/app/src/main/java/chaoran/business/activity/FileTestActivity.java @@ -0,0 +1,113 @@ +package chaoran.business.activity; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import chaoran.business.R; +import chaoran.business.utils.FileChooserHelper; +import chaoran.business.utils.CameraHelper; + +/** + * 文件选择测试Activity + */ +public class FileTestActivity extends AppCompatActivity { + + private WebView webView; + private FileChooserHelper fileChooserHelper; + private CameraHelper cameraHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_file_test); + + fileChooserHelper = new FileChooserHelper(this); + + webView = findViewById(R.id.webViewFileTest); + cameraHelper = new CameraHelper(this, webView); + initWebView(); + + // 加载测试页面 + webView.loadUrl("file:///android_asset/demo/file_test.html"); + } + + @SuppressLint("SetJavaScriptEnabled") + private void initWebView() { + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setDomStorageEnabled(true); + + // 添加JavaScript接口 + webView.addJavascriptInterface(cameraHelper, "CameraHelper"); + + webView.setWebViewClient(new WebViewClient()); + webView.setWebChromeClient(new WebChromeClient() { + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + // 检查是否接受图片 + String[] acceptTypes = fileChooserParams.getAcceptTypes(); + boolean acceptImage = false; + boolean acceptCamera = false; + boolean cameraOnly = false; + + if (acceptTypes != null && acceptTypes.length > 0) { + for (String type : acceptTypes) { + if (type.contains("image")) { + acceptImage = true; + break; + } + } + } + + // 检查capture模式 + if (fileChooserParams.isCaptureEnabled()) { + acceptCamera = true; + + // 注意:Android WebView中,capture="user"或capture="environment"都会返回true + // 我们通过简单的方式判断:如果是图片且启用capture,默认显示选择器 + // 只有在特定情况下才直接打开相机 + + // 这里我们不设置cameraOnly=true,让所有capture都显示选择器 + // 如果需要仅相机模式,可以通过其他方式(如URL参数)来控制 + } + + fileChooserHelper.openFileChooser(filePathCallback, acceptImage, acceptCamera, cameraOnly); + return true; + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (!fileChooserHelper.onActivityResult(requestCode, resultCode, data)) { + cameraHelper.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + fileChooserHelper.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + public void onBackPressed() { + if (webView.canGoBack()) { + webView.goBack(); + } else { + super.onBackPressed(); + } + } +} diff --git a/app/src/main/java/chaoran/business/activity/MainActivity.java b/app/src/main/java/chaoran/business/activity/MainActivity.java index d75e372..972e78a 100644 --- a/app/src/main/java/chaoran/business/activity/MainActivity.java +++ b/app/src/main/java/chaoran/business/activity/MainActivity.java @@ -16,6 +16,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.MediaPlayer; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Vibrator; @@ -58,6 +59,7 @@ import chaoran.business.service.ScanServiceZEBRA; import chaoran.business.utils.DataCleanManager; import chaoran.business.utils.LocalAddressUtil; import chaoran.business.utils.StatusBarUtil; +import chaoran.business.utils.FileChooserHelper; /** * 流程:联网认证设备型号,验证通过,查找设备品牌进行调用驱动操作 @@ -77,6 +79,7 @@ public class MainActivity extends AppCompatActivity implements ResultListener{ private SettingEngine settingEngine; private ProgressBar progressBar; private ActionBar actionBar; + private FileChooserHelper fileChooserHelper; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -215,9 +218,11 @@ public class MainActivity extends AppCompatActivity implements ResultListener{ actionBar = getSupportActionBar(); voiceEngine = new TekVoiceEngine(this); settingEngine = new NetworkSettingEngine(this); + fileChooserHelper = new FileChooserHelper(this); webView = findViewById(R.id.webView); progressBar = findViewById(R.id.loading); webView.setWebViewClient(disposeView()); + webView.setWebChromeClient(createWebChromeClient()); WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); @@ -241,6 +246,48 @@ public class MainActivity extends AppCompatActivity implements ResultListener{ private boolean isPageFinished = false; // 新增标志位 + /** + * 创建WebChromeClient以支持文件选择 + */ + private WebChromeClient createWebChromeClient() { + return new WebChromeClient() { + // For Android 5.0+ + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + // 检查是否接受图片 + String[] acceptTypes = fileChooserParams.getAcceptTypes(); + boolean acceptImage = false; + boolean acceptCamera = false; + boolean cameraOnly = false; + + if (acceptTypes != null && acceptTypes.length > 0) { + for (String type : acceptTypes) { + if (type.contains("image")) { + acceptImage = true; + break; + } + } + } + + // 检查capture模式 + if (fileChooserParams.isCaptureEnabled()) { + acceptCamera = true; + + // 注意:Android WebView中,capture="user"或capture="environment"都会返回true + // 我们通过简单的方式判断:如果是图片且启用capture,默认显示选择器 + // 只有在特定情况下才直接打开相机 + + // 这里我们不设置cameraOnly=true,让所有capture都显示选择器 + // 如果需要仅相机模式,可以通过其他方式(如URL参数)来控制 + } + + fileChooserHelper.openFileChooser(filePathCallback, acceptImage, acceptCamera, cameraOnly); + return true; + } + }; + } + //配置客户端 private WebViewClient disposeView() { return new WebViewClient() { @@ -391,6 +438,9 @@ public class MainActivity extends AppCompatActivity implements ResultListener{ case R.id.action_setting_voice: startActivity(new Intent(this, VoiceSettingActivity.class)); break; + case R.id.action_file_test: + startActivity(new Intent(this, FileTestActivity.class)); + break; } return super.onOptionsItemSelected(item); } @@ -529,4 +579,20 @@ public class MainActivity extends AppCompatActivity implements ResultListener{ .show(); // 不调用 super.onBackPressed(),避免直接退出 } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (!fileChooserHelper.onActivityResult(requestCode, resultCode, data)) { + // 如果不是文件选择器的结果,可以在这里处理其他结果 + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (!fileChooserHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + // 如果不是文件选择器的权限请求,可以在这里处理其他权限请求 + } + } } \ No newline at end of file diff --git a/app/src/main/java/chaoran/business/utils/CameraHelper.java b/app/src/main/java/chaoran/business/utils/CameraHelper.java new file mode 100644 index 0000000..6496343 --- /dev/null +++ b/app/src/main/java/chaoran/business/utils/CameraHelper.java @@ -0,0 +1,97 @@ +package chaoran.business.utils; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; + +import androidx.core.content.FileProvider; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * 相机辅助类 - 通过JavaScript接口直接调用相机 + */ +public class CameraHelper { + + private static final int REQUEST_CODE_CAMERA_DIRECT = 1003; + private Activity activity; + private WebView webView; + private Uri cameraPhotoUri; + private String currentPhotoPath; + + public CameraHelper(Activity activity, WebView webView) { + this.activity = activity; + this.webView = webView; + } + + /** + * 直接打开相机拍照 + */ + @JavascriptInterface + public void openCamera() { + activity.runOnUiThread(() -> { + Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (cameraIntent.resolveActivity(activity.getPackageManager()) != null) { + File photoFile = createImageFile(); + if (photoFile != null) { + currentPhotoPath = photoFile.getAbsolutePath(); + cameraPhotoUri = FileProvider.getUriForFile( + activity, + activity.getPackageName() + ".fileprovider", + photoFile + ); + cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPhotoUri); + cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + activity.startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA_DIRECT); + } + } + }); + } + + /** + * 创建图片文件 + */ + private File createImageFile() { + try { + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); + String imageFileName = "JPEG_" + timeStamp + "_"; + File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + if (storageDir != null && !storageDir.exists()) { + storageDir.mkdirs(); + } + return File.createTempFile(imageFileName, ".jpg", storageDir); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 处理Activity结果 + */ + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_CAMERA_DIRECT) { + if (resultCode == Activity.RESULT_OK && cameraPhotoUri != null) { + // 通知JavaScript照片已拍摄 + String jsCode = "javascript:onCameraResult('" + cameraPhotoUri.toString() + "', '" + currentPhotoPath + "')"; + webView.post(() -> webView.loadUrl(jsCode)); + } else { + // 取消拍照 + String jsCode = "javascript:onCameraResult(null, null)"; + webView.post(() -> webView.loadUrl(jsCode)); + } + cameraPhotoUri = null; + currentPhotoPath = null; + return true; + } + return false; + } +} diff --git a/app/src/main/java/chaoran/business/utils/FileChooserHelper.java b/app/src/main/java/chaoran/business/utils/FileChooserHelper.java new file mode 100644 index 0000000..3471a20 --- /dev/null +++ b/app/src/main/java/chaoran/business/utils/FileChooserHelper.java @@ -0,0 +1,378 @@ +package chaoran.business.utils; + +import android.Manifest; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import android.util.Base64; +import android.util.Log; +import android.webkit.ValueCallback; +import android.widget.Toast; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * 文件选择和相机拍照辅助类 + */ +public class FileChooserHelper { + + private static final String TAG = "FileChooserHelper"; + private static final int REQUEST_CODE_CAMERA = 1001; + private static final int REQUEST_CODE_FILE_CHOOSER = 1002; + private static final int REQUEST_CODE_PERMISSION_CAMERA = 2001; + private static final int REQUEST_CODE_PERMISSION_STORAGE = 2002; + + private Activity activity; + private ValueCallback filePathCallback; + private Uri cameraPhotoUri; + private boolean pendingAcceptImage = false; + private boolean pendingAcceptCamera = false; + private boolean pendingCameraOnly = false; + + public FileChooserHelper(Activity activity) { + this.activity = activity; + } + + /** + * 打开文件选择器(支持相机和图片选择) + */ + public void openFileChooser(ValueCallback callback, boolean acceptImage, boolean acceptCamera) { + openFileChooser(callback, acceptImage, acceptCamera, false); + } + + /** + * 打开文件选择器(支持相机和图片选择) + * @param callback 文件选择回调 + * @param acceptImage 是否只接受图片 + * @param acceptCamera 是否支持相机 + * @param cameraOnly 是否仅使用相机(不显示文件选择器) + */ + public void openFileChooser(ValueCallback callback, boolean acceptImage, boolean acceptCamera, boolean cameraOnly) { + this.filePathCallback = callback; + this.pendingAcceptImage = acceptImage; + this.pendingAcceptCamera = acceptCamera; + this.pendingCameraOnly = cameraOnly; + + // 检查权限 + if (acceptCamera && !checkCameraPermission()) { + requestCameraPermission(); + return; + } + + if (!cameraOnly && !checkStoragePermission()) { + requestStoragePermission(); + return; + } + + // 创建选择器 + showFileChooser(); + } + + /** + * 显示文件选择器 + */ + private void showFileChooser() { + Intent chooserIntent = createChooserIntent(pendingAcceptImage, pendingAcceptCamera); + if (chooserIntent != null) { + try { + activity.startActivityForResult(chooserIntent, REQUEST_CODE_FILE_CHOOSER); + } catch (Exception e) { + Log.e(TAG, "打开文件选择器失败", e); + Toast.makeText(activity, "打开文件选择器失败", Toast.LENGTH_SHORT).show(); + if (filePathCallback != null) { + filePathCallback.onReceiveValue(null); + filePathCallback = null; + } + } + } + } + + /** + * 创建选择器Intent + */ + private Intent createChooserIntent(boolean acceptImage, boolean acceptCamera) { + // 如果只需要相机,直接返回相机Intent + if (acceptCamera && pendingCameraOnly) { + return createCameraIntent(); + } + + Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); + Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); + contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); + + if (acceptImage) { + contentSelectionIntent.setType("image/*"); + } else { + contentSelectionIntent.setType("*/*"); + } + + Intent[] intentArray; + if (acceptCamera) { + Intent cameraIntent = createCameraIntent(); + if (cameraIntent != null) { + intentArray = new Intent[]{cameraIntent}; + } else { + intentArray = new Intent[0]; + } + } else { + intentArray = new Intent[0]; + } + + chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); + chooserIntent.putExtra(Intent.EXTRA_TITLE, "选择文件"); + + return chooserIntent; + } + + /** + * 创建相机Intent + */ + private Intent createCameraIntent() { + Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (cameraIntent.resolveActivity(activity.getPackageManager()) != null) { + File photoFile = createImageFile(); + if (photoFile != null) { + cameraPhotoUri = FileProvider.getUriForFile( + activity, + activity.getPackageName() + ".fileprovider", + photoFile + ); + cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPhotoUri); + cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + return cameraIntent; + } + } + return null; + } + + /** + * 创建图片文件 + */ + private File createImageFile() { + try { + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); + String imageFileName = "JPEG_" + timeStamp + "_"; + File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + if (storageDir != null && !storageDir.exists()) { + storageDir.mkdirs(); + } + return File.createTempFile(imageFileName, ".jpg", storageDir); + } catch (IOException e) { + Log.e(TAG, "创建图片文件失败", e); + return null; + } + } + + /** + * 处理Activity结果 + */ + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_FILE_CHOOSER) { + if (filePathCallback == null) { + return true; + } + + Uri[] results = null; + if (resultCode == Activity.RESULT_OK) { + if (data != null && data.getData() != null) { + // 从文件选择器选择的文件 + results = new Uri[]{data.getData()}; + } else if (cameraPhotoUri != null) { + // 从相机拍摄的照片 + results = new Uri[]{cameraPhotoUri}; + } + } + + filePathCallback.onReceiveValue(results); + filePathCallback = null; + cameraPhotoUri = null; + return true; + } + return false; + } + + /** + * 处理权限请求结果 + */ + public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Toast.makeText(activity, "相机权限已授予", Toast.LENGTH_SHORT).show(); + // 权限授予后,检查存储权限 + if (!checkStoragePermission()) { + requestStoragePermission(); + } else { + // 权限都已授予,重新打开文件选择器 + showFileChooser(); + } + } else { + Toast.makeText(activity, "相机权限被拒绝", Toast.LENGTH_SHORT).show(); + if (filePathCallback != null) { + filePathCallback.onReceiveValue(null); + filePathCallback = null; + } + } + return true; + } else if (requestCode == REQUEST_CODE_PERMISSION_STORAGE) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Toast.makeText(activity, "存储权限已授予", Toast.LENGTH_SHORT).show(); + // 权限授予后,重新打开文件选择器 + showFileChooser(); + } else { + Toast.makeText(activity, "存储权限被拒绝", Toast.LENGTH_SHORT).show(); + if (filePathCallback != null) { + filePathCallback.onReceiveValue(null); + filePathCallback = null; + } + } + return true; + } + return false; + } + + /** + * 检查相机权限 + */ + private boolean checkCameraPermission() { + return ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * 请求相机权限 + */ + private void requestCameraPermission() { + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.CAMERA}, + REQUEST_CODE_PERMISSION_CAMERA); + } + + /** + * 检查存储权限 + * Android 10+ 使用分区存储,不需要READ_EXTERNAL_STORAGE权限来访问通过文件选择器选择的文件 + */ + private boolean checkStoragePermission() { + if (Build.VERSION.SDK_INT >= 33) { // Android 13 (TIRAMISU) + // Android 13+ 使用新的媒体权限 + return ContextCompat.checkSelfPermission(activity, "android.permission.READ_MEDIA_IMAGES") + == PackageManager.PERMISSION_GRANTED; + } else if (Build.VERSION.SDK_INT >= 29) { // Android 10 (Q) + // Android 10-12 使用分区存储,通过文件选择器不需要权限 + return true; + } else { + // Android 9 需要存储权限 + return ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED; + } + } + + /** + * 请求存储权限 + */ + private void requestStoragePermission() { + if (Build.VERSION.SDK_INT >= 33) { // Android 13 (TIRAMISU) + // Android 13+ 请求新的媒体权限 + ActivityCompat.requestPermissions(activity, + new String[]{"android.permission.READ_MEDIA_IMAGES"}, + REQUEST_CODE_PERMISSION_STORAGE); + } else if (Build.VERSION.SDK_INT >= 29) { // Android 10 (Q) + // Android 10-12 不需要请求权限 + Toast.makeText(activity, "存储权限已授予", Toast.LENGTH_SHORT).show(); + } else { + // Android 9 请求存储权限 + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + REQUEST_CODE_PERMISSION_STORAGE); + } + } + + /** + * 获取文件名 + */ + public static String getFileName(Context context, Uri uri) { + String result = null; + if (uri.getScheme().equals("content")) { + try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (nameIndex >= 0) { + result = cursor.getString(nameIndex); + } + } + } catch (Exception e) { + Log.e(TAG, "获取文件名失败", e); + } + } + if (result == null) { + result = uri.getPath(); + int cut = result.lastIndexOf('/'); + if (cut != -1) { + result = result.substring(cut + 1); + } + } + return result; + } + + /** + * 将文件转换为Base64字符串 + */ + public static String fileToBase64(Context context, Uri uri) { + try { + InputStream inputStream = context.getContentResolver().openInputStream(uri); + if (inputStream == null) { + return null; + } + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + byteArrayOutputStream.write(buffer, 0, bytesRead); + } + inputStream.close(); + + byte[] fileBytes = byteArrayOutputStream.toByteArray(); + return Base64.encodeToString(fileBytes, Base64.NO_WRAP); + } catch (Exception e) { + Log.e(TAG, "文件转Base64失败", e); + return null; + } + } + + /** + * 获取文件大小 + */ + public static long getFileSize(Context context, Uri uri) { + try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + if (sizeIndex >= 0) { + return cursor.getLong(sizeIndex); + } + } + } catch (Exception e) { + Log.e(TAG, "获取文件大小失败", e); + } + return 0; + } +} diff --git a/app/src/main/res/layout/activity_file_test.xml b/app/src/main/res/layout/activity_file_test.xml new file mode 100644 index 0000000..f1f61f7 --- /dev/null +++ b/app/src/main/res/layout/activity_file_test.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 51329b7..94a3e0c 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -14,4 +14,10 @@ android:orderInCategory="100" app:showAsAction="never" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4956bff..e53f989 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,6 +4,8 @@ 网络设置界面 语音设置 语音设置界面 + 文件测试 + 文件选择测试 主页 diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..bbed4a8 --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,7 @@ + + + + + + +