Commit 72a39320 authored by bixing's avatar bixing

maser去掉Media app

parent 8bd4abbe
......@@ -12,7 +12,6 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/media_app" />
</set>
</option>
</GradleProjectSettings>
......
/build
\ No newline at end of file
plugins {
id 'com.android.application'
}
android {
namespace 'com.ads.cal.picturetranslate'
compileSdk 34
defaultConfig {
applicationId "com.abc.tt.kk"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
}
buildTypes {
release {
debuggable false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'app-proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
signingConfigs {
toolsTest {
storeFile file("../test.jks")
storePassword '123456'
keyAlias 'key0'
keyPassword '123456'
}
}
flavorDimensions "versionName"
productFlavors {
transalte {
applicationId "com.ads.cal.picturetranslate"
versionName "1.0.0.0"
signingConfig signingConfigs.toolsTest
manifestPlaceholders = [google_ad_app_id: "ca-app-pub-9356757350640102~6934070860"]
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.camera:camera-view:1.2.3'
implementation 'androidx.lifecycle:lifecycle-process:2.6.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation (platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
// To recognize Latin script
implementation 'com.google.mlkit:text-recognition:16.0.0'
// To recognize Chinese script
implementation 'com.google.mlkit:text-recognition-chinese:16.0.0'
// To recognize Devanagari script
implementation 'com.google.mlkit:text-recognition-devanagari:16.0.0'
// To recognize Japanese script
implementation 'com.google.mlkit:text-recognition-japanese:16.0.0'
// To recognize Korean script
implementation 'com.google.mlkit:text-recognition-korean:16.0.0'
implementation "androidx.camera:camera-core:1.3.0-alpha04"
implementation "androidx.camera:camera-camera2:1.3.0-alpha04"
implementation "androidx.camera:camera-lifecycle:1.3.0-alpha04"
//图像裁剪
implementation 'com.edmodo:cropper:1.0.1'
implementation 'com.github.bumptech.glide:glide:4.15.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.27'
implementation("org.greenrobot:eventbus:3.3.1")
// Import the BoM for the Firebase platform
// implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
// Add the dependency for the Analytics library
// When using the BoM, you don't specify versions in Firebase library dependencies
// implementation("com.google.firebase:firebase-analytics")
// implementation 'com.google.android.gms:play-services-ads:22.5.0'
implementation 'com.google.guava:guava:27.0.1-android'
//facebook
implementation 'com.facebook.android:facebook-android-sdk:latest.release'
//Androidx
api "androidx.browser:browser:1.4.0"
api "androidx.recyclerview:recyclerview:1.1.0"
//Anythink
api "com.anythink.sdk:core:6.2.79"
api "com.anythink.sdk:nativead:6.2.79"
api "com.anythink.sdk:banner:6.2.79"
api "com.anythink.sdk:interstitial:6.2.79"
api "com.anythink.sdk:rewardedvideo:6.2.79"
api "com.anythink.sdk:splash:6.2.79"
//Pangle
api "com.anythink.sdk:adapter-pangle-nonchina:6.2.79"
api "com.pangle.global:ads-sdk:5.5.0.4"
api "com.google.android.gms:play-services-ads-identifier:18.0.1"
//AppLovin
api "com.anythink.sdk:adapter-applovin:6.2.79"
api "com.applovin:applovin-sdk:11.11.3"
//Mintegral
api "com.anythink.sdk:adapter-mintegral-nonchina:6.2.79"
api "com.mbridge.msdk.oversea:reward:16.5.21"
api "com.mbridge.msdk.oversea:newinterstitial:16.5.21"
api "com.mbridge.msdk.oversea:mbnative:16.5.21"
api "com.mbridge.msdk.oversea:mbnativeadvanced:16.5.21"
api "com.mbridge.msdk.oversea:mbsplash:16.5.21"
api "com.mbridge.msdk.oversea:mbbanner:16.5.21"
api "com.mbridge.msdk.oversea:mbbid:16.5.21"
//Vungle
api "com.anythink.sdk:adapter-vungle:6.2.79"
api "com.vungle:vungle-ads:7.0.0"
api "com.google.android.gms:play-services-basement:18.1.0"
api "com.google.android.gms:play-services-ads-identifier:18.0.1"
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontpreverify
-flattenpackagehierarchy
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-useuniqueclassmembernames
-ignorewarnings
#基础模板开始
# 保护注解
-keepattributes *Annotation*
-keepattributes *JavascriptInterface*
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
#泛型 内部类 反射
-keepattributes Signature,InnerClasses,EnclosingMethod
#显示代码行数
-keepattributes Exceptions,SourceFile,LineNumberTable
-keep public class *$JavaScriptInterface
-keepattributes *$JavaScriptInterface
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
*;
}
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
#【不进行混淆保持原样】
-keep public class * extends android.view.View
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
#commom
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
-keep public class * extends android.support.**
-keep class com.google.** { *; }
-keep class android.webkit.**{*;}
-keep class org.apache.** { *; }
-keep public class android.** { *; }
-keepclassmembers public class android.** { *; }
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {*;}
-keepclassmembers class * implements android.os.Parcelable {*;}
-keep class * implements java.io.Serializable {*;}
-keepclassmembers class * implements java.io.Serializable {*;}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class **.R$* {
public static <fields>;
}
#基础模板结束
#utilcode
-keep class com.blankj.utilcode.** { *; }
-keepclassmembers class com.blankj.utilcode.** { *; }
-keepclassmembers class * {
@com.blankj.utilcode.util.BusUtils$Bus <methods>;
}
-dontwarn com.blankj.utilcode.**
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
# OkHttp3
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
#okhttp
-dontwarn okhttp3.**
-keep class okhttp3.*{*;}
#okio
-dontwarn okio.**
-keep class okio.*{*;}
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature-keepattributes
# Gson
-keep class com.google.gson.stream.** { *; }
-keepattributes EnclosingMethod
-keep class org.xz_sale.entity.**{*;}
# agentWeb
-keep class com.just.agentweb.** {
*;
}
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
##Glide
-keep class com.bumptech.glide.** {*;}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl { *; }
#alibaba arouter start
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
#alibaba arouter end
#kotlinx start
-keep class kotlinx.** { *; }
-keep class kotlin.** { *; }
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
#kotlinx end
#9.22版本新增加混淆
-keep class android.support.v7.widget.RecyclerView {*;}
-keepnames class android.support.v7.widget.RecyclerView$* {
public <fields>;
public <methods>;
}
#android
-keep class android.** {*;}
-keep class androidx.** {*;}
-keep class android.support.** {*;}
-keep class android.content.** {*;}
-keep class android.app.** {*;}
-keep class android.os.** {*;}
-keep class android.net.** {*;}
-keep class android.provider.** {*;}
#com.github
-keep class com.github.** {*;}
#com.google
-keep class com.google.** {*;}
#org.
-keep class org.**{ *; }
package com.ads.cal.picturetranslate;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.ads.cal.picturetranslate", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.ads.cal.picturetranslate">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application
android:name="com.ads.cal.picturetranslate.PictureApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.PictureTranslate"
tools:targetApi="31">
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="ocr,ocr_chinese,ocr_devanagari,ocr_japanese,ocr_korean" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="${google_ad_app_id}" />
<activity
android:name="com.ads.cal.picturetranslate.activity.PictureTranslateStartActivity"
android:exported="true"
android:theme="@style/Theme.PictureTranslate"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.ads.cal.picturetranslate.activity.AboutActivity"
android:exported="true"
android:screenOrientation="portrait"
/>
<activity
android:name="com.ads.cal.picturetranslate.activity.PictureTranslateListMainActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"/>
<activity
android:name="com.ads.cal.picturetranslate.activity.CameraActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true"
android:hardwareAccelerated="true" />
<activity
android:name="com.ads.cal.picturetranslate.activity.PictureTranslateCutOutPhotoActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true"
android:hardwareAccelerated="true" />
<activity
android:name="com.ads.cal.picturetranslate.activity.PictureTranslateResultActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true" />
<activity
android:name="com.ads.cal.picturetranslate.activity.PictureTranslateShowPhotoActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:exported="true" />
<activity
android:name="com.ads.cal.picturetranslate.activity.PrivacyPolicyActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:exported="true" />
<!-- facebook -->
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_app_token" />
<meta-data
android:name="com.facebook.sdk.AutoLogAppEventsEnabled"
android:value="true" />
<meta-data
android:name="com.facebook.sdk.AutoInitEnabled"
android:value="true" />
<meta-data
android:name="com.facebook.sdk.AdvertiserIDCollectionEnabled"
android:value="true" />
</application>
<!-- To use multiple models: android:value="ocr,ocr_chinese,ocr_devanagari,ocr_japanese,ocr_korean,..." -->
</manifest>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Privacy Policy</title>
</head>
<body>
<h1>Privacy Policy</h1>
<p>Thank you for using our Android Image Text Extraction app. We highly value your privacy, and as such, we have formulated the following privacy policy to help you understand how we collect, use, and protect your personal information. Please read the following carefully.</p>
<h2>Collected Information</h2>
<p>Our app uses the following third-party frameworks and permissions to provide its functionality and may collect the following information:</p>
<h3>1. Glide</h3>
<p>We use Glide to load and display images. Glide may collect information about your device and image loading to enhance performance and user experience.</p>
<h3>2. Android-Gif-Drawable</h3>
<p>Android-Gif-Drawable is used to support the display of GIF images. It may collect information about GIF images for proper decoding and display.</p>
<h3>3. EventBus</h3>
<p>EventBus is used for event handling and communication. It may log information related to event handling but does not directly collect personally identifiable information.</p>
<h3>4. AndroidX.Camera</h3>
<p>We use AndroidX.Camera to access the camera device for image text extraction. The app will require the following permissions:</p>
<ul>
<li><code>android.permission.CAMERA</code></li>
<li><code>android.hardware.camera.any</code></li>
<li><code>android.hardware.camera</code> (optional, if available)</li>
</ul>
<h3>5. Google ML Kit</h3>
<p>We use Google ML Kit for image text extraction. This framework may involve processing of image data but does not store or transmit images or extracted text data.</p>
<h3>6. Other Permissions</h3>
<p>The app may also require the following permissions:</p>
<ul>
<li><code>android.permission.RECORD_AUDIO</code></li>
<li><code>android.permission.WRITE_EXTERNAL_STORAGE</code> (only for Android versions 28 and below)</li>
<li><code>android.permission.READ_MEDIA_IMAGES</code></li>
</ul>
<h2>Use of Information</h2>
<p>The information we collect will be used for the following purposes:</p>
<ul>
<li>Providing the core functionality of the app, such as image text extraction.</li>
<li>Improving app performance and user experience.</li>
<li>Complying with legal regulations and requirements.</li>
</ul>
<h2>Protection of Information</h2>
<p>We have implemented appropriate security measures to protect your personal information from unauthorized access, disclosure, or misuse. We retain your information only for the duration necessary to fulfill the collection purposes.</p>
<h2>Contact Us</h2>
<p>If you have any questions or concerns regarding our privacy policy or data processing, please feel free to contact us through the following means:</p>
<p>Email: quickTextCts@outlook.com</p>
<p>This privacy policy may be updated periodically, and we recommend checking it regularly for the latest information.</p>
<p>Last Updated: September 27, 2023</p>
<hr>
</body>
</html>
\ No newline at end of file
//package com.ads.cal.picturetranslate;
//
//import android.app.Activity;
//
//import androidx.annotation.NonNull;
//
//import com.google.android.gms.ads.AdError;
//import com.google.android.gms.ads.AdRequest;
//import com.google.android.gms.ads.FullScreenContentCallback;
//import com.google.android.gms.ads.LoadAdError;
//import com.google.android.gms.ads.appopen.AppOpenAd;
//
//import java.util.Date;
//
//
//public class AppOpenAdManager {
////
// private static final String LOG_TAG = "AppOpenAdManager";
// private static final String AD_UNIT_ID = "ca-app-pub-9356757350640102/9428372261";
//
// private AppOpenAd appOpenAd = null;
// private boolean isLoadingAd = false;
// private boolean isShowingAd = false;
//
// private OnLoadAdCompleteListener onLoadAdCompleteListener;
// private OnShowAdCompleteListener onShowAdCompleteListener;
//
// public boolean isShowingAd() {
// return isShowingAd;
// }
//
// /**
// * Keep track of the time an app open ad is loaded to ensure you don't show an expired ad.
// */
// private long loadTime = 0;
//
// /**
// * Constructor.
// */
// public AppOpenAdManager() {
// }
//
// private static final class AppOpenAdManagerHolder {
// static final AppOpenAdManager appOpenAdManager = new AppOpenAdManager();
// }
//
// public static AppOpenAdManager getInstance() {
// return AppOpenAdManagerHolder.appOpenAdManager;
// }
//
//
// /**
// * Load an ad.
// *
// */
// public void loadAd() {
// // Do not load ad if there is an unused ad or one is already loading.
// if (isLoadingAd || isAdAvailable()) {
// return;
// }
//
// isLoadingAd = true;
// AdRequest request = new AdRequest.Builder().build();
// AppOpenAd.load(
// PictureApplication.getApplication(),
// AD_UNIT_ID,
// request,
// new AppOpenAd.AppOpenAdLoadCallback() {
// /**
// * Called when an app open ad has loaded.
// *
// * @param ad the loaded app open ad.
// */
// @Override
// public void onAdLoaded(AppOpenAd ad) {
// appOpenAd = ad;
// isLoadingAd = false;
// loadTime = (new Date()).getTime();
// if (null != onLoadAdCompleteListener) {
// onLoadAdCompleteListener.onLoadAdComplete();
// onLoadAdCompleteListener = null;
// }
//
// LogUtils.d(LOG_TAG, "onAdLoaded.");
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_LOAD_SUCCESS);
// }
//
// /**
// * Called when an app open ad has failed to load.
// *
// * @param loadAdError the error.
// */
// @Override
// public void onAdFailedToLoad(LoadAdError loadAdError) {
// isLoadingAd = false;
// if (null != onLoadAdCompleteListener) {
// onLoadAdCompleteListener.onLoadAdFailed(loadAdError.getMessage());
// onLoadAdCompleteListener = null;
// }
// LogUtils.d(LOG_TAG, "onAdFailedToLoad: " + loadAdError.getMessage());
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_LOAD_FAILED);
// }
// });
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_START_LOAD);
// }
//
// /**
// * Check if ad was loaded more than n hours ago.
// */
// private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
// long dateDifference = (new Date()).getTime() - loadTime;
// long numMilliSecondsPerHour = 3600000;
// return (dateDifference < (numMilliSecondsPerHour * numHours));
// }
//
// /**
// * Check if ad exists and can be shown.
// */
// public boolean isAdAvailable() {
// // Ad references in the app open beta will time out after four hours, but this time limit
// // may change in future beta versions. For details, see:
// // https://support.google.com/admob/answer/9341964?hl=en
// return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
// }
//
//
//
// /**
// * Show the ad if one isn't already showing.
// *
// * @param activity the activity that shows the app open ad
// */
// public boolean showAdIfAvailable(
// @NonNull Activity activity) {
// // If the app open ad is already showing, do not show the ad again.
// if (isShowingAd) {
// LogUtils.d(LOG_TAG, "The app open ad is already showing.");
// return false;
// }
//
// // If the app open ad is not available yet, invoke the callback then load the ad.
// if (!isAdAvailable()) {
// LogUtils.d(LOG_TAG, "The app open ad is not ready yet.");
// loadAd();
// return false;
// }
//
// LogUtils.d(LOG_TAG, "Will show ad.");
//
// appOpenAd.setFullScreenContentCallback(
// new FullScreenContentCallback() {
// /** Called when full screen content is dismissed. */
// @Override
// public void onAdDismissedFullScreenContent() {
// // Set the reference to null so isAdAvailable() returns false.
// appOpenAd = null;
// isShowingAd = false;
//
// LogUtils.d(LOG_TAG, "onAdDismissedFullScreenContent.");
// if (null != onShowAdCompleteListener) {
// onShowAdCompleteListener.onShowAdComplete();
// onShowAdCompleteListener = null;
// }
// loadAd();
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_CLOSE);
// }
//
// /** Called when fullscreen content failed to show. */
// @Override
// public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
// appOpenAd = null;
// isShowingAd = false;
//
// LogUtils.d(LOG_TAG, "onAdFailedToShowFullScreenContent: " + adError.getMessage());
// if (null != onShowAdCompleteListener) {
// onShowAdCompleteListener.onShowAdFailed(adError.getMessage());
// onShowAdCompleteListener = null;
// }
// loadAd();
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_SHOW_FAILED);
// }
//
// /** Called when fullscreen content is shown. */
// @Override
// public void onAdShowedFullScreenContent() {
// LogUtils.d(LOG_TAG, "onAdShowedFullScreenContent.");
// }
//
// @Override
// public void onAdImpression() {
// super.onAdImpression();
// LogUtils.d(LOG_TAG, "onAdImpression.");
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_EXP);
// }
//
// @Override
// public void onAdClicked() {
// super.onAdClicked();
//// FireBaseAnalyticsUtils.init().send(AD_OPEN_CLK);
// }
// });
//
// isShowingAd = true;
// appOpenAd.show(activity);
// return true;
// }
//
// public interface OnShowAdCompleteListener {
// void onShowAdComplete();
//
// void onShowAdFailed(String errorMsg);
// }
//
// public interface OnLoadAdCompleteListener {
// void onLoadAdComplete();
//
// void onLoadAdFailed(String errorMsg);
// }
//
// public void setOnLoadAdCompleteListener(OnLoadAdCompleteListener onLoadAdCompleteListener) {
// this.onLoadAdCompleteListener = onLoadAdCompleteListener;
// }
//
// public void setOnShowAdCompleteListener(OnShowAdCompleteListener onShowAdCompleteListener) {
// this.onShowAdCompleteListener = onShowAdCompleteListener;
// }
//}
package com.ads.cal.picturetranslate;
import android.util.Log;
public class LogUtils {
private static final String TAG = "AAAAAAAA"; // 默认的日志标签
private static boolean isEnabled = true; // 是否启用日志输出,可以根据需要在应用中动态控制
// 设置是否启用日志输出
public static void setEnabled(boolean enabled) {
isEnabled = enabled;
}
// 输出普通信息日志
public static void d(String message) {
if (isEnabled) {
Log.d(TAG, message);
}
}
// 输出错误信息日志
public static void e(String message) {
if (isEnabled) {
Log.e(TAG, message);
}
}
// 输出警告信息日志
public static void w(String message) {
if (isEnabled) {
Log.w(TAG, message);
}
}
// 输出信息日志
public static void i(String message) {
if (isEnabled) {
Log.i(TAG, message);
}
}
// 输出调试信息日志
public static void v(String message) {
if (isEnabled) {
Log.v(TAG, message);
}
}
// 输出指定标签的信息日志
public static void d(String tag, String message) {
if (isEnabled) {
Log.d(tag, message);
}
}
// 输出指定标签的错误信息日志
public static void e(String tag, String message) {
if (isEnabled) {
Log.e(tag, message);
}
}
// 输出指定标签的警告信息日志
public static void w(String tag, String message) {
if (isEnabled) {
Log.w(tag, message);
}
}
// 输出指定标签的信息日志
public static void i(String tag, String message) {
if (isEnabled) {
Log.i(tag, message);
}
}
// 输出指定标签的调试信息日志
public static void v(String tag, String message) {
if (isEnabled) {
Log.v(tag, message);
}
}
}
package com.ads.cal.picturetranslate;
public class MessageEvent {
public static final int UPDATE_HOME_DATA = 1;
public static final int FINISH_ACTIVITY = 2;
public MessageEvent(int type, Object o) {
this.type = type;
this.object = o;
}
public Object object;
public int type;
}
package com.ads.cal.picturetranslate;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionUtil {
public static void checkSelfIMAGEPermission(Activity activity, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(activity, android.Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有权限,请求权限
ActivityCompat.requestPermissions(activity,
new String[]{android.Manifest.permission.READ_MEDIA_IMAGES},
requestCode);
} else {
// 已经有权限,可以访问媒体图像文件
toSystemPhoto(activity, requestCode);
}
} else {
// 请求外部存储权限
if (ContextCompat.checkSelfPermission(activity, android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有权限,请求权限
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
requestCode);
} else {
// 已经有权限,可以继续处理逻辑
toSystemPhoto(activity, requestCode);
}
}
}
public static void toSystemPhoto(Activity activity, int requestCode) {
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
activity.startActivityForResult(intent, requestCode);
}
}
package com.ads.cal.picturetranslate;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.ads.cal.picturetranslate.db.DataBaseManager;
//import com.google.android.gms.ads.MobileAds;
//import com.google.android.gms.ads.initialization.InitializationStatus;
//import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
public class PictureApplication extends Application implements Application.ActivityLifecycleCallbacks, LifecycleObserver {
private static DataBaseManager dataBaseManager;
private static Application application;
@Override
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(this);
application = this;
// MobileAds.initialize(this, new OnInitializationCompleteListener() {
// @Override
// public void onInitializationComplete(@NonNull InitializationStatus initializationStatus) {
// LogUtils.d("PictureApplication", "initializationStatus " + initializationStatus.toString());
// }
// });
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
new Thread(() -> {
PictureTranslateUtils.init();
});
initDB();
TopOnManager.get().initSDK(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
protected void onMoveToForeground() {
// Show the ad (if available) when the app moves to foreground.
TopOnAppOpenAdManager.getInstance().showAdIfAvailable(currentActivity);
}
public static Application getApplication() {
return application;
}
private void initDB() {
dataBaseManager = new DataBaseManager(this);
dataBaseManager.open();
}
public static DataBaseManager getDataBaseManager() {
return dataBaseManager;
}
private Activity currentActivity;
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
if (!TopOnAppOpenAdManager.getInstance().isShowingAd()) {
currentActivity = activity;
}
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
}
package com.ads.cal.picturetranslate;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.text.Text;
import com.google.mlkit.vision.text.TextRecognition;
import com.google.mlkit.vision.text.TextRecognizer;
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions;
import com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions;
import com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions;
import com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions;
import com.google.mlkit.vision.text.latin.TextRecognizerOptions;
public class PictureTranslateUtils {
private final TextRecognizer recognizer;
private final TextRecognizer chineseRecognizer;
private final TextRecognizer devanagariRecognizer;
private final TextRecognizer japaneseRecognizer;
private final TextRecognizer koreanRecognizer;
public PictureTranslateUtils() {
recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
chineseRecognizer = TextRecognition.getClient(new ChineseTextRecognizerOptions.Builder().build());
devanagariRecognizer = TextRecognition.getClient(new DevanagariTextRecognizerOptions.Builder().build());
japaneseRecognizer = TextRecognition.getClient(new JapaneseTextRecognizerOptions.Builder().build());
koreanRecognizer = TextRecognition.getClient(new KoreanTextRecognizerOptions.Builder().build());
}
private static final class PictureTranslateUtilsHolder {
static final PictureTranslateUtils pictureTranslateUtils = new PictureTranslateUtils();
}
public static PictureTranslateUtils init() {
return PictureTranslateUtilsHolder.pictureTranslateUtils;
}
public void translateStandard(InputImage image, OnSuccessListener<Text> onSuccessListener, OnFailureListener onFailureListener) {
recognizer.process(image)
.addOnSuccessListener(onSuccessListener)
.addOnFailureListener(onFailureListener);
}
public void translateChinese(InputImage image, OnSuccessListener<Text> onSuccessListener, OnFailureListener onFailureListener) {
chineseRecognizer.process(image)
.addOnSuccessListener(onSuccessListener)
.addOnFailureListener(onFailureListener);
}
public void translateDevanagari(InputImage image, OnSuccessListener<Text> onSuccessListener, OnFailureListener onFailureListener) {
devanagariRecognizer.process(image)
.addOnSuccessListener(onSuccessListener)
.addOnFailureListener(onFailureListener);
}
public void translateJapanese(InputImage image, OnSuccessListener<Text> onSuccessListener, OnFailureListener onFailureListener) {
japaneseRecognizer.process(image)
.addOnSuccessListener(onSuccessListener)
.addOnFailureListener(onFailureListener);
}
public void translateKorean(InputImage image, OnSuccessListener<Text> onSuccessListener, OnFailureListener onFailureListener) {
koreanRecognizer.process(image)
.addOnSuccessListener(onSuccessListener)
.addOnFailureListener(onFailureListener);
}
public void close() {
if (recognizer != null) {
recognizer.close();
}
if (chineseRecognizer != null) {
chineseRecognizer.close();
}
if (devanagariRecognizer != null) {
devanagariRecognizer.close();
}
if (japaneseRecognizer != null) {
japaneseRecognizer.close();
}
if (koreanRecognizer != null) {
koreanRecognizer.close();
}
}
}
package com.ads.cal.picturetranslate;
import android.content.Context;
import android.content.SharedPreferences;
public class SharedPreferencesUtil {
private static final String PREFS_NAME = "MyAppPreferences";
public static final String KEY_FIRST_INSTALL_APP = "key_first_install_app";
public static final String KEY_FIRST_CLK_TAKE_PHOTO = "key_first_clk_take_photo";
// 保存字符串
public static void saveString(Context context, String key, String value) {
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.apply();
}
// 读取字符串
public static String getString(Context context, String key, String defaultValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getString(key, defaultValue);
}
}
package com.ads.cal.picturetranslate;
public class StaticEventId {
public static final String LAUNCH_EXP = "launch_exp";
public static final String HOME_EXP = "home_exp";
public static final String ABOUT_EXP = "about_exp";
public static final String CAMERA_EXP = "camera_exp";
public static final String CUTOUT_EXP = "cutout_exp";
public static final String RESULT_EXP = "result_exp";
public static final String SHOW_EXP = "show_exp";
}
package com.ads.cal.picturetranslate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadUtils {
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void startRunnable(Runnable runnable) {
executorService.submit(runnable);
}
}
package com.ads.cal.picturetranslate;
import android.app.Activity;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.anythink.core.api.ATAdInfo;
import com.anythink.splashad.api.ATSplashAd;
import com.anythink.splashad.api.ATSplashAdExtraInfo;
import com.anythink.splashad.api.ATSplashAdListener;
import java.util.Date;
public class TopOnAppOpenAdManager {
//
private static final String LOG_TAG = "TopOnAppOpenAdManager";
private static final String AD_UNIT_ID = "b1f138leh1o4gp";
private ATSplashAd appOpenAd = null;
private boolean isLoadingAd = false;
private boolean isShowingAd = false;
private OnLoadAdCompleteListener onLoadAdCompleteListener;
private OnShowAdCompleteListener onShowAdCompleteListener;
public boolean isShowingAd() {
return isShowingAd;
}
/**
* Keep track of the time an app open ad is loaded to ensure you don't show an expired ad.
*/
private long loadTime = 0;
/**
* Constructor.
*/
public TopOnAppOpenAdManager() {
}
private static final class AppOpenAdManagerHolder {
static final TopOnAppOpenAdManager appOpenAdManager = new TopOnAppOpenAdManager();
}
public static TopOnAppOpenAdManager getInstance() {
return AppOpenAdManagerHolder.appOpenAdManager;
}
/**
* Load an ad.
*/
public void loadAd() {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return;
}
isLoadingAd = true;
appOpenAd = new ATSplashAd(PictureApplication.getApplication(), AD_UNIT_ID, null);
appOpenAd.setAdListener(new ATSplashAdListener() {
@Override
public void onAdLoaded(boolean b) {
LogUtils.d(LOG_TAG, "onAdLoaded.");
isLoadingAd = false;
loadTime = (new Date()).getTime();
if (null != onLoadAdCompleteListener) {
onLoadAdCompleteListener.onLoadAdComplete();
onLoadAdCompleteListener = null;
}
}
@Override
public void onAdLoadTimeout() {
isLoadingAd = false;
if (null != onLoadAdCompleteListener) {
onLoadAdCompleteListener.onLoadAdFailed("time out");
onLoadAdCompleteListener = null;
}
LogUtils.d(LOG_TAG, "onAdFailedToLoad: time out");
}
@Override
public void onNoAdError(com.anythink.core.api.AdError adError) {
isLoadingAd = false;
if (null != onLoadAdCompleteListener) {
onLoadAdCompleteListener.onLoadAdFailed(adError.getPlatformMSG());
onLoadAdCompleteListener = null;
}
LogUtils.d(LOG_TAG, "onAdFailedToLoad: " + adError.getPlatformMSG());
}
@Override
public void onAdShow(ATAdInfo atAdInfo) {
}
@Override
public void onAdClick(ATAdInfo atAdInfo) {
}
@Override
public void onAdDismiss(ATAdInfo atAdInfo, ATSplashAdExtraInfo atSplashAdExtraInfo) {
appOpenAd = null;
isShowingAd = false;
LogUtils.d(LOG_TAG, "onAdDismissedFullScreenContent.");
if (null != onShowAdCompleteListener) {
onShowAdCompleteListener.onShowAdComplete();
onShowAdCompleteListener = null;
}
loadAd();
}
});
appOpenAd.loadAd();
}
/**
* Check if ad was loaded more than n hours ago.
*/
private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
long dateDifference = (new Date()).getTime() - loadTime;
long numMilliSecondsPerHour = 3600000;
return (dateDifference < (numMilliSecondsPerHour * numHours));
}
/**
* Check if ad exists and can be shown.
*/
public boolean isAdAvailable() {
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
}
/**
* Show the ad if one isn't already showing.
*
* @param activity the activity that shows the app open ad
*/
public boolean showAdIfAvailable(@NonNull Activity activity) {
if (isShowingAd) {
LogUtils.d(LOG_TAG, "The app open ad is already showing.");
return false;
}
if (!isAdAvailable()) {
LogUtils.d(LOG_TAG, "The app open ad is not ready yet.");
loadAd();
return false;
}
LogUtils.d(LOG_TAG, "Will show ad.");
isShowingAd = true;
appOpenAd.show(activity, (ViewGroup) activity.getWindow().getDecorView());
return true;
}
public interface OnShowAdCompleteListener {
void onShowAdComplete();
void onShowAdFailed(String errorMsg);
}
public interface OnLoadAdCompleteListener {
void onLoadAdComplete();
void onLoadAdFailed(String errorMsg);
}
public void setOnLoadAdCompleteListener(OnLoadAdCompleteListener onLoadAdCompleteListener) {
this.onLoadAdCompleteListener = onLoadAdCompleteListener;
}
public void setOnShowAdCompleteListener(OnShowAdCompleteListener onShowAdCompleteListener) {
this.onShowAdCompleteListener = onShowAdCompleteListener;
}
}
package com.ads.cal.picturetranslate;
import android.app.Activity;
import com.anythink.core.api.ATAdInfo;
import com.anythink.core.api.AdError;
import com.anythink.interstitial.api.ATInterstitial;
import com.anythink.interstitial.api.ATInterstitialListener;
public class TopOnItAdManager {
private static final String IT_AD_UNIT_ID = "b6509805ed0208";
private static ATInterstitial itAd = null;
private static OnItAdListener listener = null;
public static void loadItAd() {
if (itAd != null) {
itAd.load();
return;
}
itAd = new ATInterstitial(PictureApplication.getApplication(), IT_AD_UNIT_ID);
itAd.setAdListener(new ATInterstitialListener() {
@Override
public void onInterstitialAdLoaded() {
}
@Override
public void onInterstitialAdLoadFail(AdError adError) {
}
@Override
public void onInterstitialAdClicked(ATAdInfo atAdInfo) {
}
@Override
public void onInterstitialAdShow(ATAdInfo atAdInfo) {
if (listener != null) {
listener.onShow();
}
}
@Override
public void onInterstitialAdClose(ATAdInfo atAdInfo) {
if (listener != null) {
listener.onClose();
}
loadItAd();
}
@Override
public void onInterstitialAdVideoStart(ATAdInfo atAdInfo) {
}
@Override
public void onInterstitialAdVideoEnd(ATAdInfo atAdInfo) {
}
@Override
public void onInterstitialAdVideoError(AdError adError) {
if (listener != null) {
listener.onFail(adError.getPlatformMSG());
}
loadItAd();
}
});
itAd.load();
}
public static void showItAd(Activity activity, OnItAdListener listener) {
LogUtils.d("anythink showItAd");
if (itAd == null) {
loadItAd();
if (listener != null) {
listener.onFail("it ad is null");
}
return;
}
if (!itAd.isAdReady()) {
loadItAd();
if (listener != null) {
listener.onFail("it ad is not ready");
}
return;
}
itAd.show(activity);
}
interface OnItAdListener {
void onShow();
void onClose();
void onFail(String reason);
}
}
package com.ads.cal.picturetranslate;
import static com.anythink.network.pangle.PangleATConst.DEBUGGER_CONFIG.Pangle_NETWORK;
import android.content.Context;
import com.anythink.core.api.ATDebuggerConfig;
import com.anythink.core.api.ATSDK;
public class TopOnManager {
private TopOnManager() {
}
private static class Holder {
private static final TopOnManager INSTANCE = new TopOnManager();
}
public static TopOnManager get() {
return Holder.INSTANCE;
}
public static final String TOPON_APP_ID = "a6501757a165c4";
// Field from default config.
public static final String TOPON_APP_KEY = "a53892abacdd1aebf0ea1d927ab0f0d88";
public void initSDK(Context context) {
//SDK日志功能,集成测试阶段建议开启,上线前必须关闭
// ATSDK.setNetworkLogDebug(true);
//检查广告平台的集成状态,提交审核时需注释此API
//ATSDK.integrationChecking(context);
// ATSDK.setDebuggerConfig(
// context,
// "596795a7-b851-4514-bd7e-8561d641a968",
// new ATDebuggerConfig.Builder(Pangle_NETWORK).build());
ATSDK.init(context, TOPON_APP_ID, TOPON_APP_KEY);
//SDK版本
LogUtils.d("TopOn SDK version: " + ATSDK.getSDKVersionName());
//(v5.7.77新增) 打印当前设备的设备信息(IMEI、OAID、GAID、AndroidID等)
// ATSDK.testModeDeviceInfo(context, new DeviceInfoCallback() {
// @Override
// public void deviceInfo(String deviceInfo) {
// Log.i(TAG, "deviceInfo: " + deviceInfo);
// }
// });
}
}
package com.ads.cal.picturetranslate;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Point;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.view.Display;
import android.view.WindowManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Util {
/**
* 获取真实路径
* <p>
* 支持以下
* <p>
* file://
* content://media/external/file/109009
* FileProvider适配
* content://com.tencent.mobileqq.fileprovider/external_files/storage/emulated/0/Tencent/QQfile_recv/
* content://com.tencent.mm.external.fileprovider/external/tencent/MicroMsg/Download/
* content://com.android.providers.downloads.documents"
* content://com.android.externalstorage.documents
* content://com.android.providers.media.documents
* content://com.google.android.apps.photos.content
*/
public static String getFileFromUri(Context context, Uri uri) {
if (uri == null) {
return null;
}
switch (uri.getScheme()) {
case ContentResolver.SCHEME_CONTENT:
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
} else if (isMediaDocument(uri)) {
// MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getFilePathFromContentUri(context, contentUri, selection, selectionArgs);
} else if (isDownloadsDocument(uri)) {
// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getFilePathFromContentUri(context, contentUri, null, null);
}
return getFilePathFromContentUri(context, uri, null, null);
case ContentResolver.SCHEME_FILE:
default:
//file://
return new File(uri.getPath()).getAbsolutePath();
}
}
/**
* 从uri获取path 或 拷贝
*/
private static String getFilePathFromContentUri(Context context, Uri uri, String selection, String[] selectionArgs) {
if (null == uri) return null;
String data = null;
String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, selection, selectionArgs, null);
if (null != cursor) {
if (cursor.moveToFirst()) {
int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (index > -1) {
data = cursor.getString(index);
if (data == null || !fileIsExists(data)) {
//可能拿不到真实路径 或 文件不存在 走拷贝流程
int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
String fileName = cursor.getString(nameIndex);
data = getPathFromInputStreamUri(context, uri, fileName);
}
} else {
//拷贝一份
int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
String fileName = cursor.getString(nameIndex);
data = getPathFromInputStreamUri(context, uri, fileName);
}
}
cursor.close();
}
return data;
}
/**
* 用流拷贝文件一份到自己APP私有目录下
*
* @param context
* @param uri
* @param fileName
*/
private static String getPathFromInputStreamUri(Context context, Uri uri, String fileName) {
InputStream inputStream = null;
String filePath = null;
if (uri.getAuthority() != null) {
try {
inputStream = context.getContentResolver().openInputStream(uri);
File file = createTemporalFileFrom(context, inputStream, fileName);
filePath = file.getPath();
} catch (Exception e) {
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
}
}
}
return filePath;
}
private static File createTemporalFileFrom(Context context, InputStream inputStream, String fileName)
throws IOException {
File targetFile = null;
if (inputStream != null) {
int read;
byte[] buffer = new byte[8 * 1024];
//自己定义拷贝文件路径
targetFile = new File(context.getExternalCacheDir(), fileName);
if (targetFile.exists()) {
targetFile.delete();
}
OutputStream outputStream = new FileOutputStream(targetFile);
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
outputStream.flush();
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return targetFile;
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
//判断文件是否存在
private static boolean fileIsExists(String filePath) {
try {
File f = new File(filePath);
if (!f.exists()) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
public static String getDataTime(long createTime) {
long timeDifference = System.currentTimeMillis() - createTime;
String timeAgo;
if (timeDifference < 60000) { // 不到1分钟
long time = (timeDifference / 1000);
timeAgo = time <= 0 ? "1second ago" : time + "second ago";
} else if (timeDifference < 3600000) { // 不到1小时
timeAgo = (timeDifference / 60000) + "minute ago";
} else if (timeDifference < 86400000) { // 不到1天
timeAgo = (timeDifference / 3600000) + "hour ago";
} else { // 大于1天
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
timeAgo = sdf.format(new Date());
}
return timeAgo;
}
public static Uri getFirstImageUriFromGallery(Context context) {
// 定义要查询的内容URI
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
// 定义要返回的列,这里我们只需要文件路径
String[] projection = {MediaStore.Images.Media.DATA};
// 查询并排序
Cursor cursor = context.getContentResolver().query(
uri,
projection,
null,
null,
null
);
if (cursor != null && cursor.moveToFirst()) {
// 获取第一张图片的路径
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
String imagePath = cursor.getString(columnIndex);
// 关闭游标
cursor.close();
// 返回第一张图片的URI
return Uri.parse("file://" + imagePath);
}
return null; // 如果没有找到图片,返回null
}
public static int getScreenHeight(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.y;
}
}
package com.ads.cal.picturetranslate.activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.base.BaseActivity;
import java.io.IOException;
import pl.droidsonroids.gif.GifDecoder;
import pl.droidsonroids.gif.GifDrawable;
import pl.droidsonroids.gif.GifImageView;
import pl.droidsonroids.gif.InputSource;
@ExperimentalGetImage
public class AboutActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
initView();
}
private void initView() {
GifImageView imageView = findViewById(R.id.image);
try {
GifDrawable gifFromAssets = new GifDrawable(getAssets(), "app_gif.gif");
gifFromAssets.setLoopCount(1);
imageView.setImageDrawable(gifFromAssets);
} catch (IOException e) {
e.printStackTrace();
}
TextView versionCode = findViewById(R.id.versioncode);
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
versionCode.setText(String.valueOf(packageInfo.versionName));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
findViewById(R.id.title_layout).setOnClickListener(v -> finish());
}
public static void startAboutActivity(Context context) {
Intent intent = new Intent(context, AboutActivity.class);
context.startActivity(intent);
}
}
package com.ads.cal.picturetranslate.activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import com.ads.cal.picturetranslate.LogUtils;
import com.ads.cal.picturetranslate.PermissionUtil;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.SharedPreferencesUtil;
import com.ads.cal.picturetranslate.Util;
import com.ads.cal.picturetranslate.base.BaseActivity;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
@ExperimentalGetImage public class CameraActivity extends BaseActivity implements ImageAnalysis.Analyzer {
private static final int SELECT_TAKE_PHONE = 1;
private ImageCapture imageCapture;
private ImageView imageView, selectPhone;
private PreviewView mPreview;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 隐藏状态栏和虚拟导航栏
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
);
// 隐藏虚拟导航栏
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
initView();
initData();
try {
initCamera();
} catch (Exception e) {
e.printStackTrace();
LogUtils.e("AAAAAAA", e.getMessage());
}
SharedPreferencesUtil.saveString(this, SharedPreferencesUtil.KEY_FIRST_CLK_TAKE_PHOTO, "clk");
}
private void initView() {
ImageView close = findViewById(R.id.close);
close.setOnClickListener(v -> finish());
mPreview = findViewById(R.id.preview);
imageView = findViewById(R.id.take_photo);
imageView.setOnClickListener(v -> startTakePhone());
selectPhone = findViewById(R.id.select_phone);
selectPhone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PermissionUtil.checkSelfIMAGEPermission(CameraActivity.this, SELECT_TAKE_PHONE);
}
});
}
private void initData() {
Uri firstImageUri = Util.getFirstImageUriFromGallery(this);
if (firstImageUri == null) {
return;
}
selectPhone.setImageURI(firstImageUri);
}
private void initCamera() {
// 将Camera的生命周期和Activity绑定在一起(设定生命周期所有者),这样就不用手动控制相机的启动和关闭。
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
ProcessCameraProvider processCameraProvider = null;
try {
processCameraProvider = cameraProviderFuture.get();
} catch (Exception e) {
e.printStackTrace();
}
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(mPreview.getSurfaceProvider());
// 创建拍照所需的实例
imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.setJpegQuality(80).build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build();
// Select back camera as a default
CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
try {
if (null == processCameraProvider) {
return;
}
processCameraProvider.unbindAll();
processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalysis);
} catch (Exception e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
private void startTakePhone() {
ImageCapture imageCapture = this.imageCapture;
if (imageCapture == null) {
return;
}
File photoFile = new File(getCacheDir(), "/" + System.currentTimeMillis() + ".jpeg");
// 创建 output option 对象,用以指定照片的输出方式
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions
.Builder(photoFile)
.build();
imageView.setEnabled(false);
// 执行takePicture(拍照)方法
imageCapture.takePicture(outputFileOptions,
ContextCompat.getMainExecutor(this),
new ImageCapture.OnImageSavedCallback() {// 保存照片时的回调
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
PictureTranslateShowPhotoActivity.startPictureTranslateShowPhotoActivity(CameraActivity.this, Uri.fromFile(photoFile));
imageView.setEnabled(true);
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
LogUtils.e("AAAAAA", exception.getMessage());
imageView.setEnabled(true);
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == SELECT_TAKE_PHONE) {
if (allPermissionsGranted(grantResults)) {
PermissionUtil.toSystemPhoto(this, SELECT_TAKE_PHONE);
} else {
Toast.makeText(this, getString(R.string.app_toast_enable_permissions), Toast.LENGTH_SHORT).show();
}
}
}
private boolean allPermissionsGranted(int[] grantResults) {
return grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
}
/**
* 获取图片回调
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
if (requestCode == SELECT_TAKE_PHONE) {
Uri selectedImageUri = data.getData();
PictureTranslateShowPhotoActivity.startPictureTranslateShowPhotoActivity(CameraActivity.this, selectedImageUri);
} else {
PictureTranslateShowPhotoActivity.startPictureTranslateShowPhotoActivity(CameraActivity.this, data.getData());
LogUtils.e("uri", data.getData().toString());
}
}
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public void analyze(@NonNull ImageProxy image) {
LogUtils.e("AAAAAA", image.toString());
}
public static void startCameraActivity(Context context) {
Intent intent = new Intent(context, CameraActivity.class);
context.startActivity(intent);
}
}
package com.ads.cal.picturetranslate.activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import com.ads.cal.picturetranslate.LogUtils;
import com.ads.cal.picturetranslate.MessageEvent;
import com.ads.cal.picturetranslate.PictureApplication;
import com.ads.cal.picturetranslate.PictureTranslateUtils;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.Util;
import com.ads.cal.picturetranslate.base.BaseActivity;
import com.ads.cal.picturetranslate.bean.PictureTranslateBean;
import com.ads.cal.picturetranslate.fragment.LoadingFragment;
import com.edmodo.cropper.CropImageView;
import com.google.mlkit.vision.common.InputImage;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ExperimentalGetImage
public class PictureTranslateCutOutPhotoActivity extends BaseActivity {
private CropImageView cropImageView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cutoutphoto);
initView();
initData();
}
private void initView() {
cropImageView = findViewById(R.id.crop);
ImageView close = findViewById(R.id.back);
LinearLayout ok = findViewById(R.id.ok_crop);
close.setOnClickListener(v -> {
finish();
});
ok.setOnClickListener(v -> {
showLoadingFragment(new LoadingFragment());
Bitmap cropperBitmap = cropImageView.getCroppedImage();
// 图像名称
String path = getCacheDir().getPath();
String resultPath = saveImage(path, cropperBitmap);
translate(cropperBitmap, resultPath);
});
}
private void translate(Bitmap bitmap, String path) {
if (bitmap == null) {
hideLoadingFragment();
return;
}
PictureTranslateUtils.init().translateChinese(InputImage.fromBitmap(bitmap, 0),
text -> {
hideLoadingFragment();
LogUtils.e("AAAAAA", text.getText());
PictureApplication.getDataBaseManager().insertData(path, text.getText(), System.currentTimeMillis());
PictureTranslateBean bean = new PictureTranslateBean();
bean.setImageUrl(path);
bean.setTitle(text.getText());
bean.setTime(System.currentTimeMillis());
PictureTranslateResultActivity.startPictureTranslateResultActivity(PictureTranslateCutOutPhotoActivity.this, bean);
EventBus.getDefault().post(new MessageEvent(MessageEvent.FINISH_ACTIVITY, null));
finish();
if (bitmap.isRecycled()) {
return;
}
bitmap.recycle();
},
e -> {
hideLoadingFragment();
LogUtils.e("AAAAAA", e.getMessage());
if (bitmap.isRecycled()) {
return;
}
bitmap.recycle();
});
}
private void initData() {
Intent intent = getIntent();
Uri uri = null;
if (intent != null) {
uri = intent.getParcelableExtra("uri");
}
if (uri == null) {
return;
}
String path = Util.getFileFromUri(this, uri);
if (TextUtils.isEmpty(path)) {
Toast.makeText(this, getString(R.string.app_toast_the_file_is_corrupted), Toast.LENGTH_SHORT).show();
} else {
Bitmap bitmap = BitmapFactory.decodeFile(path);
ExifInterface exif = null;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
e.printStackTrace();
}
cropImageView.setImageBitmap(bitmap, exif);
}
}
/**
* 存储图像
*/
private String saveImage(String path, Bitmap source) {
LogUtils.e("AAAAAAAAA", path);
OutputStream outputStream = null;
File file;
try {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
file = new File(path, System.currentTimeMillis() + ".jpeg");
LogUtils.e("AAAAAAAAA", file.getPath());
if (file.createNewFile()) {
outputStream = new FileOutputStream(file);
if (source != null) {
source.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
}
}
} catch (IOException e) {
LogUtils.e("AAAAAAAA", e.getMessage());
return "";
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
}
}
}
return file.getPath();
}
public static void startCutOutPhotoActivity(Context context, Uri uri) {
Intent intent = new Intent(context, PictureTranslateCutOutPhotoActivity.class);
intent.putExtra("uri", uri);
context.startActivity(intent);
}
}
package com.ads.cal.picturetranslate.activity;
import static com.ads.cal.picturetranslate.SharedPreferencesUtil.KEY_FIRST_INSTALL_APP;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.SharedPreferencesUtil;
import com.ads.cal.picturetranslate.TopOnAppOpenAdManager;
import com.ads.cal.picturetranslate.base.BaseActivity;
import java.io.IOException;
import java.lang.ref.WeakReference;
import pl.droidsonroids.gif.GifDrawable;
import pl.droidsonroids.gif.GifImageView;
@ExperimentalGetImage
public class PictureTranslateStartActivity extends BaseActivity {
private MyHandler handler;
private ProgressBar bar;
private ViewPager viewPager;
private final int[] images = {R.mipmap.image1, R.mipmap.image2, R.mipmap.image3}; // 图片资源
private int currentPage = 0;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
initView();
}
private void initView() {
GifImageView imageView = findViewById(R.id.gifimg);
try {
GifDrawable gifFromAssets = new GifDrawable(getAssets(), "app_gif.gif");
gifFromAssets.setLoopCount(1);
imageView.setImageDrawable(gifFromAssets);
} catch (IOException e) {
e.printStackTrace();
}
bar = findViewById(R.id.horizontalProgressBar);
handler = new MyHandler(this);
TextView try_it_now = findViewById(R.id.try_it_now);
String firstInstall = SharedPreferencesUtil.getString(this, KEY_FIRST_INSTALL_APP, "");
if (!TextUtils.isEmpty(firstInstall)) {
try_it_now.setVisibility(View.GONE);
bar.setVisibility(View.VISIBLE);
handler.sendEmptyMessage(1);
} else {
try_it_now.setOnClickListener(v -> {
PictureTranslateListMainActivity.PictureTranslateListMainActivityStart(PictureTranslateStartActivity.this);
SharedPreferencesUtil.saveString(PictureTranslateStartActivity.this, KEY_FIRST_INSTALL_APP, "install");
finish();
});
playBanner();
}
if (TopOnAppOpenAdManager.getInstance().isAdAvailable()) {
showOpenAd();
} else {
loadOpenAd();
}
}
private void showOpenAd() {
handler.removeCallbacksAndMessages(null);
TopOnAppOpenAdManager.getInstance().setOnShowAdCompleteListener(new TopOnAppOpenAdManager.OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
PictureTranslateListMainActivity.PictureTranslateListMainActivityStart(PictureTranslateStartActivity.this);
finish();
}
@Override
public void onShowAdFailed(String errorMsg) {
PictureTranslateListMainActivity.PictureTranslateListMainActivityStart(PictureTranslateStartActivity.this);
finish();
}
});
TopOnAppOpenAdManager.getInstance().showAdIfAvailable(this);
}
private void loadOpenAd() {
TopOnAppOpenAdManager.getInstance().setOnLoadAdCompleteListener(new TopOnAppOpenAdManager.OnLoadAdCompleteListener() {
@Override
public void onLoadAdComplete() {
showOpenAd();
}
@Override
public void onLoadAdFailed(String errorMsg) {
}
});
TopOnAppOpenAdManager.getInstance().loadAd();
}
public void setProgressBarProgress(int i) {
if (i > 100) {
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
PictureTranslateListMainActivity.PictureTranslateListMainActivityStart(this);
finish();
return;
}
bar.setProgress(i);
}
@Override
protected void onDestroy() {
TopOnAppOpenAdManager.getInstance().setOnShowAdCompleteListener(null);
TopOnAppOpenAdManager.getInstance().setOnLoadAdCompleteListener(null);
super.onDestroy();
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
}
private static class MyHandler extends Handler {
private final WeakReference<Activity> weakReference;
private int i = 0;
public MyHandler(Activity activity) {
super();
weakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Activity activity = weakReference.get();
switch (msg.what) {
case 1:
sendEmptyMessageDelayed(1, 50);
if (activity instanceof PictureTranslateStartActivity) {
((PictureTranslateStartActivity) activity).setProgressBarProgress(i++);
}
break;
case 2:
if (activity instanceof PictureTranslateStartActivity) {
((PictureTranslateStartActivity) activity).smoothScroll();
}
sendEmptyMessageDelayed(2, 1500);
break;
}
}
}
public void smoothScroll() {
if (currentPage == images.length) {
currentPage = 0;
}
viewPager.setCurrentItem(currentPage++, currentPage != 0);
}
private ImageView im1, im2, im3;
private void playBanner() {
LinearLayout layout = findViewById(R.id.layout);
im1 = findViewById(R.id.im_1);
im2 = findViewById(R.id.im_2);
im3 = findViewById(R.id.im_3);
layout.setVisibility(View.VISIBLE);
viewPager = findViewById(R.id.viewPager);
ImagePagerAdapter adapter = new ImagePagerAdapter();
viewPager.setAdapter(adapter);
viewPager.setVisibility(View.VISIBLE);
handler.sendEmptyMessageDelayed(2, 1500);
viewPager.setOnTouchListener((v, event) -> {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
handler.removeCallbacksAndMessages(null);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
handler.sendEmptyMessageDelayed(2, 1500);
}
return false;
});
// 手动滑动时停止自动滑动
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentPage = position;
setImBg(currentPage);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void setImBg(int position) {
switch (position) {
case 0:
im1.setBackgroundResource(R.drawable.app_f1a68f);
im2.setBackgroundResource(R.drawable.app_ede0dc);
im3.setBackgroundResource(R.drawable.app_ede0dc);
break;
case 1:
im2.setBackgroundResource(R.drawable.app_f1a68f);
im1.setBackgroundResource(R.drawable.app_ede0dc);
im3.setBackgroundResource(R.drawable.app_ede0dc);
break;
case 2:
im3.setBackgroundResource(R.drawable.app_f1a68f);
im1.setBackgroundResource(R.drawable.app_ede0dc);
im2.setBackgroundResource(R.drawable.app_ede0dc);
break;
}
}
private class ImagePagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return images.length;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull View container, int position) {
ViewPager viewPager = (ViewPager) container;
View imageView = getLayoutInflater().inflate(R.layout.image_item, viewPager, false);
// 设置图片资源
imageView.setBackgroundResource(images[position]);
viewPager.addView(imageView);
return imageView;
}
@Override
public void destroyItem(@NonNull View container, int position, @NonNull Object object) {
ViewPager viewPager = (ViewPager) container;
viewPager.removeView((View) object);
}
}
}
package com.ads.cal.picturetranslate.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.base.BaseActivity;
@ExperimentalGetImage public class PrivacyPolicyActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_privacy_policy);
String html = "<h1>Privacy Policy</h1>\n" +
"\n" +
"<p>Thank you for using our Android Image Text Extraction app. We highly value your privacy, and as such, we have formulated the following privacy policy to help you understand how we collect, use, and protect your personal information. Please read the following carefully.</p>\n" +
"\n" +
"<h2>Collected Information</h2>\n" +
"\n" +
"<p>Our app uses the following third-party frameworks and permissions to provide its functionality and may collect the following information:</p>\n" +
"\n" +
"<h3>1. Glide</h3>\n" +
"<p>We use Glide to load and display images. Glide may collect information about your device and image loading to enhance performance and user experience.</p>\n" +
"\n" +
"<h3>2. Android-Gif-Drawable</h3>\n" +
"<p>Android-Gif-Drawable is used to support the display of GIF images. It may collect information about GIF images for proper decoding and display.</p>\n" +
"\n" +
"<h3>3. EventBus</h3>\n" +
"<p>EventBus is used for event handling and communication. It may log information related to event handling but does not directly collect personally identifiable information.</p>\n" +
"\n" +
"<h3>4. AndroidX.Camera</h3>\n" +
"<p>We use AndroidX.Camera to access the camera device for image text extraction. The app will require the following permissions:</p>\n" +
"<ul>\n" +
" <li><code>android.permission.CAMERA</code></li>\n" +
" <li><code>android.hardware.camera.any</code></li>\n" +
" <li><code>android.hardware.camera</code> (optional, if available)</li>\n" +
"</ul>\n" +
"\n" +
"<h3>5. Google ML Kit</h3>\n" +
"<p>We use Google ML Kit for image text extraction. This framework may involve processing of image data but does not store or transmit images or extracted text data.</p>\n" +
"\n" +
"<h3>6. Other Permissions</h3>\n" +
"<p>The app may also require the following permissions:</p>\n" +
"<ul>\n" +
" <li><code>android.permission.RECORD_AUDIO</code></li>\n" +
" <li><code>android.permission.WRITE_EXTERNAL_STORAGE</code> (only for Android versions 28 and below)</li>\n" +
" <li><code>android.permission.READ_MEDIA_IMAGES</code></li>\n" +
"</ul>\n" +
"\n" +
"<h2>Use of Information</h2>\n" +
"\n" +
"<p>The information we collect will be used for the following purposes:</p>\n" +
"<ul>\n" +
" <li>Providing the core functionality of the app, such as image text extraction.</li>\n" +
" <li>Improving app performance and user experience.</li>\n" +
" <li>Complying with legal regulations and requirements.</li>\n" +
"</ul>\n" +
"\n" +
"<h2>Protection of Information</h2>\n" +
"\n" +
"<p>We have implemented appropriate security measures to protect your personal information from unauthorized access, disclosure, or misuse. We retain your information only for the duration necessary to fulfill the collection purposes.</p>\n" +
"\n" +
"<h2>Contact Us</h2>\n" +
"\n" +
"<p>If you have any questions or concerns regarding our privacy policy or data processing, please feel free to contact us through the following means:</p>\n" +
"<p>Email: quickTextCts@outlook.com</p>\n" +
"\n" +
"<p>This privacy policy may be updated periodically, and we recommend checking it regularly for the latest information.</p>\n" +
"\n" +
"<p>Last Updated: September 27, 2023</p>\n" +
"\n" +
"<hr>";
TextView textView = findViewById(R.id.html);
textView.setText(Html.fromHtml(html));
textView.setMovementMethod(LinkMovementMethod.getInstance());
LinearLayout layout = findViewById(R.id.title_layout);
layout.setOnClickListener(v -> {
finish();
});
}
public static void startPrivacyPolicyActivity(Context context) {
Intent intent = new Intent(context, PrivacyPolicyActivity.class);
context.startActivity(intent);
}
}
package com.ads.cal.picturetranslate.adapter;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.camera.core.ExperimentalGetImage;
import androidx.recyclerview.widget.RecyclerView;
import com.ads.cal.picturetranslate.PictureApplication;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.ThreadUtils;
import com.ads.cal.picturetranslate.Util;
import com.ads.cal.picturetranslate.activity.PictureTranslateResultActivity;
import com.ads.cal.picturetranslate.bean.PictureTranslateBean;
import com.bumptech.glide.Glide;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@ExperimentalGetImage
public class PictureTranslateListAdapter extends RecyclerView.Adapter<PictureTranslateListAdapter.MyViewHolder> {
private WeakReference<Context> weakReference;
private ArrayList<PictureTranslateBean> data;
public PictureTranslateListAdapter(Context context, ArrayList<PictureTranslateBean> data) {
if (weakReference == null) {
weakReference = new WeakReference<>(context);
}
this.data = data;
}
public void updateData(PictureTranslateBean bean) {
if (data == null) {
data = new ArrayList<>();
} else {
for (PictureTranslateBean translateBean : data) {
if (translateBean.getTime() == bean.getTime()) {
data.remove(translateBean);
break;
}
}
bean.setTime(bean.getNewTime());
data.add(0, bean);
}
notifyDataSetChanged();
}
public void updateData(List<PictureTranslateBean> beans) {
if (data == null) {
data = new ArrayList<>();
} else {
data.clear();
data.addAll(beans);
}
notifyDataSetChanged();
}
public boolean isDataEmpty() {
return null == data || data.isEmpty();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(weakReference.get()).inflate(R.layout.picture_translate_list_item, null, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
PictureTranslateBean bean = data.get(position);
holder.itemView.setOnLongClickListener(v -> {
showPopupWindow(v, bean);
return true;
});
holder.itemView.setOnClickListener(v -> PictureTranslateResultActivity.startPictureTranslateResultActivity(weakReference.get(), bean));
if (bean == null) {
return;
}
holder.setImage(weakReference.get(), bean.getImageUrl());
holder.setTitle(bean.getTitle());
holder.setTime(bean.getTime());
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
private void showPopupWindow(View anchorView, PictureTranslateBean bean) {
// 获取 item 在屏幕上的坐标
int[] location = new int[2];
anchorView.getLocationOnScreen(location);
// 设置 PopupWindow 的位置
int xOffset = 0;
int yOffset = 0;
int height = Util.getScreenHeight(weakReference.get());
View contentView = null;
TextView delete = null;
if (location[1] > height / 2) {
contentView = LayoutInflater.from(weakReference.get()).inflate(R.layout.delete_popuwindo_bottom_layout, null, false);
xOffset = anchorView.getWidth() / 2; // X 偏移
yOffset = location[1]; // Y 偏移
delete = contentView.findViewById(R.id.delete);
} else {
contentView = LayoutInflater.from(weakReference.get()).inflate(R.layout.delete_popuwindo_top_layout, null, false);
xOffset = anchorView.getWidth() / 2; // X 偏移
yOffset = location[1] + anchorView.getHeight() / 2; // Y 偏移
delete = contentView.findViewById(R.id.delete);
}
PopupWindow popupWindow = new PopupWindow(weakReference.get());
popupWindow.setContentView(contentView);
// 设置PopupWindow的背景为透明
popupWindow.setBackgroundDrawable(weakReference.get().getResources().getDrawable(android.R.color.transparent));
// 设置PopupWindow可以获取焦点,这样可以响应触摸事件
popupWindow.setFocusable(true);
popupWindow.showAtLocation(anchorView, Gravity.NO_GRAVITY, xOffset, yOffset);
delete.setOnClickListener(v -> {
// 处理删除按钮点击事件,删除对应的 item
deleteItem(bean);
popupWindow.dismiss();
});
}
private void deleteItem(PictureTranslateBean bean) {
int position = data.indexOf(bean);
// 从数据集中移除对应的 item 数据
data.remove(bean);
// 通知 RecyclerView 刷新数据
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount());
ThreadUtils.startRunnable(() -> PictureApplication.getDataBaseManager().deleteData(bean.getTime()));
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private final ImageView imageView;
private final TextView mTitle;
private final TextView time;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.item_img);
mTitle = itemView.findViewById(R.id.item_title);
time = itemView.findViewById(R.id.item_time);
}
public void setImage(Context context, String imageUrl) {
// 使用Glide加载图片
Glide.with(context)
.load(imageUrl)
.into(imageView);
}
public void setTitle(String title) {
mTitle.setText(title);
}
public void setTime(long createTime) {
time.setText(Util.getDataTime(createTime));
}
}
}
package com.ads.cal.picturetranslate.base;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.ads.cal.picturetranslate.LogUtils;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.activity.PictureTranslateStartActivity;
import com.ads.cal.picturetranslate.adapter.PictureTranslateListAdapter;
import com.ads.cal.picturetranslate.bean.PictureTranslateBean;
import com.ads.cal.picturetranslate.fragment.LoadingFragment;
import java.util.Locale;
@ExperimentalGetImage public class BaseActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (this instanceof PictureTranslateStartActivity) {
return;
}
getWindow().setStatusBarColor(getColor(R.color.color_0073FF)); // 设置颜色
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onRestart() {
super.onRestart();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
protected void showLoadingFragment(LoadingFragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
if (!fragment.isAdded()) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(android.R.id.content, fragment);
fragmentTransaction.addToBackStack("loadingFragment");
fragmentTransaction.commit();
}
}
protected void hideLoadingFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
}
}
protected void showFragment(Fragment fragment, int containerViewId) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (!fragment.isAdded()) {
fragmentTransaction.add(containerViewId, fragment);
if (containerViewId == android.R.id.content) {
fragmentTransaction.addToBackStack("fragment");
}
fragmentTransaction.commit();
} else {
fragmentTransaction.show(fragment);
}
}
public void popBackStackFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
}
}
protected void hineFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.hide(fragment);
}
// private void refreshAd() {
// AdLoader.Builder builder = new AdLoader.Builder(this, ADMOB_AD_UNIT_ID);
// // OnLoadedListener implementation.
// builder.forNativeAd(nativeAd -> {
// // If this callback occurs after the activity is destroyed, you must call
// // destroy and return or you may get a memory leak.
// boolean isDestroyed = isDestroyed();
// if (isDestroyed || isFinishing() || isChangingConfigurations()) {
// nativeAd.destroy();
// return;
// }
// // You must call destroy on old ads when you are done with them,
// // otherwise you will have a memory leak.
// if (BaseActivity.this.nativeAd != null) {
// BaseActivity.this.nativeAd.destroy();
// }
// BaseActivity.this.nativeAd = nativeAd;
//// FrameLayout frameLayout = findViewById(R.id.ad_layout);
//// NativeAdView adView = (NativeAdView) getLayoutInflater().inflate(R.layout.ad_unified, frameLayout, false);
//// populateNativeAdView(nativeAd, adView);
//// frameLayout.removeAllViews();
//// frameLayout.addView(adView);
//// NativeTemplateStyle styles = null;
//// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
//// styles = new NativeTemplateStyle.Builder().withMainBackgroundColor(new ColorDrawable(getColor(R.color.white))).build();
//// } else {
//// styles = new NativeTemplateStyle.Builder().withMainBackgroundColor(new ColorDrawable(getResources().getColor(R.color.white))).build();
//// }
//// TemplateView template = findViewById(R.id.ad_layout);
//// template.setStyles(styles);
//// template.setNativeAd(nativeAd);
// });
//
// VideoOptions videoOptions = new VideoOptions.Builder().setStartMuted(false).build();
//
// NativeAdOptions adOptions = new NativeAdOptions.Builder().setVideoOptions(videoOptions).build();
//
// builder.withNativeAdOptions(adOptions);
//
// AdLoader adLoader = builder.withAdListener(new AdListener() {
// @Override
// public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
// String error = String.format(Locale.getDefault(), "domain: %s, code: %d, message: %s", loadAdError.getDomain(), loadAdError.getCode(), loadAdError.getMessage());
// LogUtils.d("home native onAdLoad Failed " + error);
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_LOAD_FAILED);
// }
//
// @Override
// public void onAdLoaded() {
// super.onAdLoaded();
// LogUtils.d("home native onAdLoaded");
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_LOAD_SUCCESS);
// }
//
// @Override
// public void onAdClicked() {
// super.onAdClicked();
// LogUtils.d("home native onAdClicked");
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_CLK);
// }
//
// @Override
// public void onAdClosed() {
// super.onAdClosed();
// LogUtils.d("home native onAdClosed");
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_CLOSE);
// }
//
// @Override
// public void onAdImpression() {
// super.onAdImpression();
// LogUtils.d("home native onAdImpression");
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_EXP);
// }
//
// @Override
// public void onAdOpened() {
// super.onAdOpened();
// }
//
// }).build();
//
// adLoader.loadAd(new AdRequest.Builder().build());
//// FireBaseAnalyticsUtils.init().send(AD_HOME_NATIVE_START_LOAD);
// LogUtils.d("home native onAdLoad start " );
// }
}
package com.ads.cal.picturetranslate.bean;
import java.io.Serializable;
public class PictureTranslateBean implements Serializable {
private String imageUrl;
private String title;
private long time;
private long newTime;
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public void setTitle(String title) {
this.title = title;
}
public void setTime(long time) {
this.time = time;
}
public long getTime() {
return time;
}
public String getImageUrl() {
return imageUrl;
}
public String getTitle() {
return title;
}
public void setNewTime(long newTime) {
this.newTime = newTime;
}
public long getNewTime() {
return newTime;
}
}
package com.ads.cal.picturetranslate.customeview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class CustomProgressBar extends View {
private Paint backgroundPaint; // 进度条背景画笔
private Paint progressBarPaint; // 进度条画笔
private int progress; // 当前进度
private int maxProgress = 100; // 最大进度
private int progressBarHeight = 20; // 进度条高度
public CustomProgressBar(Context context) {
super(context);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
backgroundPaint = new Paint();
backgroundPaint.setColor(0xFFDFEFFF); // 进度条背景颜色
progressBarPaint = new Paint();
progressBarPaint.setColor(0xFF0075FF); // 进度条颜色
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制进度条背景
canvas.drawRect(0, 0, getWidth(), progressBarHeight, backgroundPaint);
// 计算进度条的宽度
int progressBarWidth = (int) ((float) progress / maxProgress * getWidth());
// 绘制进度条
canvas.drawRect(0, 0, progressBarWidth, progressBarHeight, progressBarPaint);
}
// 设置进度
public void setProgress(int progress) {
if (progress >= 0 && progress <= maxProgress) {
this.progress = progress;
invalidate(); // 重新绘制进度条
}
}
}
package com.ads.cal.picturetranslate.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.ads.cal.picturetranslate.LogUtils;
import com.ads.cal.picturetranslate.bean.PictureTranslateBean;
import java.util.ArrayList;
import java.util.List;
public class DataBaseManager {
private final PictureTranslateDataBaseHelper dbHelper;
private SQLiteDatabase database;
public DataBaseManager(Context context) {
dbHelper = new PictureTranslateDataBaseHelper(context);
}
// 打开数据库连接
public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}
// 关闭数据库连接
public void close() {
dbHelper.close();
}
// 插入数据
public long insertData(String imageUrl, String title, long createTime) {
ContentValues values = new ContentValues();
values.put(PictureTranslateDataBaseHelper.COLUMN_IMAGE_URL, imageUrl);
values.put(PictureTranslateDataBaseHelper.COLUMN_TITLE, title);
values.put(PictureTranslateDataBaseHelper.COLUMN_TIME, createTime);
return database.insert(PictureTranslateDataBaseHelper.TABLE_NAME, null, values);
}
// 查询数据
public List<PictureTranslateBean> queryData() {
String[] columns = {PictureTranslateDataBaseHelper.COLUMN_IMAGE_URL, PictureTranslateDataBaseHelper.COLUMN_TITLE, PictureTranslateDataBaseHelper.COLUMN_TIME};
Cursor cursor = database.query(PictureTranslateDataBaseHelper.TABLE_NAME, columns, null, null, null, null, null);
List<PictureTranslateBean> dataList = new ArrayList<>();
if (cursor != null) {
try {
while (cursor.moveToNext()) {
String imageUrl = cursor.getString(cursor.getColumnIndex(PictureTranslateDataBaseHelper.COLUMN_IMAGE_URL));
String title = cursor.getString(cursor.getColumnIndex(PictureTranslateDataBaseHelper.COLUMN_TITLE));
long time = cursor.getLong(cursor.getColumnIndex(PictureTranslateDataBaseHelper.COLUMN_TIME));
// 创建 PictureTranslateData 对象并添加到列表中
PictureTranslateBean data = new PictureTranslateBean();
data.setTime(time);
data.setTitle(title);
data.setImageUrl(imageUrl);
dataList.add(data);
}
} catch (Exception e) {
LogUtils.e(e.getMessage());
} finally {
cursor.close(); // 记得关闭 Cursor
}
}
return dataList;
}
// 更新数据
public int updateData(String imageUrl, String title, long createTime) {
ContentValues values = new ContentValues();
values.put(PictureTranslateDataBaseHelper.COLUMN_IMAGE_URL, imageUrl);
values.put(PictureTranslateDataBaseHelper.COLUMN_TITLE, title);
values.put(PictureTranslateDataBaseHelper.COLUMN_TIME, createTime);
return database.update(PictureTranslateDataBaseHelper.TABLE_NAME, values, "createTime=" + createTime, null);
}
public boolean deleteData(long createTime) {
int rowsAffected = database.delete(
PictureTranslateDataBaseHelper.TABLE_NAME,
PictureTranslateDataBaseHelper.COLUMN_TIME + "=" + createTime,
null);
return rowsAffected > 0;
}
public boolean deleteData() {
int rowsAffected = database.delete(
PictureTranslateDataBaseHelper.TABLE_NAME,
null,
null);
return rowsAffected > 0;
}
}
package com.ads.cal.picturetranslate.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class PictureTranslateDataBaseHelper extends SQLiteOpenHelper {
// 数据库名称和版本
private static final String DATABASE_NAME = "picture_translate_database.db";
private static final int DATABASE_VERSION = 1;
// 表名和列名
public static final String TABLE_NAME = "picture_translate";
public static final String COLUMN_IMAGE_URL = "imageUrl";
public static final String COLUMN_TITLE = "title";
public static final String COLUMN_TIME = "createTime";
public PictureTranslateDataBaseHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
// 创建表的 SQL 语句
private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_IMAGE_URL + " TEXT, " +
COLUMN_TITLE + " TEXT, " +
COLUMN_TIME + " INTEGER);";
}
package com.ads.cal.picturetranslate.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import androidx.fragment.app.Fragment;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.activity.PictureTranslateShowPhotoActivity;
import com.ads.cal.picturetranslate.base.BaseActivity;
@ExperimentalGetImage public class AgainFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return initView(inflater);
}
private View initView(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.fragment_again, null, false);
view.findViewById(R.id.got_it).setOnClickListener(v -> {
Activity activity = getActivity();
if (activity instanceof PictureTranslateShowPhotoActivity) {
((PictureTranslateShowPhotoActivity)activity).extractFunction();
}
backFragment();
});
return view;
}
private void backFragment() {
Activity activity = getActivity();
if (activity instanceof BaseActivity) {
((BaseActivity)activity).popBackStackFragment();
}
}
}
package com.ads.cal.picturetranslate.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import androidx.fragment.app.Fragment;
import com.ads.cal.picturetranslate.PictureApplication;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.ThreadUtils;
import com.ads.cal.picturetranslate.activity.PictureTranslateListMainActivity;
import com.ads.cal.picturetranslate.base.BaseActivity;
@ExperimentalGetImage public class DeleteFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return initView(inflater);
}
private View initView(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.fragment_delete, null, false);
TextView cancel = view.findViewById(R.id.cancel);
TextView clear = view.findViewById(R.id.clear);
cancel.setOnClickListener(v -> backFragment());
clear.setOnClickListener(v -> {
ThreadUtils.startRunnable(() -> {
PictureApplication.getDataBaseManager().deleteData();
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(() -> {
if (activity instanceof PictureTranslateListMainActivity) {
((PictureTranslateListMainActivity)activity).requestData();
}
backFragment();
});
}
});
});
return view;
}
private void backFragment() {
Activity activity = getActivity();
if (activity instanceof BaseActivity) {
((BaseActivity)activity).popBackStackFragment();
}
}
}
package com.ads.cal.picturetranslate.fragment;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.ads.cal.picturetranslate.R;
public class LoadingFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private ObjectAnimator rotationAnimator;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.loading_fragment, null, false);
ImageView loading = view.findViewById(R.id.loading);
rotationAnimator = ObjectAnimator.ofFloat(loading, "rotation", 0f, 360f);
rotationAnimator.setDuration(2000); // 旋转一周的时间(毫秒)
rotationAnimator.setInterpolator(new LinearInterpolator()); // 线性插值器使动画匀速旋转
rotationAnimator.setRepeatCount(ObjectAnimator.INFINITE); // 设置为无限循环
rotationAnimator.start(); // 启动动画
return view;
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (rotationAnimator != null) {
rotationAnimator.cancel();
}
}
}
package com.ads.cal.picturetranslate.fragment;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.camera.core.ExperimentalGetImage;
import androidx.fragment.app.Fragment;
import com.ads.cal.picturetranslate.R;
import com.ads.cal.picturetranslate.activity.AboutActivity;
import com.ads.cal.picturetranslate.activity.PrivacyPolicyActivity;
import java.util.Objects;
@ExperimentalGetImage
public class SettingFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return initView(inflater);
}
private View initView(LayoutInflater inflater) {
View view = inflater.inflate(R.layout.fragment_setting, null, false);
RelativeLayout share_layout = view.findViewById(R.id.share_layout);
RelativeLayout email_layout = view.findViewById(R.id.email_layout);
RelativeLayout policy_layout = view.findViewById(R.id.policy_layout);
RelativeLayout about_layout = view.findViewById(R.id.about_layout);
share_layout.setOnClickListener(v -> {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
Activity activity = getActivity();
if (activity != null) {
String packageName = activity.getPackageName();
shareIntent.putExtra(Intent.EXTRA_TEXT, "The best Text Extraction app ! \n https://play.google.com/store/apps/details?id=" + packageName); // 设置要分享的内容
}
startActivity(Intent.createChooser(shareIntent, getString(R.string.app_share_to)));
});
email_layout.setOnClickListener(v -> {
try {
// 创建一个Intent,指定Action为发送邮件
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// 设置邮件的类型为“text/plain”
emailIntent.setType("text/plain");
// 添加收件人(可选)
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"zl@gmail.com"});
// 设置要使用的Gmail应用程序包名
emailIntent.setPackage("com.google.android.gm");
startActivity(emailIntent);
} catch (Exception e) {
e.printStackTrace();
}
});
policy_layout.setOnClickListener(v -> PrivacyPolicyActivity.startPrivacyPolicyActivity(getContext()));
about_layout.setOnClickListener(v -> AboutActivity.startAboutActivity(getContext()));
return view;
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<solid android:color="#3B3F43"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/color_e9eaef" android:state_focused="true"/>
<item android:drawable="@color/color_e9eaef" android:state_checked="true"/>
<item android:drawable="@color/white"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="#DFEFEE" /> <!-- 背景颜色 -->
<corners android:radius="10dp" /> <!-- 圆角 -->
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape android:shape="rectangle">
<solid android:color="#5A75FF" /> <!-- 进度条颜色 -->
<corners android:radius="10dp" /> <!-- 圆角 -->
</shape>
</clip>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<solid android:color="#DFEFFF"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<solid android:color="#e9eaef"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<solid android:color="#EDE0DC"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<gradient android:startColor="#00A3FF" android:endColor="#0075FF"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="180dp"/>
<solid android:color="#F1A68F"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@mipmap/app_icon_recent_press"/>
<item android:state_selected="true" android:drawable="@mipmap/app_icon_recent_press"/>
<item android:drawable="@mipmap/app_icon_recent_default"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@mipmap/app_icon_setting_press"/>
<item android:state_selected="true" android:drawable="@mipmap/app_icon_setting_press"/>
<item android:drawable="@mipmap/app_icon_setting"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:color="#EFF4F9" android:width="1dp"/>
<corners android:radius="5dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:width="2dp" android:color="@color/white"/>
<corners android:radius="4dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/color_e9eaef" android:state_pressed="true"/>
<item android:drawable="@color/white"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listData"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_nav"
android:layout_below="@+id/title" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:background="@color/white"
android:src="@mipmap/app_status_bar_bg" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="53dp"
android:layout_marginTop="19dp"
android:gravity="center_vertical"
android:paddingStart="14dp"
android:paddingEnd="14dp"
android:text="@string/app_recent"
android:textColor="#1C1C1C"
android:textSize="20sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="53dp"
android:layout_marginTop="19dp"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/app_icon_delete"
android:layout_marginEnd="30dp" />
<ImageView
android:id="@+id/select_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="30dp"
android:src="@mipmap/app_icon_photo" />
</LinearLayout>
<LinearLayout
android:id="@+id/not_data_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:clipChildren="false"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/app_icon_empty" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/app_not_data" />
</LinearLayout>
<FrameLayout
android:id="@+id/setting_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/title"
android:clickable="true"
android:focusable="true"
android:background="@color/white"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_alignParentBottom="true"
android:background="@mipmap/app_nav_bg">
<ImageView
android:id="@+id/home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="70dp"
android:src="@drawable/app_home_icon_select" />
<ImageView
android:id="@+id/setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="70dp"
android:src="@drawable/app_setting_icon_select" />
</RelativeLayout>
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/take_photo"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:background="@mipmap/app_takephoto_hint"
android:gravity="center"
android:paddingBottom="15dp"
android:textColor="@color/white"
android:textSize="14sp" />
<ImageView
android:id="@+id/take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="17dp"
android:src="@mipmap/app_icon_play" />
</RelativeLayout>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="20dp"
android:src="@mipmap/app_icon_close"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/select_phone"
android:layout_width="34dp"
android:layout_height="34dp"
android:layout_marginEnd="51dp"
android:background="@drawable/app_white_corner_4"
android:padding="2dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="@+id/take_photo"
app:layout_constraintEnd_toStartOf="@+id/take_photo"
app:layout_constraintTop_toTopOf="@+id/take_photo" />
<ImageView
android:id="@+id/take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:src="@mipmap/app_icon_take_photo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop" />
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment