list) {
- super(fragmentActivity);
-
- this.fragments = new ArrayList<>();
- if (!list.isEmpty()) {
- this.fragments.addAll(list);
- }
- }
-
- @NonNull
- @Override
- public Fragment createFragment(int position) {
- return fragments.get(position);
- }
-
- @Override
- public int getItemCount() {
- return fragments.size();
- }
-}
diff --git a/app/src/main/java/com/assimilate/alltrans/allservice/SusService.kt b/app/src/main/java/com/assimilate/alltrans/allservice/SusService.kt
new file mode 100644
index 0000000..3eb84f1
--- /dev/null
+++ b/app/src/main/java/com/assimilate/alltrans/allservice/SusService.kt
@@ -0,0 +1,275 @@
+package com.assimilate.alltrans.allservice
+
+import android.app.*
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.PixelFormat
+import android.hardware.display.DisplayManager
+import android.hardware.display.VirtualDisplay
+import android.media.ImageReader
+import android.media.projection.MediaProjection
+import android.media.projection.MediaProjectionManager
+import android.os.*
+import android.util.DisplayMetrics
+import android.util.Log
+import android.view.*
+import androidx.core.app.NotificationCompat
+import com.assimilate.alltrans.R
+import com.assimilate.alltrans.common.TextRecognitionProcessor
+import com.assimilate.alltrans.common.VisionImageProcessor
+import com.assimilate.alltrans.databinding.SusControlViewBinding
+import com.assimilate.alltrans.databinding.LayoutSusGlobalBinding
+import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
+import java.io.IOException
+
+class SusService : Service() {
+ private var imageProcessor: VisionImageProcessor? = null
+ private lateinit var mediaProjectionManager: MediaProjectionManager
+ private lateinit var mediaProjection: MediaProjection
+ private lateinit var virtualDisplay: VirtualDisplay
+ private lateinit var displayMetrics: DisplayMetrics
+
+ private lateinit var windowManager: WindowManager
+ private lateinit var floatingView: View
+ private lateinit var globalView: View
+
+ private lateinit var bindingSusControl: SusControlViewBinding
+ private lateinit var bindingSubGlobal: LayoutSusGlobalBinding
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ mediaProjectionManager =
+ getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
+ displayMetrics = DisplayMetrics()
+ windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
+ windowManager.defaultDisplay?.getMetrics(displayMetrics)
+
+ initSusView()
+ startForeground(1, createNotification())
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ val resultCode = intent?.getIntExtra("resultCode", Activity.RESULT_OK)
+ val data: Intent? = intent?.getParcelableExtra("data")
+ if (resultCode != null && data != null) {
+ startScreenshot(resultCode, data)
+ }
+ return START_NOT_STICKY
+ }
+
+ private fun initSusView() {
+ windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
+
+ bindingSusControl = SusControlViewBinding.inflate(LayoutInflater.from(this))
+ floatingView = bindingSusControl.root
+
+ val layoutParams = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+ } else {
+ WindowManager.LayoutParams.TYPE_PHONE
+ },
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT
+ )
+ layoutParams.gravity = Gravity.TOP or Gravity.LEFT
+ layoutParams.x = 0
+ layoutParams.y = 100
+
+ windowManager.addView(floatingView, layoutParams)
+
+ // 设置点击事件
+ bindingSusControl.tvSusGlobal.setOnClickListener {
+ // 处理全局翻译点击事件
+ addGlobalView()
+ }
+
+ bindingSusControl.tvSusCopy.setOnClickListener {
+ // 处理复制文本点击事件
+ }
+
+ bindingSusControl.tvSusPhoto.setOnClickListener {
+ // 处理照片翻译点击事件
+ }
+
+ bindingSusControl.tvSusDistrict.setOnClickListener {
+ // 处理地区翻译点击事件
+ }
+
+ bindingSusControl.ivSusHome.setOnClickListener {
+ // 处理返回主页点击事件
+ }
+
+ bindingSusControl.ivSusMove.setOnClickListener {
+ // 处理移动窗口点击事件
+ }
+
+ bindingSusControl.ivSusMove.setOnTouchListener(object : View.OnTouchListener {
+ private var startX = 0f
+ private var startY = 0f
+ private var touchX = 0f
+ private var touchY = 0f
+
+ override fun onTouch(v: View, event: MotionEvent): Boolean {
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ startX = layoutParams.x.toFloat()
+ startY = layoutParams.y.toFloat()
+
+ touchX = event.rawX
+ touchY = event.rawY
+ return true
+ }
+
+ MotionEvent.ACTION_MOVE -> {
+ layoutParams.x = (startX + (event.rawX - touchX)).toInt()
+ layoutParams.y = (startY + (event.rawY - touchY)).toInt()
+ windowManager.updateViewLayout(floatingView, layoutParams)
+ return true
+ }
+
+ MotionEvent.ACTION_UP -> return true
+ }
+ return false
+ }
+ })
+ }
+
+ private fun addGlobalView() {
+ windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
+
+ bindingSubGlobal = LayoutSusGlobalBinding.inflate(LayoutInflater.from(this))
+ globalView = bindingSubGlobal.root
+ imageProcessor = TextRecognitionProcessor(
+ this,
+ ChineseTextRecognizerOptions.Builder().build()
+ )
+
+ val layoutParams = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+ } else {
+ WindowManager.LayoutParams.TYPE_PHONE
+ },
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT
+ )
+ layoutParams.gravity = Gravity.TOP or Gravity.LEFT
+ layoutParams.x = 0
+ layoutParams.y = 100
+
+ windowManager.addView(globalView, layoutParams)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (floatingView.isAttachedToWindow) {
+ windowManager.removeView(floatingView)
+ }
+ if (::globalView.isInitialized && globalView.isAttachedToWindow) {
+ windowManager.removeView(globalView)
+ }
+ }
+
+ private fun createNotification(): Notification {
+ val notificationChannelId = "FOREGROUND_SERVICE_CHANNEL"
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channelName = "Foreground Service Channel"
+ val chan = NotificationChannel(
+ notificationChannelId,
+ channelName,
+ NotificationManager.IMPORTANCE_NONE
+ )
+ val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ manager.createNotificationChannel(chan)
+ }
+
+ val builder = NotificationCompat.Builder(this, notificationChannelId)
+ .setContentTitle("悬浮窗服务")
+ .setContentText("悬浮窗服务正在运行")
+ .setSmallIcon(R.drawable.ic_close)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setCategory(Notification.CATEGORY_SERVICE)
+
+ return builder.build()
+ }
+
+ private fun tryReloadAndDetectInImage(bitmap: Bitmap) {
+ try {
+ // Clear the overlay first
+ bindingSubGlobal.susGraphicOverlay.clear()
+
+ if (imageProcessor != null) {
+ bindingSubGlobal.susGraphicOverlay.setImageSourceInfo(
+ bitmap.width,
+ bitmap.height,
+ false
+ )
+ imageProcessor!!.processBitmap(bitmap, bindingSubGlobal.susGraphicOverlay)
+ } else {
+ Log.e(
+ "SusService",
+ "Null imageProcessor, please check adb logs for imageProcessor creation error"
+ )
+ }
+ } catch (e: IOException) {
+ Log.e("SusService", "Error retrieving saved image")
+ }
+ }
+
+ fun startScreenshot(resultCode: Int, data: Intent?) {
+ mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data!!)
+ val imageReader = ImageReader.newInstance(
+ displayMetrics.widthPixels,
+ displayMetrics.heightPixels,
+ PixelFormat.RGBA_8888,
+ 2
+ )
+
+ virtualDisplay = mediaProjection.createVirtualDisplay(
+ "Screenshot",
+ displayMetrics.widthPixels,
+ displayMetrics.heightPixels,
+ displayMetrics.densityDpi,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+ imageReader.surface,
+ null,
+ null
+ )
+
+ // 初始化 globalView
+ addGlobalView()
+
+ Handler(Looper.getMainLooper()).postDelayed({
+ val image = imageReader.acquireLatestImage()
+ if (image != null) {
+ val planes = image.planes
+ val buffer = planes[0].buffer
+ val pixelStride = planes[0].pixelStride
+ val rowStride = planes[0].rowStride
+ val rowPadding = rowStride - pixelStride * displayMetrics.widthPixels
+
+ val bitmap = Bitmap.createBitmap(
+ displayMetrics.widthPixels + rowPadding / pixelStride,
+ displayMetrics.heightPixels,
+ Bitmap.Config.ARGB_8888
+ )
+ bitmap.copyPixelsFromBuffer(buffer)
+ image.close()
+ bindingSubGlobal.preview.setImageBitmap(bitmap)
+ tryReloadAndDetectInImage(bitmap)
+ }
+ stopSelf()
+ }, 1000)
+ }
+}
diff --git a/app/src/main/java/com/assimilate/alltrans/common/BitmapUtils.java b/app/src/main/java/com/assimilate/alltrans/common/BitmapUtils.java
index 42f32a4..caf957c 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/BitmapUtils.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/BitmapUtils.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
@@ -41,244 +26,254 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
-/** Utils functions for bitmap conversions. */
+/**
+ * Utils functions for bitmap conversions.
+ */
public class BitmapUtils {
- private static final String TAG = "BitmapUtils";
+ private static final String TAG = "BitmapUtils";
- /** Converts NV21 format byte buffer to bitmap. */
- @Nullable
- public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
- data.rewind();
- byte[] imageInBuffer = new byte[data.limit()];
- data.get(imageInBuffer, 0, imageInBuffer.length);
- try {
- YuvImage image =
- new YuvImage(
- imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
+ /**
+ * Converts NV21 format byte buffer to bitmap.
+ */
+ @Nullable
+ public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
+ data.rewind();
+ byte[] imageInBuffer = new byte[data.limit()];
+ data.get(imageInBuffer, 0, imageInBuffer.length);
+ try {
+ YuvImage image =
+ new YuvImage(
+ imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
- Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
+ Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
- stream.close();
- return rotateBitmap(bmp, metadata.getRotation(), false, false);
- } catch (Exception e) {
- Log.e("VisionProcessorBase", "Error: " + e.getMessage());
- }
- return null;
- }
-
- /** Converts a YUV_420_888 image from CameraX API to a bitmap. */
- @RequiresApi(VERSION_CODES.LOLLIPOP)
- @Nullable
- @ExperimentalGetImage
- public static Bitmap getBitmap(ImageProxy image) {
- FrameMetadata frameMetadata =
- new FrameMetadata.Builder()
- .setWidth(image.getWidth())
- .setHeight(image.getHeight())
- .setRotation(image.getImageInfo().getRotationDegrees())
- .build();
-
- ByteBuffer nv21Buffer =
- yuv420ThreePlanesToNV21(image.getImage().getPlanes(), image.getWidth(), image.getHeight());
- return getBitmap(nv21Buffer, frameMetadata);
- }
-
- /** Rotates a bitmap if it is converted from a bytebuffer. */
- private static Bitmap rotateBitmap(
- Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
- Matrix matrix = new Matrix();
-
- // Rotate the image back to straight.
- matrix.postRotate(rotationDegrees);
-
- // Mirror the image along the X or Y axis.
- matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
- Bitmap rotatedBitmap =
- Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
-
- // Recycle the old bitmap if it has changed.
- if (rotatedBitmap != bitmap) {
- bitmap.recycle();
- }
- return rotatedBitmap;
- }
-
- @Nullable
- public static Bitmap getBitmapFromContentUri(ContentResolver contentResolver, Uri imageUri)
- throws IOException {
- Bitmap decodedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);
- if (decodedBitmap == null) {
- return null;
- }
- int orientation = getExifOrientationTag(contentResolver, imageUri);
-
- int rotationDegrees = 0;
- boolean flipX = false;
- boolean flipY = false;
- // See e.g. https://magnushoff.com/articles/jpeg-orientation/ for a detailed explanation on each
- // orientation.
- switch (orientation) {
- case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
- flipX = true;
- break;
- case ExifInterface.ORIENTATION_ROTATE_90:
- rotationDegrees = 90;
- break;
- case ExifInterface.ORIENTATION_TRANSPOSE:
- rotationDegrees = 90;
- flipX = true;
- break;
- case ExifInterface.ORIENTATION_ROTATE_180:
- rotationDegrees = 180;
- break;
- case ExifInterface.ORIENTATION_FLIP_VERTICAL:
- flipY = true;
- break;
- case ExifInterface.ORIENTATION_ROTATE_270:
- rotationDegrees = -90;
- break;
- case ExifInterface.ORIENTATION_TRANSVERSE:
- rotationDegrees = -90;
- flipX = true;
- break;
- case ExifInterface.ORIENTATION_UNDEFINED:
- case ExifInterface.ORIENTATION_NORMAL:
- default:
- // No transformations necessary in this case.
+ stream.close();
+ return rotateBitmap(bmp, metadata.getRotation(), false, false);
+ } catch (Exception e) {
+ Log.e("VisionProcessorBase", "Error: " + e.getMessage());
+ }
+ return null;
}
- return rotateBitmap(decodedBitmap, rotationDegrees, flipX, flipY);
- }
+ /**
+ * Converts a YUV_420_888 image from CameraX API to a bitmap.
+ */
+ @RequiresApi(VERSION_CODES.LOLLIPOP)
+ @Nullable
+ @ExperimentalGetImage
+ public static Bitmap getBitmap(ImageProxy image) {
+ FrameMetadata frameMetadata =
+ new FrameMetadata.Builder()
+ .setWidth(image.getWidth())
+ .setHeight(image.getHeight())
+ .setRotation(image.getImageInfo().getRotationDegrees())
+ .build();
- private static int getExifOrientationTag(ContentResolver resolver, Uri imageUri) {
- // We only support parsing EXIF orientation tag from local file on the device.
- // See also:
- // https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html
- if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())
- && !ContentResolver.SCHEME_FILE.equals(imageUri.getScheme())) {
- return 0;
+ ByteBuffer nv21Buffer =
+ yuv420ThreePlanesToNV21(image.getImage().getPlanes(), image.getWidth(), image.getHeight());
+ return getBitmap(nv21Buffer, frameMetadata);
}
- ExifInterface exif;
- try (InputStream inputStream = resolver.openInputStream(imageUri)) {
- if (inputStream == null) {
- return 0;
- }
+ /**
+ * Rotates a bitmap if it is converted from a bytebuffer.
+ */
+ private static Bitmap rotateBitmap(
+ Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
+ Matrix matrix = new Matrix();
- exif = new ExifInterface(inputStream);
- } catch (IOException e) {
- Log.e(TAG, "failed to open file to read rotation meta data: " + imageUri, e);
- return 0;
+ // Rotate the image back to straight.
+ matrix.postRotate(rotationDegrees);
+
+ // Mirror the image along the X or Y axis.
+ matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
+ Bitmap rotatedBitmap =
+ Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+
+ // Recycle the old bitmap if it has changed.
+ if (rotatedBitmap != bitmap) {
+ bitmap.recycle();
+ }
+ return rotatedBitmap;
}
- return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
- }
+ @Nullable
+ public static Bitmap getBitmapFromContentUri(ContentResolver contentResolver, Uri imageUri)
+ throws IOException {
+ Bitmap decodedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);
+ if (decodedBitmap == null) {
+ return null;
+ }
+ int orientation = getExifOrientationTag(contentResolver, imageUri);
- /**
- * Converts YUV_420_888 to NV21 bytebuffer.
- *
- * The NV21 format consists of a single byte array containing the Y, U and V values. For an
- * image of size S, the first S positions of the array contain all the Y values. The remaining
- * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both
- * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain
- * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU
- *
- *
YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled
- * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and
- * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into
- * the first part of the NV21 array. The U and V planes may already have the representation in the
- * NV21 format. This happens if the planes share the same buffer, the V buffer is one position
- * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy
- * them to the NV21 array.
- */
- private static ByteBuffer yuv420ThreePlanesToNV21(
- Plane[] yuv420888planes, int width, int height) {
- int imageSize = width * height;
- byte[] out = new byte[imageSize + 2 * (imageSize / 4)];
+ int rotationDegrees = 0;
+ boolean flipX = false;
+ boolean flipY = false;
+ // See e.g. https://magnushoff.com/articles/jpeg-orientation/ for a detailed explanation on each
+ // orientation.
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ rotationDegrees = 90;
+ break;
+ case ExifInterface.ORIENTATION_TRANSPOSE:
+ rotationDegrees = 90;
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ rotationDegrees = 180;
+ break;
+ case ExifInterface.ORIENTATION_FLIP_VERTICAL:
+ flipY = true;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ rotationDegrees = -90;
+ break;
+ case ExifInterface.ORIENTATION_TRANSVERSE:
+ rotationDegrees = -90;
+ flipX = true;
+ break;
+ case ExifInterface.ORIENTATION_UNDEFINED:
+ case ExifInterface.ORIENTATION_NORMAL:
+ default:
+ // No transformations necessary in this case.
+ }
- if (areUVPlanesNV21(yuv420888planes, width, height)) {
- // Copy the Y values.
- yuv420888planes[0].getBuffer().get(out, 0, imageSize);
-
- ByteBuffer uBuffer = yuv420888planes[1].getBuffer();
- ByteBuffer vBuffer = yuv420888planes[2].getBuffer();
- // Get the first V value from the V buffer, since the U buffer does not contain it.
- vBuffer.get(out, imageSize, 1);
- // Copy the first U value and the remaining VU values from the U buffer.
- uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);
- } else {
- // Fallback to copying the UV values one by one, which is slower but also works.
- // Unpack Y.
- unpackPlane(yuv420888planes[0], width, height, out, 0, 1);
- // Unpack U.
- unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);
- // Unpack V.
- unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);
+ return rotateBitmap(decodedBitmap, rotationDegrees, flipX, flipY);
}
- return ByteBuffer.wrap(out);
- }
+ private static int getExifOrientationTag(ContentResolver resolver, Uri imageUri) {
+ // We only support parsing EXIF orientation tag from local file on the device.
+ // See also:
+ // https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html
+ if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())
+ && !ContentResolver.SCHEME_FILE.equals(imageUri.getScheme())) {
+ return 0;
+ }
- /** Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format. */
- private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {
- int imageSize = width * height;
+ ExifInterface exif;
+ try (InputStream inputStream = resolver.openInputStream(imageUri)) {
+ if (inputStream == null) {
+ return 0;
+ }
- ByteBuffer uBuffer = planes[1].getBuffer();
- ByteBuffer vBuffer = planes[2].getBuffer();
+ exif = new ExifInterface(inputStream);
+ } catch (IOException e) {
+ Log.e(TAG, "failed to open file to read rotation meta data: " + imageUri, e);
+ return 0;
+ }
- // Backup buffer properties.
- int vBufferPosition = vBuffer.position();
- int uBufferLimit = uBuffer.limit();
-
- // Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.
- vBuffer.position(vBufferPosition + 1);
- // Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.
- uBuffer.limit(uBufferLimit - 1);
-
- // Check that the buffers are equal and have the expected number of elements.
- boolean areNV21 =
- (vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);
-
- // Restore buffers to their initial state.
- vBuffer.position(vBufferPosition);
- uBuffer.limit(uBufferLimit);
-
- return areNV21;
- }
-
- /**
- * Unpack an image plane into a byte array.
- *
- *
The input plane data will be copied in 'out', starting at 'offset' and every pixel will be
- * spaced by 'pixelStride'. Note that there is no row padding on the output.
- */
- private static void unpackPlane(
- Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {
- ByteBuffer buffer = plane.getBuffer();
- buffer.rewind();
-
- // Compute the size of the current plane.
- // We assume that it has the aspect ratio as the original image.
- int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();
- if (numRow == 0) {
- return;
+ return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
- int scaleFactor = height / numRow;
- int numCol = width / scaleFactor;
- // Extract the data in the output buffer.
- int outputPos = offset;
- int rowStart = 0;
- for (int row = 0; row < numRow; row++) {
- int inputPos = rowStart;
- for (int col = 0; col < numCol; col++) {
- out[outputPos] = buffer.get(inputPos);
- outputPos += pixelStride;
- inputPos += plane.getPixelStride();
- }
- rowStart += plane.getRowStride();
+ /**
+ * Converts YUV_420_888 to NV21 bytebuffer.
+ *
+ *
The NV21 format consists of a single byte array containing the Y, U and V values. For an
+ * image of size S, the first S positions of the array contain all the Y values. The remaining
+ * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both
+ * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain
+ * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU
+ *
+ *
YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled
+ * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and
+ * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into
+ * the first part of the NV21 array. The U and V planes may already have the representation in the
+ * NV21 format. This happens if the planes share the same buffer, the V buffer is one position
+ * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy
+ * them to the NV21 array.
+ */
+ private static ByteBuffer yuv420ThreePlanesToNV21(
+ Plane[] yuv420888planes, int width, int height) {
+ int imageSize = width * height;
+ byte[] out = new byte[imageSize + 2 * (imageSize / 4)];
+
+ if (areUVPlanesNV21(yuv420888planes, width, height)) {
+ // Copy the Y values.
+ yuv420888planes[0].getBuffer().get(out, 0, imageSize);
+
+ ByteBuffer uBuffer = yuv420888planes[1].getBuffer();
+ ByteBuffer vBuffer = yuv420888planes[2].getBuffer();
+ // Get the first V value from the V buffer, since the U buffer does not contain it.
+ vBuffer.get(out, imageSize, 1);
+ // Copy the first U value and the remaining VU values from the U buffer.
+ uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);
+ } else {
+ // Fallback to copying the UV values one by one, which is slower but also works.
+ // Unpack Y.
+ unpackPlane(yuv420888planes[0], width, height, out, 0, 1);
+ // Unpack U.
+ unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);
+ // Unpack V.
+ unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);
+ }
+
+ return ByteBuffer.wrap(out);
+ }
+
+ /**
+ * Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format.
+ */
+ private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {
+ int imageSize = width * height;
+
+ ByteBuffer uBuffer = planes[1].getBuffer();
+ ByteBuffer vBuffer = planes[2].getBuffer();
+
+ // Backup buffer properties.
+ int vBufferPosition = vBuffer.position();
+ int uBufferLimit = uBuffer.limit();
+
+ // Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.
+ vBuffer.position(vBufferPosition + 1);
+ // Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.
+ uBuffer.limit(uBufferLimit - 1);
+
+ // Check that the buffers are equal and have the expected number of elements.
+ boolean areNV21 =
+ (vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);
+
+ // Restore buffers to their initial state.
+ vBuffer.position(vBufferPosition);
+ uBuffer.limit(uBufferLimit);
+
+ return areNV21;
+ }
+
+ /**
+ * Unpack an image plane into a byte array.
+ *
+ *
The input plane data will be copied in 'out', starting at 'offset' and every pixel will be
+ * spaced by 'pixelStride'. Note that there is no row padding on the output.
+ */
+ private static void unpackPlane(
+ Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {
+ ByteBuffer buffer = plane.getBuffer();
+ buffer.rewind();
+
+ // Compute the size of the current plane.
+ // We assume that it has the aspect ratio as the original image.
+ int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();
+ if (numRow == 0) {
+ return;
+ }
+ int scaleFactor = height / numRow;
+ int numCol = width / scaleFactor;
+
+ // Extract the data in the output buffer.
+ int outputPos = offset;
+ int rowStart = 0;
+ for (int row = 0; row < numRow; row++) {
+ int inputPos = rowStart;
+ for (int col = 0; col < numCol; col++) {
+ out[outputPos] = buffer.get(inputPos);
+ outputPos += pixelStride;
+ inputPos += plane.getPixelStride();
+ }
+ rowStart += plane.getRowStride();
+ }
}
- }
}
diff --git a/app/src/main/java/com/assimilate/alltrans/common/CameraImageGraphic.java b/app/src/main/java/com/assimilate/alltrans/common/CameraImageGraphic.java
index c783a2e..285db42 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/CameraImageGraphic.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/CameraImageGraphic.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
diff --git a/app/src/main/java/com/assimilate/alltrans/common/FrameMetadata.java b/app/src/main/java/com/assimilate/alltrans/common/FrameMetadata.java
index e9d2242..5364c29 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/FrameMetadata.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/FrameMetadata.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
diff --git a/app/src/main/java/com/assimilate/alltrans/common/InferenceInfoGraphic.java b/app/src/main/java/com/assimilate/alltrans/common/InferenceInfoGraphic.java
index 2d070ca..703162c 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/InferenceInfoGraphic.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/InferenceInfoGraphic.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
diff --git a/app/src/main/java/com/assimilate/alltrans/common/PreferenceUtils.java b/app/src/main/java/com/assimilate/alltrans/common/PreferenceUtils.java
index 5c6246a..9e1c6e6 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/PreferenceUtils.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/PreferenceUtils.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
diff --git a/app/src/main/java/com/assimilate/alltrans/common/ScopedExecutor.java b/app/src/main/java/com/assimilate/alltrans/common/ScopedExecutor.java
index 6a7793e..b6b305d 100755
--- a/app/src/main/java/com/assimilate/alltrans/common/ScopedExecutor.java
+++ b/app/src/main/java/com/assimilate/alltrans/common/ScopedExecutor.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common;
diff --git a/app/src/main/java/com/assimilate/alltrans/common/Sort.java b/app/src/main/java/com/assimilate/alltrans/common/Sort.java
deleted file mode 100644
index 5fe4e31..0000000
--- a/app/src/main/java/com/assimilate/alltrans/common/Sort.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.assimilate.alltrans.common;
-
-public enum Sort {
- language, languageCode, speechCode;
-}
diff --git a/app/src/main/java/com/assimilate/alltrans/common/TextRecognitionProcessor.kt b/app/src/main/java/com/assimilate/alltrans/common/TextRecognitionProcessor.kt
index 7748dd9..fe9151a 100644
--- a/app/src/main/java/com/assimilate/alltrans/common/TextRecognitionProcessor.kt
+++ b/app/src/main/java/com/assimilate/alltrans/common/TextRecognitionProcessor.kt
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common
diff --git a/app/src/main/java/com/assimilate/alltrans/common/VisionProcessorBase.kt b/app/src/main/java/com/assimilate/alltrans/common/VisionProcessorBase.kt
index f108a09..8d40793 100644
--- a/app/src/main/java/com/assimilate/alltrans/common/VisionProcessorBase.kt
+++ b/app/src/main/java/com/assimilate/alltrans/common/VisionProcessorBase.kt
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.common
diff --git a/app/src/main/java/com/assimilate/alltrans/curview/GraphicOverlay.java b/app/src/main/java/com/assimilate/alltrans/curview/GraphicOverlay.java
index 5dbe45d..2b49a0e 100755
--- a/app/src/main/java/com/assimilate/alltrans/curview/GraphicOverlay.java
+++ b/app/src/main/java/com/assimilate/alltrans/curview/GraphicOverlay.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2020 Google LLC. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.assimilate.alltrans.curview;
diff --git a/app/src/main/java/com/assimilate/alltrans/curview/SusView.kt b/app/src/main/java/com/assimilate/alltrans/curview/SusView.kt
new file mode 100644
index 0000000..10ba01c
--- /dev/null
+++ b/app/src/main/java/com/assimilate/alltrans/curview/SusView.kt
@@ -0,0 +1,26 @@
+package com.assimilate.alltrans.curview
+
+import android.view.View
+import android.view.WindowManager
+
+class SusView : View.OnClickListener {
+
+ private var windowManager: WindowManager? = null
+ private var layoutParams: WindowManager.LayoutParams? = null
+
+ companion object {
+
+ }
+
+
+ override fun onClick(v: View?) {
+ TODO("Not yet implemented")
+ }
+
+
+ private fun initView() {
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateCameraFragment.java b/app/src/main/java/com/assimilate/alltrans/fragments/TranslateCameraFragment.java
deleted file mode 100644
index eea57f2..0000000
--- a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateCameraFragment.java
+++ /dev/null
@@ -1,297 +0,0 @@
-package com.assimilate.alltrans.fragments;
-
-import androidx.fragment.app.Fragment;
-
-public class TranslateCameraFragment extends Fragment {
-
-// private ActivityResultLauncher activityLauncher;
-// private ActivityResultLauncher permissionLauncher;
-//
-// private FragmentTranslateCameraBinding mBinding;
-//
-// private TextToSpeech tts;
-//
-// private boolean translating = false;
-// private boolean adLoading = false; // 广告是否处于加载中
-// private boolean collectCurrent = false;
-// private String sourceText = ""; // 可能会有一种屌毛,翻译完成后,先去输入框删几个字符,然后再去点击收藏按钮。所以每次翻译前备份一下
-//
-// @Override
-// public void onCreate(@Nullable Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-// activityLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() {
-// @Override
-// public void onActivityResult(ActivityResult result) {
-// if (Activity.RESULT_OK == result.getResultCode() && null != result.getData()) {
-// Intent data = result.getData();
-// String recognizedText = data.getStringExtra("recognizedText");
-// if (!TextUtils.isEmpty(recognizedText)) {
-// mBinding.inputText.setText(recognizedText);
-// translate(recognizedText);
-// }
-// }
-// }
-// });
-// permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback() {
-// @Override
-// public void onActivityResult(Boolean result) {
-// if (result.booleanValue()) {
-// launchCameraApi();
-// } else {
-// Widget.makeToast(getActivity(), "permission denied");
-// }
-// }
-// });
-//
-// translating = false;
-// adLoading = false;
-// collectCurrent = false;
-//
-// tts = new TextToSpeech(getActivity(), new TextToSpeech.OnInitListener() {
-// @Override
-// public void onInit(int status) {
-// if (null != tts && TextToSpeech.SUCCESS == status)
-// tts.setLanguage(Locale.getDefault());
-// }
-// });
-// }
-//
-// @Override
-// public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-// mBinding = FragmentTranslateCameraBinding.inflate(getLayoutInflater());
-//
-// // 朗读原文
-// mBinding.speakSource.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 清空翻译输入框与结果文本
-// mBinding.clear.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// mBinding.result.setText("");
-// mBinding.inputText.setText("");
-//
-// reset();
-// }
-// });
-// // 朗读译文
-// mBinding.speakTarget.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 分享译文
-// mBinding.shareTrans.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// if (translating) {
-// Widget.makeToast(getActivity(), "Translating...");
-// return;
-// }
-//
-// final String share = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(share)) {
-// Intent intent = new Intent(Intent.ACTION_SEND);
-// intent.setType("text/plain");
-// intent.putExtra(Intent.EXTRA_TEXT, share);
-// startActivity(Intent.createChooser(intent, "Share " + getString(R.string.app_name)));
-// }
-// }
-// });
-// // 复制到粘贴板
-// mBinding.copyTrans.setOnClickListener(new View.OnClickListener() {
-// private final String tip = "Copied to clipboard!";
-// @Override
-// public void onClick(View v) {
-// final String share = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(share)) {
-// ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
-// ClipData clipData = ClipData.newPlainText("targetValue", share);
-// clipboardManager.setPrimaryClip(clipData);
-// Widget.makeToast(getActivity(), tip);
-// }
-// }
-// });
-// // 收藏按钮:翻译中禁止收藏, 无原文禁止收藏,无译文禁止收藏
-// mBinding.collectTrans.setOnClickListener(new View.OnClickListener() {
-// private DbTranslation dbTranslation;
-//
-// @Override
-// public void onClick(View v) {
-// if (translating) return;
-//
-// final String sourceTxt = sourceText;
-// if (TextUtils.isEmpty(sourceTxt)) return;
-//
-// if (collectCurrent) {
-// collectCurrent = false;
-// getDbTranslation(getActivity()).collectJust(false);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// } else {
-// collectCurrent = true;
-// getDbTranslation(getActivity()).collectJust(true);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collectedtrans);
-// }
-// }
-//
-// private DbTranslation getDbTranslation(Context context) {
-// if (null == dbTranslation) {
-// dbTranslation = new DbTranslation(context);
-// }
-// return dbTranslation;
-// }
-// });
-//
-// mBinding.changeLanguage.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// launchLanguageSet();
-// }
-// });
-//
-// return mBinding.getRoot();
-// }
-//
-// @Override
-// public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-// super.onViewCreated(view, savedInstanceState);
-// }
-//
-// @Override
-// public void onResume() {
-// super.onResume();
-//
-// // 每次回来可能会更新
-// mBinding.languageSource.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.languageTarget.setText(TranslateWordApp.getTargetLanguage());
-// mBinding.sourceLanguage2.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.targetLanguage2.setText(TranslateWordApp.getTargetLanguage());
-//
-// // TODO: 可以判断是否需要再次请求原生广告
-// }
-//
-// @Override
-// public void onStop() {
-// super.onStop();
-//
-// if (null != tts) tts.stop();
-// }
-//
-// @Override
-// public void onDestroy() {
-// super.onDestroy();
-// if (null != tts) tts.shutdown();
-// }
-//
-// public void launchCamera() {
-// if (withCameraPermission()) {
-// launchCameraApi();
-// } else {
-// if (null != permissionLauncher) {
-// permissionLauncher.launch(Manifest.permission.CAMERA);
-// }
-// }
-// }
-//
-// private void launchCameraApi() {
-// if (null != activityLauncher) {
-// activityLauncher.launch(new Intent(getActivity(), TranslateCameraActivity.class));
-// }
-// }
-//
-// private void translate(@NonNull final String text) {
-// // step1. 叫用户检查网络连接
-// if (translating) {
-// // 第一次点击翻译按钮后 可能会延迟响应结果,翻译期间再次点击翻译按钮无效
-// Logger.d("log", "translating(not post data)...");
-// return;
-// }
-// Logger.d("log", "translating...");
-// reset();
-//
-// translating = true;
-// final HashMap param = new HashMap<>();
-// param.put("sourceLanguage", TranslateWordApp.getSourceLanguageCode());
-// param.put("translationLanguage", TranslateWordApp.getTargetLanguageCode());
-// param.put("text", text);
-//
-// sourceText = text;
-// mBinding.result.setText("translating...");
-// Translator translator = new GoogleTranslator();
-// translator.translate(param, new GoogleTranslator.GoogleTranslateCallback() {
-// @Override
-// public void onResponse(String val) {
-// translating = false;
-//
-// if (!TextUtils.isEmpty(val)) {
-// TranslateMainActivity activity = null;
-// if (getActivity() instanceof TranslateMainActivity) {
-// activity = (TranslateMainActivity) getActivity();
-// }
-// if (null != activity) {
-// activity.runOnUiThread(new Runnable() {
-// @Override
-// public void run() {
-// mBinding.result.setText(val);
-// addLog(val);
-// }
-// });
-// }
-// }
-// }
-//
-// private void addLog(String targetTxt) {
-// FragmentActivity activity = getActivity();
-// if (null != activity) {
-// DbTranslation dbTranslation = new DbTranslation(activity);
-// Translations translations = new Translations(TranslateWordApp.getSourceLanguage(), sourceText, TranslateWordApp.getTargetLanguage(), targetTxt);
-// dbTranslation.addTranslation(translations);
-// }
-// }
-// });
-// }
-//
-// private void reset() {
-// // 归位收藏图片
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// // 归位收藏备份文本
-// sourceText = "";
-// // 设置当前未处于收藏状态
-// collectCurrent = false;
-// // 当前不处于翻译状态
-// translating = false;
-// }
-//
-// private boolean withCameraPermission() {
-// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-// FragmentActivity activity = getActivity();
-// if (null == activity) return false;
-// return ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
-// } else {
-// return true;
-// }
-// }
-//
-// private void launchLanguageSet() {
-// Intent intent = new Intent(getActivity(), TranslateChangeLanguageActivity.class);
-// getActivity().startActivity(intent);
-// }
-//
-//
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateTextFragment.java b/app/src/main/java/com/assimilate/alltrans/fragments/TranslateTextFragment.java
deleted file mode 100644
index 029beb1..0000000
--- a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateTextFragment.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package com.assimilate.alltrans.fragments;
-
-import androidx.fragment.app.Fragment;
-
-public class TranslateTextFragment extends Fragment {
-
-// private FragmentTranslateTextBinding mBinding;
-//
-// private TextToSpeech tts;
-//
-// private boolean translating = false;
-// private boolean adLoading = false; // 广告是否处于加载中
-// private boolean collectCurrent = false;
-//
-// private String sourceText = ""; // 可能会有一种屌毛,翻译完成后,先去输入框删几个字符,然后再去点击收藏按钮。所以每次翻译前备份一下
-//
-// @Override
-// public void onCreate(@Nullable Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-//
-// translating = false;
-// adLoading = false;
-// collectCurrent = false;
-//
-// tts = new TextToSpeech(getActivity(), new TextToSpeech.OnInitListener() {
-// @Override
-// public void onInit(int status) {
-// if (null != tts && TextToSpeech.SUCCESS == status)
-// tts.setLanguage(Locale.getDefault());
-// }
-// });
-// }
-//
-// @SuppressLint("ClickableViewAccessibility")
-// @Override
-// public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-// mBinding = FragmentTranslateTextBinding.inflate(getLayoutInflater());
-//
-// // 朗读原文
-// mBinding.speakSource.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 清空翻译输入框与结果文本
-// mBinding.clear.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// mBinding.result.setText("");
-// mBinding.inputText.setText("");
-//
-// reset();
-// }
-// });
-// // 输入enter键后直接翻译 & 关闭软件盘与失去光标闪烁
-// mBinding.inputText.setOnTouchListener((view1, motionEvent) -> {
-// mBinding.inputText.setCursorVisible(true);
-// return false;
-// });
-// mBinding.inputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-// @Override
-// public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
-// if (i == EditorInfo.IME_ACTION_SEARCH) {
-// hiddenSoftKeyboard();
-// final String text = mBinding.inputText.getText().toString();
-// if (!TextUtils.isEmpty(text)) {
-// translate(text);
-// }
-// return true;
-// }
-// return false;
-// }
-//
-// private void hiddenSoftKeyboard() {
-// final FragmentActivity activity = getActivity();
-// final IBinder binder = mBinding.inputText.getWindowToken();
-// if (null != activity && null != binder) {
-// InputMethodManager inputMethodManager =
-// (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
-// boolean hideSoftInputFromWindow =
-// inputMethodManager.hideSoftInputFromWindow(binder, InputMethodManager.HIDE_NOT_ALWAYS);
-// if (hideSoftInputFromWindow) {
-// mBinding.inputText.setCursorVisible(false);
-// }
-// }
-// }
-// });
-//
-// // 朗读译文
-// mBinding.speakTarget.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 分享译文
-// mBinding.shareTrans.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// if (translating) {
-// Widget.makeToast(getActivity(), "Translating...");
-// return;
-// }
-//
-// final String share = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(share)) {
-// Intent intent = new Intent(Intent.ACTION_SEND);
-// intent.setType("text/plain");
-// intent.putExtra(Intent.EXTRA_TEXT, share);
-// startActivity(Intent.createChooser(intent, "Share " + getString(R.string.app_name)));
-// }
-// }
-// });
-// // 复制到粘贴板
-// mBinding.copyTrans.setOnClickListener(new View.OnClickListener() {
-// private final String tip = "Copied to clipboard!";
-// @Override
-// public void onClick(View v) {
-// final String share = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(share)) {
-// ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
-// ClipData clipData = ClipData.newPlainText("targetValue", share);
-// clipboardManager.setPrimaryClip(clipData);
-// Widget.makeToast(getActivity(), tip);
-// }
-// }
-// });
-// // 收藏按钮:翻译中禁止收藏, 无原文禁止收藏,无译文禁止收藏
-// mBinding.collectTrans.setOnClickListener(new View.OnClickListener() {
-// private DbTranslation dbTranslation;
-//
-// @Override
-// public void onClick(View v) {
-// if (translating) return;
-//
-// final String sourceTxt = sourceText;
-// if (TextUtils.isEmpty(sourceTxt)) return;
-//
-// if (collectCurrent) {
-// collectCurrent = false;
-// getDbTranslation(getActivity()).collectJust(false);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// } else {
-// collectCurrent = true;
-// getDbTranslation(getActivity()).collectJust(true);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collectedtrans);
-// }
-// }
-//
-// private DbTranslation getDbTranslation(Context context) {
-// if (null == dbTranslation) {
-// dbTranslation = new DbTranslation(context);
-// }
-// return dbTranslation;
-// }
-// });
-//
-// mBinding.changeLanguage.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// launchLanguageSet();
-// }
-// });
-//
-// return mBinding.getRoot();
-// }
-//
-// @Override
-// public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-// super.onViewCreated(view, savedInstanceState);
-// }
-//
-// @Override
-// public void onResume() {
-// super.onResume();
-//
-// // 每次回来可能会更新
-// mBinding.languageSource.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.languageTarget.setText(TranslateWordApp.getTargetLanguage());
-// mBinding.sourceLanguage2.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.targetLanguage2.setText(TranslateWordApp.getTargetLanguage());
-//
-// // TODO: 可以判断是否需要再次请求原生广告
-// }
-//
-// @Override
-// public void onStop() {
-// super.onStop();
-// if (null != tts) tts.stop();
-// }
-//
-// @Override
-// public void onDestroy() {
-// super.onDestroy();
-// if (null != tts) tts.shutdown();
-// }
-//
-// private void translate(@NonNull final String text) {
-// // step1. 叫用户检查网络连接
-// if (translating) {
-// // 第一次点击翻译按钮后 可能会延迟响应结果,翻译期间再次点击翻译按钮无效
-// Logger.d("log", "translating(not post data)...");
-// return;
-// }
-// Logger.d("log", "translating...");
-// reset();
-//
-// translating = true;
-// final HashMap param = new HashMap<>();
-// param.put("sourceLanguage", TranslateWordApp.getSourceLanguageCode());
-// param.put("translationLanguage", TranslateWordApp.getTargetLanguageCode());
-// param.put("text", text);
-//
-// sourceText = text;
-// mBinding.result.setText("translating...");
-// Translator translator = new GoogleTranslator();
-// translator.translate(param, new GoogleTranslator.GoogleTranslateCallback() {
-// @Override
-// public void onResponse(String val) {
-// translating = false;
-//
-// if (!TextUtils.isEmpty(val)) {
-// TranslateMainActivity activity = null;
-// if (getActivity() instanceof TranslateMainActivity) {
-// activity = (TranslateMainActivity) getActivity();
-// }
-// if (null != activity) {
-// activity.runOnUiThread(new Runnable() {
-// @Override
-// public void run() {
-// mBinding.result.setText(val);
-// addLog(val);
-// }
-// });
-// }
-// }
-// }
-//
-// private void addLog(String targetTxt) {
-// FragmentActivity activity = getActivity();
-// if (null != activity) {
-// DbTranslation dbTranslation = new DbTranslation(activity);
-// Translations translations = new Translations(TranslateWordApp.getSourceLanguage(), sourceText, TranslateWordApp.getTargetLanguage(), targetTxt);
-// dbTranslation.addTranslation(translations);
-// }
-// }
-// });
-// }
-//
-// private void reset() {
-// // 归位收藏图片
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// // 归位收藏备份文本
-// sourceText = "";
-// // 设置当前未处于收藏状态
-// collectCurrent = false;
-// // 当前不处于翻译状态
-// translating = false;
-// }
-//
-// private void launchLanguageSet() {
-// Intent intent = new Intent(getActivity(), TranslateChangeLanguageActivity.class);
-// getActivity().startActivity(intent);
-// }
-//
-//
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateVoiceFragment.java b/app/src/main/java/com/assimilate/alltrans/fragments/TranslateVoiceFragment.java
deleted file mode 100644
index 46f5da9..0000000
--- a/app/src/main/java/com/assimilate/alltrans/fragments/TranslateVoiceFragment.java
+++ /dev/null
@@ -1,285 +0,0 @@
-package com.assimilate.alltrans.fragments;
-
-
-import androidx.fragment.app.Fragment;
-
-// https://play.google.com/store/apps/details?id=com.google.android.tts
-public class TranslateVoiceFragment extends Fragment {
-
-// private FragmentTranslateVoiceBinding mBinding;
-// private ActivityResultLauncher launcher;
-//
-// private TextToSpeech tts;
-//
-// private boolean translating = false;
-// private boolean adLoading = false; // 广告是否处于加载中
-// private boolean collectCurrent = false;
-//
-// private String sourceText = ""; // 可能会有一种屌毛,翻译完成后,先去输入框删几个字符,然后再去点击收藏按钮。所以每次翻译前备份一下
-//
-// @Override
-// public void onCreate(@Nullable Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-//
-// translating = false;
-// adLoading = false;
-// collectCurrent = false;
-//
-// tts = new TextToSpeech(getActivity(), new TextToSpeech.OnInitListener() {
-// @Override
-// public void onInit(int status) {
-// if (null != tts && TextToSpeech.SUCCESS == status)
-// tts.setLanguage(Locale.getDefault());
-// }
-// });
-//
-// launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() {
-// @Override
-// public void onActivityResult(ActivityResult result) {
-// Intent data = result.getData();
-// if (Activity.RESULT_OK == result.getResultCode() && null != data) {
-// String speech = data.getStringArrayListExtra("android.speech.extra.RESULTS").get(0);
-// if (!TextUtils.isEmpty(speech)) {
-// mBinding.inputText.setText(speech);
-// translate(speech);
-// }
-// }
-// }
-// });
-// }
-//
-// @Override
-// public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-// mBinding = FragmentTranslateVoiceBinding.inflate(getLayoutInflater());
-//
-// // 朗读原文
-// mBinding.speakSource.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 清空翻译输入框与结果文本
-// mBinding.clear.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// mBinding.result.setText("");
-// mBinding.inputText.setText("");
-//
-// reset();
-// }
-// });
-// // 说话完成后,自动翻译
-// mBinding.startSpeak.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// Intent speech_intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
-// speech_intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 5000); // 设置5秒的静默时间
-// speech_intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 5000); // 设置5秒的可能完全静默时间
-//
-// speech_intent.putExtra("android.speech.extra.LANGUAGE_MODEL", TranslateWordApp.getSourceLanguage());
-// speech_intent.putExtra("android.speech.extra.LANGUAGE", TranslateWordApp.getSourceLanguageCode());
-// speech_intent.putExtra("android.speech.extra.LANGUAGE_PREFERENCE", TranslateWordApp.getSourceLanguage());
-// try {
-// if (null != launcher) launcher.launch(speech_intent);
-// } catch (ActivityNotFoundException ea) {
-// Widget.makeToast(getActivity(), "Something went wrong.");
-// }
-// }
-// });
-//
-// // 朗读译文
-// mBinding.speakTarget.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// String speech = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(speech)) {
-// if (null != tts
-// && TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())) {
-// tts.speak(speech, 0, null, null);
-// }
-// }
-// }
-// });
-// // 分享译文
-// mBinding.shareTrans.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// if (translating) {
-// Widget.makeToast(getActivity(), "Translating...");
-// return;
-// }
-//
-// final String share = mBinding.result.getText().toString().trim();
-// if (!TextUtils.isEmpty(share)) {
-// Intent intent = new Intent(Intent.ACTION_SEND);
-// intent.setType("text/plain");
-// intent.putExtra(Intent.EXTRA_TEXT, share);
-// startActivity(Intent.createChooser(intent, "Share " + getString(R.string.app_name)));
-// }
-// }
-// });
-// // 复制到粘贴板
-// mBinding.copyTrans.setOnClickListener(new View.OnClickListener() {
-// private final String tip = "Copied to clipboard!";
-// @Override
-// public void onClick(View v) {
-// final String share = mBinding.result.getText().toString().trim();
-// if (!translating && !TextUtils.isEmpty(share)) {
-// ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
-// ClipData clipData = ClipData.newPlainText("targetValue", share);
-// clipboardManager.setPrimaryClip(clipData);
-// Widget.makeToast(getActivity(), tip);
-// }
-// }
-// });
-// // 收藏按钮:翻译中禁止收藏, 无原文禁止收藏,无译文禁止收藏
-// mBinding.collectTrans.setOnClickListener(new View.OnClickListener() {
-// private DbTranslation dbTranslation;
-//
-// @Override
-// public void onClick(View v) {
-// if (translating) return;
-//
-// final String sourceTxt = sourceText;
-// if (TextUtils.isEmpty(sourceTxt)) return;
-//
-// if (collectCurrent) {
-// collectCurrent = false;
-// getDbTranslation(getActivity()).collectJust(false);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// } else {
-// collectCurrent = true;
-// getDbTranslation(getActivity()).collectJust(true);
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collectedtrans);
-// }
-// }
-//
-// private DbTranslation getDbTranslation(Context context) {
-// if (null == dbTranslation) {
-// dbTranslation = new DbTranslation(context);
-// }
-// return dbTranslation;
-// }
-// });
-//
-// mBinding.changeLanguage.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// launchLanguageSet();
-// }
-// });
-//
-// return mBinding.getRoot();
-// }
-//
-// @Override
-// public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-// super.onViewCreated(view, savedInstanceState);
-//
-// }
-//
-// @Override
-// public void onResume() {
-// super.onResume();
-//
-// mBinding.languageSource.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.languageTarget.setText(TranslateWordApp.getTargetLanguage());
-// mBinding.sourceLanguage2.setText(TranslateWordApp.getSourceLanguage());
-// mBinding.targetLanguage2.setText(TranslateWordApp.getTargetLanguage());
-//
-// // TODO: 可以判断是否需要再次请求原生广告
-// }
-//
-// @Override
-// public void onStop() {
-// super.onStop();
-// if (null != tts) tts.stop();
-// }
-//
-// @Override
-// public void onDestroy() {
-// super.onDestroy();
-// if (null != tts) tts.shutdown();
-// if (null != launcher) {
-// launcher.unregister();
-// launcher = null;
-// }
-// }
-//
-// private void translate(@NonNull final String text) {
-// // step1. 叫用户检查网络连接
-// if (translating) {
-// // 第一次点击翻译按钮后 可能会延迟响应结果,翻译期间再次点击翻译按钮无效
-// Logger.d("log", "translating(not post data)...");
-// return;
-// }
-// Logger.d("log", "translating...");
-// reset();
-//
-// translating = true;
-// final HashMap param = new HashMap<>();
-// param.put("sourceLanguage", TranslateWordApp.getSourceLanguageCode());
-// param.put("translationLanguage", TranslateWordApp.getTargetLanguageCode());
-// param.put("text", text);
-//
-// sourceText = text;
-// mBinding.result.setText("translating...");
-// Translator translator = new GoogleTranslator();
-// translator.translate(param, new GoogleTranslator.GoogleTranslateCallback() {
-// @Override
-// public void onResponse(String val) {
-// translating = false;
-//
-// if (!TextUtils.isEmpty(val)) {
-// TranslateMainActivity activity = null;
-// if (getActivity() instanceof TranslateMainActivity) {
-// activity = (TranslateMainActivity) getActivity();
-// }
-// if (null != activity) {
-// activity.runOnUiThread(new Runnable() {
-// @Override
-// public void run() {
-// mBinding.result.setText(val);
-// addLog(val);
-// }
-// });
-// }
-// }
-// }
-//
-// private void addLog(String targetTxt) {
-// FragmentActivity activity = getActivity();
-// if (null != activity) {
-// DbTranslation dbTranslation = new DbTranslation(activity);
-// Translations translations = new Translations(TranslateWordApp.getSourceLanguage(), sourceText, TranslateWordApp.getTargetLanguage(), targetTxt);
-// dbTranslation.addTranslation(translations);
-// }
-// }
-// });
-// }
-//
-// private void reset() {
-// // 归位收藏图片
-// mBinding.collectTrans.setImageResource(R.mipmap.trw_ic_collecttrans);
-// // 归位收藏备份文本
-// sourceText = "";
-// // 设置当前未处于收藏状态
-// collectCurrent = false;
-// // 当前不处于翻译状态
-// translating = false;
-// }
-//
-// private void launchLanguageSet() {
-// Intent intent = new Intent(getActivity(), TranslateChangeLanguageActivity.class);
-// getActivity().startActivity(intent);
-// }
-//
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/mydb/DbTranslation.java b/app/src/main/java/com/assimilate/alltrans/mydb/DbTranslation.java
index a7a20d0..713b6a2 100644
--- a/app/src/main/java/com/assimilate/alltrans/mydb/DbTranslation.java
+++ b/app/src/main/java/com/assimilate/alltrans/mydb/DbTranslation.java
@@ -115,7 +115,6 @@ public class DbTranslation extends SQLiteOpenHelper {
}
/**
- * 是否收藏刚刚那条翻译
* @param collect 收藏|不收藏
*/
public boolean collectJust(boolean collect) {
diff --git a/app/src/main/java/com/assimilate/alltrans/viewui/HistoryActivity.java b/app/src/main/java/com/assimilate/alltrans/viewui/HistoryActivity.java
index 06be3ed..13c3a92 100644
--- a/app/src/main/java/com/assimilate/alltrans/viewui/HistoryActivity.java
+++ b/app/src/main/java/com/assimilate/alltrans/viewui/HistoryActivity.java
@@ -6,6 +6,9 @@ import android.speech.tts.TextToSpeech;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.assimilate.alltrans.R;
@@ -26,7 +29,7 @@ public class HistoryActivity extends AppCompatActivity {
public final static String COMMAND_COLLECTION = "remove-collection";
public final static String COMMAND_HISTORY = "remove-history";
private TextToSpeech tts;
- private ActivityHistoryBinding mBinding;
+ private ActivityHistoryBinding binding;
private HashSet ids; // 通过id 删除数据库文件
private HashSet items; // 通许index 删除界面上面的数据
private boolean operationCollection = false;
@@ -34,18 +37,19 @@ public class HistoryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mBinding = ActivityHistoryBinding.inflate(getLayoutInflater());
- setContentView(mBinding.getRoot());
+ binding = ActivityHistoryBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(26, systemBars.top, 26, systemBars.bottom);
+ return insets;
+ });
ids = new HashSet<>();
items = new HashSet<>();
String extra = getIntent().getStringExtra(COMMAND);
- if (COMMAND_COLLECTION.equals(extra)) {
- operationCollection = true;
- } else {
- operationCollection = false;
- }
+ operationCollection = COMMAND_COLLECTION.equals(extra);
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
@@ -58,16 +62,16 @@ public class HistoryActivity extends AppCompatActivity {
ArrayList translations = new ArrayList<>();
if (operationCollection) {
// 查出收藏的翻译记录
- mBinding.tvFuncTrans.setText("Collect");
- mBinding.ivFuncTrans.setImageResource(R.mipmap.ic_launcher);
+ binding.tvFuncTrans.setText("Collect");
+ binding.ivFuncTrans.setImageResource(R.drawable.ic_add);
ArrayList list = new DbTranslation(this).getTranslations(true);
if (null != list && !list.isEmpty()) {
translations.addAll(list);
}
} else {
// 查出所有的翻译记录
- mBinding.tvFuncTrans.setText("History");
- mBinding.ivFuncTrans.setImageResource(R.mipmap.ic_launcher);
+ binding.tvFuncTrans.setText("History");
+ binding.ivFuncTrans.setImageResource(R.drawable.ic_add);
ArrayList list = new DbTranslation(this).getTranslations(false);
if (null != list && !list.isEmpty()) {
translations.addAll(list);
@@ -104,15 +108,15 @@ public class HistoryActivity extends AppCompatActivity {
private void updateBtn() {
if (ids.isEmpty()) {
- mBinding.remove.setImageResource(R.mipmap.ic_launcher);
+ binding.remove.setVisibility(View.INVISIBLE);
} else {
- mBinding.remove.setImageResource(R.mipmap.ic_launcher);
+ binding.remove.setVisibility(View.VISIBLE);
}
}
});
final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
- mBinding.remove.setOnClickListener(new View.OnClickListener() {
+ binding.remove.setOnClickListener(new View.OnClickListener() {
private DbTranslation dbTranslation;
@Override
@@ -142,7 +146,7 @@ public class HistoryActivity extends AppCompatActivity {
adapter.updateSet(integerArrayList);
items.clear();
}
- mBinding.remove.setImageResource(R.mipmap.ic_launcher);
+ binding.remove.setVisibility(View.VISIBLE);
}
private DbTranslation getDbTranslation(Context context) {
@@ -153,8 +157,8 @@ public class HistoryActivity extends AppCompatActivity {
}
});
- mBinding.histories.setLayoutManager(layoutManager);
- mBinding.histories.setAdapter(adapter);
+ binding.histories.setLayoutManager(layoutManager);
+ binding.histories.setAdapter(adapter);
}
@Override
diff --git a/app/src/main/java/com/assimilate/alltrans/viewui/LanguageChangeActivity.kt b/app/src/main/java/com/assimilate/alltrans/viewui/LanguageChangeActivity.kt
index ad82128..8f77b68 100644
--- a/app/src/main/java/com/assimilate/alltrans/viewui/LanguageChangeActivity.kt
+++ b/app/src/main/java/com/assimilate/alltrans/viewui/LanguageChangeActivity.kt
@@ -1,15 +1,22 @@
package com.assimilate.alltrans.viewui
import android.os.Bundle
+import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.R
+import com.assimilate.alltrans.adapters.LanguageAdapter
+import com.assimilate.alltrans.common.Language
+import com.assimilate.alltrans.common.LanguagesConstants
import com.assimilate.alltrans.databinding.ActivityLanguageChangeBinding
class LanguageChangeActivity : AppCompatActivity() {
private lateinit var binding: ActivityLanguageChangeBinding
+ private var lastTranslateLanguage = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLanguageChangeBinding.inflate(layoutInflater)
@@ -20,5 +27,44 @@ class LanguageChangeActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
+
+ initList()
+ initClick()
+ }
+
+ private fun initClick() {
+ binding.tvChangeSource.setOnClickListener {
+ lastTranslateLanguage = false
+ }
+ binding.tvChangeTarget.setOnClickListener {
+ lastTranslateLanguage = true
+
+ }
+ }
+
+ private fun initList() {
+ val languages: ArrayList = LanguagesConstants.getInstance().getList(
+ this
+ )
+ if (languages.isNotEmpty()) {
+ val adapter =
+ LanguageAdapter(
+ this, languages
+ ) { _, language ->
+
+ Log.d("fsdafsdfd", language.language)
+ if (lastTranslateLanguage) {
+ MyApp.setTargetLanguage(language)
+ onBackPressed()
+ } else {
+ MyApp.setSourceLanguage(language)
+ }
+ binding.tvChangeSource.text = MyApp.getSourceLanguage()
+ binding.tvChangeTarget.text = MyApp.getTargetLanguage()
+ }
+ val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
+ binding.listLanguages.setLayoutManager(layoutManager)
+ binding.listLanguages.setAdapter(adapter)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/viewui/MainActivity.kt b/app/src/main/java/com/assimilate/alltrans/viewui/MainActivity.kt
index 52dfee4..b95fd5d 100644
--- a/app/src/main/java/com/assimilate/alltrans/viewui/MainActivity.kt
+++ b/app/src/main/java/com/assimilate/alltrans/viewui/MainActivity.kt
@@ -1,18 +1,44 @@
package com.assimilate.alltrans.viewui
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.ClipDescription
+import android.content.ClipboardManager
+import android.content.Context
import android.content.Intent
+import android.media.projection.MediaProjectionManager
+import android.os.Build
import android.os.Bundle
+import android.speech.RecognizerIntent
+import android.text.Editable
+import android.text.TextUtils
+import android.text.TextWatcher
+import android.view.View
+import android.widget.EditText
import androidx.activity.enableEdgeToEdge
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import androidx.localbroadcastmanager.content.LocalBroadcastManager
+import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.R
+import com.assimilate.alltrans.allservice.SusService
+import com.assimilate.alltrans.common.Widget
import com.assimilate.alltrans.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
+ private var launcher: ActivityResultLauncher? = null
+
+
private lateinit var binding: ActivityMainBinding
+ private lateinit var lcm: LocalBroadcastManager
+
+ private lateinit var mediaProjectionManager: MediaProjectionManager
+ private val REQUEST_CODE_SCREEN_CAPTURE = 1001
override fun onCreate(savedInstanceState: Bundle?) {
@@ -23,12 +49,84 @@ class MainActivity : AppCompatActivity() {
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
+ v.setPadding(26, systemBars.top + 26, 26, systemBars.bottom)
insets
}
-
+ initSet()
initClick()
+ registerResult()
+
+ }
+
+ private fun registerResult() {
+ launcher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ val data = result.data
+ if (result.resultCode == RESULT_OK && data != null) {
+ val speech =
+ data.getStringArrayListExtra("android.speech.extra.RESULTS")?.get(0)
+ if (!TextUtils.isEmpty(speech)) {
+ binding.etText.setText(speech)
+ }
+ }
+ }
+ }
+
+ private fun startScreenCapture() {
+ val captureIntent = mediaProjectionManager.createScreenCaptureIntent()
+ startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == Activity.RESULT_OK) {
+ startSusService(resultCode, data)
+ }
+ }
+
+ private fun startSusService(resultCode: Int, data: Intent?) {
+ val serviceIntent = Intent(this, SusService::class.java).apply {
+ putExtra("resultCode", resultCode)
+ putExtra("data", data)
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(serviceIntent)
+ } else {
+ startService(serviceIntent)
+ }
+ }
+
+
+ private fun initView() {
+ binding.chSourceLanguage.text = MyApp.getSourceLanguage()
+ binding.chTargetLanguage.text = MyApp.getTargetLanguage()
+ }
+
+ private fun initSet() {
+ lcm = LocalBroadcastManager.getInstance(this)
+
+ // 监听EditText的文本变化
+ binding.etText.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+ }
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+ }
+
+ override fun afterTextChanged(s: Editable?) {
+ // 根据EditText的内容显示或隐藏粘贴按钮
+ if (s.isNullOrEmpty()) {
+ binding.tvMainTrans.visibility = View.GONE
+
+ } else {
+ binding.tvMainTrans.visibility = View.VISIBLE
+ }
+ }
+ })
+
}
@@ -38,20 +136,29 @@ class MainActivity : AppCompatActivity() {
Intent(this, StillImageActivity::class.java)
)
}
+ binding.tvMainVoice.setOnClickListener {
+ voiceToText()
+ toTextTransResult()
+ }
+ binding.tvMainPaste.setOnClickListener {
+ pasteFromClipboard(binding.etText)
+ toTextTransResult()
+
+ }
binding.tvMainTrans.setOnClickListener {
- startActivity(Intent(this, TextResultActivity::class.java))
+ toTextTransResult()
}
binding.ivMainSetting.setOnClickListener {
startActivity(
Intent(this, SettingsActivity::class.java)
)
}
- binding.sourceLanguage2.setOnClickListener {
+ binding.chSourceLanguage.setOnClickListener {
startActivity(
Intent(this, LanguageChangeActivity::class.java)
)
}
- binding.targetLanguage2.setOnClickListener {
+ binding.chTargetLanguage.setOnClickListener {
startActivity(
Intent(this, LanguageChangeActivity::class.java)
)
@@ -67,9 +174,95 @@ class MainActivity : AppCompatActivity() {
)
}
binding.ivQuickStart.setOnClickListener {
- startActivity(
- Intent(this, QuickSetActivity::class.java)
- )
+
+ mediaProjectionManager =
+ getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
+ startScreenCapture()
+
+ val intent = Intent(this, SusService::class.java)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(intent)
+ } else {
+ startService(intent)
+ }
+ }
+
+ }
+
+ private fun toTextTransResult() {
+ if (binding.etText.text.isEmpty()) {
+ return
+ }
+ val intent = Intent(this, TextResultActivity::class.java)
+ // 将字符串数据添加到Intent中
+ intent.putExtra("source_text", binding.etText.text.toString())
+ startActivity(intent)
+ binding.etText.text = null
+ }
+
+ // 语音转文本
+ private fun voiceToText() {
+ val speechIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
+ speechIntent.putExtra(
+ RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
+ 5000
+ ) // 设置5秒的静默时间
+ speechIntent.putExtra(
+ RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
+ 5000
+ ) // 设置5秒的可能完全静默时间
+
+ speechIntent.putExtra(
+ "android.speech.extra.LANGUAGE_MODEL",
+ MyApp.getSourceLanguage()
+ )
+ speechIntent.putExtra(
+ "android.speech.extra.LANGUAGE",
+ MyApp.getSourceLanguageCode()
+ )
+ speechIntent.putExtra(
+ "android.speech.extra.LANGUAGE_PREFERENCE",
+ MyApp.getSourceLanguage()
+ )
+ try {
+ launcher?.launch(speechIntent)
+ } catch (ea: ActivityNotFoundException) {
+ Widget.makeToast(this, "Something went wrong.")
}
}
+
+
+ // 粘贴文本
+ private fun pasteFromClipboard(etText: EditText) {
+ val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ if (clipboard.hasPrimaryClip() && clipboard.primaryClipDescription!!.hasMimeType(
+ ClipDescription.MIMETYPE_TEXT_PLAIN
+ )
+ ) {
+ val item = clipboard.primaryClip!!.getItemAt(0)
+ val text = item.text.toString()
+ if (text.isNotEmpty()) {
+ // 在EditText中显示粘贴的文本
+ etText.setText(text)
+
+ etText.requestFocus() // 获取焦点
+ }
+ }
+ }
+
+
+ override fun onResume() {
+ super.onResume()
+ initView()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (null != launcher) {
+ launcher!!.unregister()
+ launcher = null
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/assimilate/alltrans/viewui/StillImageActivity.kt b/app/src/main/java/com/assimilate/alltrans/viewui/StillImageActivity.kt
index a43927f..834be83 100644
--- a/app/src/main/java/com/assimilate/alltrans/viewui/StillImageActivity.kt
+++ b/app/src/main/java/com/assimilate/alltrans/viewui/StillImageActivity.kt
@@ -1,9 +1,11 @@
package com.assimilate.alltrans.viewui
+import android.Manifest
import android.app.Activity
import android.content.ContentValues
import android.content.Intent
+import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Bitmap
import android.net.Uri
@@ -22,6 +24,8 @@ import android.widget.PopupMenu
import android.widget.Spinner
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
import com.assimilate.alltrans.R
import com.assimilate.alltrans.common.BitmapUtils
import com.assimilate.alltrans.common.TextRecognitionProcessor
@@ -53,9 +57,25 @@ class StillImageActivity : AppCompatActivity() {
private var imageMaxHeight = 0
private var imageProcessor: VisionImageProcessor? = null
+ private val REQUEST_CAMERA_PERMISSION = 100
+
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_still_image)
+
+ // 检查并请求相机权限
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED
+ ) {
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.CAMERA),
+ REQUEST_CAMERA_PERMISSION
+ )
+ }
+
+
findViewById(R.id.select_image_button).setOnClickListener { view: View ->
// Menu for selecting either: a) take new photo b) select from existing
val popup = PopupMenu(this@StillImageActivity, view)
@@ -109,6 +129,32 @@ class StillImageActivity : AppCompatActivity() {
}
}
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
+ REQUEST_CAMERA_PERMISSION -> {
+ if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ // Permission is granted, proceed with camera
+ startCameraIntentForResult()
+ } else {
+ // Permission denied, show a message to the user
+ Toast.makeText(
+ this,
+ "Camera permission is required to use the camera",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ return
+ }
+ }
+ }
+
+
public override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
@@ -200,7 +246,21 @@ class StillImageActivity : AppCompatActivity() {
outState.putString(KEY_SELECTED_SIZE, selectedSize)
}
- private fun startCameraIntentForResult() { // Clean up last time's image
+ private fun startCameraIntentForResult() {
+ // Ensure permission is still granted before starting camera intent
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.CAMERA
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ Toast.makeText(
+ this,
+ "Camera permission is required to use the camera",
+ Toast.LENGTH_SHORT
+ ).show()
+ return
+ }
+
imageUri = null
preview!!.setImageBitmap(null)
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
diff --git a/app/src/main/java/com/assimilate/alltrans/viewui/TextResultActivity.kt b/app/src/main/java/com/assimilate/alltrans/viewui/TextResultActivity.kt
index 732d74a..27a3496 100644
--- a/app/src/main/java/com/assimilate/alltrans/viewui/TextResultActivity.kt
+++ b/app/src/main/java/com/assimilate/alltrans/viewui/TextResultActivity.kt
@@ -1,17 +1,32 @@
package com.assimilate.alltrans.viewui
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.speech.tts.TextToSpeech
+import android.text.TextUtils
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import com.assimilate.alltrans.MyApp
import com.assimilate.alltrans.R
+import com.assimilate.alltrans.common.Logger
+import com.assimilate.alltrans.common.Widget
import com.assimilate.alltrans.databinding.ActivityTextResultBinding
+import com.assimilate.alltrans.http.GoogleTranslator
+import com.assimilate.alltrans.http.Translator
+import com.assimilate.alltrans.mydb.DbTranslation
+import com.assimilate.alltrans.mydb.Translations
+import java.util.Locale
class TextResultActivity : AppCompatActivity() {
private lateinit var binding: ActivityTextResultBinding
+ private lateinit var tts: TextToSpeech
+ private var translating = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -24,14 +39,133 @@ class TextResultActivity : AppCompatActivity() {
insets
}
+ initSet()
initClick()
}
- private fun initClick() {
- binding.ivReToPhoto.setOnClickListener {
- startActivity(
- Intent(this, StillImageActivity::class.java)
+ private fun initSet() {
+ // 获取Intent
+ val intent = intent
+ val receivedString = intent.getStringExtra("source_text")
+ binding.tvTrSource.text = receivedString
+ translate(binding.tvTrSource.text.toString())
+
+
+ tts = TextToSpeech(this) { status ->
+ if (TextToSpeech.SUCCESS == status) tts.setLanguage(
+ Locale.getDefault()
)
}
+
}
+
+ private fun initClick() {
+ binding.ivTrBack.setOnClickListener { onBackPressed() }
+ binding.tvTrNewTrans.setOnClickListener { onBackPressed() }
+ binding.ivReToPhoto.setOnClickListener {
+ startActivity(Intent(this, StillImageActivity::class.java))
+ }
+ binding.ivTrCopy.setOnClickListener { copyToClipboard() }
+ binding.ivSourceClear.setOnClickListener { onBackPressed() }
+ binding.ivSourceTts.setOnClickListener { readText(binding.tvTrSource.text.toString()) }
+ binding.ivTargetTts.setOnClickListener { readText(binding.tvTrTarget.text.toString()) }
+ binding.ivTrTargetShare.setOnClickListener { shareText(binding.tvTrTarget.text.toString()) }
+ binding.ivTrCollect.setOnClickListener { addCollect() }
+
+ }
+
+ private fun translate(text: String) {
+ if (text.isEmpty() || translating) {
+ Logger.d("log", "translating(not post data)...")
+ return
+ }
+
+ translating = true
+ val param = HashMap().apply {
+ put("sourceLanguage", MyApp.getSourceLanguageCode())
+ put("translationLanguage", MyApp.getTargetLanguageCode())
+ put("text", text)
+ }
+
+ binding.tvTrTarget.text = "translating..."
+ val translator: Translator = GoogleTranslator()
+ translator.translate(param,
+ GoogleTranslator.GoogleTranslateCallback { result ->
+ translating = false
+ if (!TextUtils.isEmpty(result)) {
+ runOnUiThread {
+ binding.tvTrTarget.text = result
+ }
+ addHistory(result)
+ }
+ })
+ }
+
+ private fun addHistory(transResult: String) {
+ val dbTranslation = DbTranslation(this)
+ val translations = Translations(
+ MyApp.getSourceLanguage(),
+ binding.tvTrSource.text.toString(),
+ MyApp.getTargetLanguage(),
+ transResult
+
+ )
+ dbTranslation.addTranslation(translations)
+ }
+
+ private fun addCollect() {
+ if (translating) return
+ val dbTranslation = DbTranslation(this)
+ dbTranslation.collectJust(true)
+
+ binding.ivTrCollect.setImageResource(R.drawable.ic_like_yes)
+ }
+
+ private fun shareText(text: String) {
+ val share: String = text.trim()
+ if (!TextUtils.isEmpty(share)) {
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.setType("text/plain")
+ intent.putExtra(Intent.EXTRA_TEXT, share)
+ startActivity(Intent.createChooser(intent, "Share " + getString(R.string.app_name)))
+ }
+ }
+
+ private fun readText(text: String) {
+ val speech: String = text.trim()
+ if (!TextUtils.isEmpty(speech)) {
+ if (TextToSpeech.LANG_NOT_SUPPORTED != tts.isLanguageAvailable(Locale.getDefault())
+ ) {
+ tts.speak(speech, 0, null, null)
+ }
+ }
+
+ }
+
+ // 复制到粘贴板
+ private fun copyToClipboard() {
+ val tip = "Copied to clipboard!"
+ val tipNull = "text is null!"
+ val share = binding.tvTrTarget.text.toString().trim()
+ if (!TextUtils.isEmpty(share)) {
+ val clipboardManager =
+ getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clipData = ClipData.newPlainText("targetValue", share)
+ clipboardManager.setPrimaryClip(clipData)
+ Widget.makeToast(this, tip)
+ } else {
+ Widget.makeToast(this, tipNull)
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ tts.stop()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ tts.shutdown()
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/checkbox_selector.xml b/app/src/main/res/drawable/checkbox_selector.xml
new file mode 100644
index 0000000..92b3afc
--- /dev/null
+++ b/app/src/main/res/drawable/checkbox_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_dashed_line_4b4b4b4.xml b/app/src/main/res/drawable/ic_dashed_line_4b4b4b4.xml
index 8df3e00..535ff70 100644
--- a/app/src/main/res/drawable/ic_dashed_line_4b4b4b4.xml
+++ b/app/src/main/res/drawable/ic_dashed_line_4b4b4b4.xml
@@ -5,7 +5,7 @@
diff --git a/app/src/main/res/drawable/ic_his_choose_def.xml b/app/src/main/res/drawable/ic_his_choose_def.xml
new file mode 100644
index 0000000..69044fd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_his_choose_def.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_his_choose_yes.xml b/app/src/main/res/drawable/ic_his_choose_yes.xml
new file mode 100644
index 0000000..e6c7cfe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_his_choose_yes.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_like_yes.xml b/app/src/main/res/drawable/ic_like_yes.xml
new file mode 100644
index 0000000..c59875f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_like_yes.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_remove.xml b/app/src/main/res/drawable/ic_remove.xml
new file mode 100644
index 0000000..1506f42
--- /dev/null
+++ b/app/src/main/res/drawable/ic_remove.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/main_bg.xml b/app/src/main/res/drawable/main_bg.xml
new file mode 100644
index 0000000..d0ae181
--- /dev/null
+++ b/app/src/main/res/drawable/main_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml
index f8d9080..6f610d8 100644
--- a/app/src/main/res/layout/activity_history.xml
+++ b/app/src/main/res/layout/activity_history.xml
@@ -2,6 +2,7 @@
@@ -46,16 +47,20 @@
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHeight_percent="0.82"
+ app:layout_constraintHeight_percent="0.9"
app:layout_constraintStart_toStartOf="parent" />
-
diff --git a/app/src/main/res/layout/activity_language_change.xml b/app/src/main/res/layout/activity_language_change.xml
index 16fe26d..c0f9663 100644
--- a/app/src/main/res/layout/activity_language_change.xml
+++ b/app/src/main/res/layout/activity_language_change.xml
@@ -5,6 +5,7 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="#FFF9F9F9"
android:paddingTop="16dp"
tools:context=".viewui.LanguageChangeActivity">
@@ -23,7 +24,7 @@
app:layout_constraintTop_toTopOf="parent">
+ android:text="@string/tr_common"
+ android:textColor="@color/bg_ff605c62"
+ android:textSize="12sp"
+ android:textStyle="bold" />
+ android:background="@drawable/button_r10_gray_bg"
+ android:minHeight="210dp" />
+ android:text="@string/tr_other"
+ android:textColor="@color/bg_ff605c62"
+ android:textSize="12sp"
+ android:textStyle="bold" />
+ android:layout_marginTop="16dp"
+ android:background="@drawable/button_r10_gray_bg" />
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index bdd4f09..a3ceb36 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -5,7 +5,7 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/main_bg_fff9f9f9"
+ android:background="@drawable/main_bg"
android:paddingStart="16dp"
android:paddingTop="16dp"
android:paddingEnd="16dp"
@@ -67,7 +67,7 @@
app:layout_constraintTop_toBottomOf="@id/tv_main_title">
@@ -191,6 +193,7 @@
android:paddingBottom="9dp"
android:text="@string/main_try_text"
android:textColor="@color/main_bg_fff9f9f9"
+ android:visibility="gone"
app:drawableEndCompat="@drawable/ic_arrow_try" />
diff --git a/app/src/main/res/layout/activity_text_result.xml b/app/src/main/res/layout/activity_text_result.xml
index 45a03f0..16a6922 100644
--- a/app/src/main/res/layout/activity_text_result.xml
+++ b/app/src/main/res/layout/activity_text_result.xml
@@ -42,6 +42,7 @@
android:orientation="horizontal">
@@ -18,12 +19,15 @@
android:id="@+id/language"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="6dp"
+ android:layout_marginStart="12dp"
android:layout_marginEnd="24dp"
android:ellipsize="end"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
android:singleLine="true"
android:text="@string/app_name"
android:textColor="@color/black"
+ android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/language_flag"
diff --git a/app/src/main/res/layout/layout_item_translation.xml b/app/src/main/res/layout/layout_item_translation.xml
index 6a85c84..09cfe01 100644
--- a/app/src/main/res/layout/layout_item_translation.xml
+++ b/app/src/main/res/layout/layout_item_translation.xml
@@ -18,9 +18,11 @@
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
android:layout_weight="1"
+ android:maxLines="7"
android:gravity="center_vertical"
android:textColor="@color/black"
- android:textSize="18sp" />
+ android:textSize="16sp"
+ android:textStyle="bold" />
+ android:src="@mipmap/ic_launcher"
+ android:visibility="gone" />
+ android:maxLines="7"
+ android:textColor="@color/text_ffa5a5a5"
+ android:textSize="12sp" />
+ android:button="@drawable/checkbox_selector" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_sus_global.xml b/app/src/main/res/layout/layout_sus_global.xml
new file mode 100644
index 0000000..f98032f
--- /dev/null
+++ b/app/src/main/res/layout/layout_sus_global.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/sus_control_view.xml b/app/src/main/res/layout/sus_control_view.xml
index 5ab0ec9..06bbe68 100644
--- a/app/src/main/res/layout/sus_control_view.xml
+++ b/app/src/main/res/layout/sus_control_view.xml
@@ -2,14 +2,14 @@
+ android:textSize="12sp" />
+ android:textSize="12sp" />
#FFF9F9F9
+ #FFE2EFFF
#FF1F1724
#FF0E8CE8
#FFFFFFFF
@@ -15,6 +16,10 @@
#FFF6F6F6
#FF2F2F2F
+
+ #FF605C62
+
+ #FFA5A5A5
\ 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 a188fe1..e407a48 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,7 +10,7 @@
Select image
Settings
- translator
+ translate
Chinese
English
enter text
@@ -42,6 +42,8 @@
Copy Text
Photo Translation
District Translation
+
+ Delete
\ No newline at end of file