diff --git a/ApkEditorTranslate.iml b/ApkEditorTranslate.iml new file mode 100644 index 0000000..4f92904 --- /dev/null +++ b/ApkEditorTranslate.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/apkEditorTranslate.iml b/apkEditorTranslate/apkEditorTranslate.iml new file mode 100644 index 0000000..55892c4 --- /dev/null +++ b/apkEditorTranslate/apkEditorTranslate.iml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/build.gradle b/apkEditorTranslate/build.gradle new file mode 100644 index 0000000..21c47f1 --- /dev/null +++ b/apkEditorTranslate/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "25.0.2" + useLibrary 'org.apache.http.legacy' + + defaultConfig { + applicationId "apkeditor.translate" + minSdkVersion 12 + targetSdkVersion 13 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile files('libs/rhino-1.7.7.jar') +} diff --git a/apkEditorTranslate/libs/rhino-1.7.7.jar b/apkEditorTranslate/libs/rhino-1.7.7.jar new file mode 100644 index 0000000..422b5f2 Binary files /dev/null and b/apkEditorTranslate/libs/rhino-1.7.7.jar differ diff --git a/apkEditorTranslate/lint.xml b/apkEditorTranslate/lint.xml new file mode 100644 index 0000000..8423c0e --- /dev/null +++ b/apkEditorTranslate/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/AndroidManifest.xml b/apkEditorTranslate/src/main/AndroidManifest.xml new file mode 100644 index 0000000..422d68c --- /dev/null +++ b/apkEditorTranslate/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/CookieInfo.java b/apkEditorTranslate/src/main/java/apkeditor/translate/CookieInfo.java new file mode 100644 index 0000000..ee22425 --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/CookieInfo.java @@ -0,0 +1,44 @@ +package apkeditor.translate; + +import java.io.Serializable; +import java.util.Date; + +public class CookieInfo implements Serializable { + private static final long serialVersionUID = -1906450774713846916L; + private String domain; + private Date expiryDate; + private String name; + private String value; + + public Date getCookieDate() { + return this.expiryDate; + } + + public String getCookieDomain() { + return this.domain; + } + + public String getCookieName() { + return this.name; + } + + public String getCookieValue() { + return this.value; + } + + public void setCookieDate(Date paramDate) { + this.expiryDate = paramDate; + } + + public void setCookieDomain(String paramString) { + this.domain = paramString; + } + + public void setCookieName(String paramString) { + this.name = paramString; + } + + public void setCookieValue(String paramString) { + this.value = paramString; + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/Debug.java b/apkEditorTranslate/src/main/java/apkeditor/translate/Debug.java new file mode 100644 index 0000000..c6bb158 --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/Debug.java @@ -0,0 +1,19 @@ +package apkeditor.translate; + +import android.util.Log; + +public class Debug { + public static void dumpClassName(Object paramObject) { + Object[] arrayOfObject = new Object[1]; + arrayOfObject[0] = paramObject.getClass().getName(); + log("** Class Name: %", arrayOfObject); + } + + public static void log(String paramString, Object... args) { + //Log.d("DEBUG", String.format(paramString, args) + "\n"); + } + + public static void dump(String name, String content) { + //Log.d("DEBUG", name + ": ****\n" + content); + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/MainActivity.java b/apkEditorTranslate/src/main/java/apkeditor/translate/MainActivity.java new file mode 100644 index 0000000..32e1f9c --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/MainActivity.java @@ -0,0 +1,52 @@ +package apkeditor.translate; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.view.Window; + +public class MainActivity extends Activity implements View.OnClickListener { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + + setContentView(R.layout.activity_main); + + initView(); + } + + private void initView() { + findViewById(R.id.btn_view_free).setOnClickListener(this); + findViewById(R.id.btn_view_pro).setOnClickListener(this); + } + + private void viewInMarket(String pkgName) { + Uri uri = Uri.parse("market://details?id=" + pkgName); + Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri); + try { + startActivity(goToMarket); + } catch (ActivityNotFoundException e) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri + .parse("http://play.google.com/store/apps/details?id=" + pkgName))); + } + } + + @Override + public void onClick(View view) { + int id = view.getId(); + switch (id) { + case R.id.btn_view_free: + viewInMarket("com.gmail.heagoo.apkeditor"); + break; + case R.id.btn_view_pro: + viewInMarket("com.gmail.heagoo.apkeditor.pro"); + break; + } + } +} diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/MyCookieStore.java b/apkEditorTranslate/src/main/java/apkeditor/translate/MyCookieStore.java new file mode 100644 index 0000000..932d50d --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/MyCookieStore.java @@ -0,0 +1,129 @@ +package apkeditor.translate; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.apache.http.client.CookieStore; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.cookie.BasicClientCookie; + +public class MyCookieStore implements CookieStore { + + private List cookieList = (List) getCookieFile("CookieFile"); + File file = null; + + public MyCookieStore() { + if (this.cookieList == null) + this.cookieList = new ArrayList(); + } + + private List getCookieFile(String filename) { + return new ArrayList(); + } + + @SuppressWarnings("unused") + private void dumpCookieList() { + Iterator localIterator = this.cookieList.iterator(); + while (true) { + if (!localIterator.hasNext()) + return; + CookieInfo localCookieInfo = (CookieInfo) localIterator.next(); + Debug.log("\tName: " + localCookieInfo.getCookieName(), + new Object[0]); + Debug.log("\tValue: " + localCookieInfo.getCookieValue(), + new Object[0]); + Debug.log("\tDomain: " + localCookieInfo.getCookieDomain(), + new Object[0]); + Debug.log("\tDate: " + localCookieInfo.getCookieDate(), + new Object[0]); + } + } + + // Update the cookie + private void updateCookieList(CookieInfo cookieInfo) { + + String name = cookieInfo.getCookieName(); + + for (CookieInfo ci : this.cookieList) { + // The same name already exists + if (ci.getCookieName().equals(name)) { + ci.setCookieDate(cookieInfo.getCookieDate()); + ci.setCookieDomain(cookieInfo.getCookieDomain()); + ci.setCookieName(cookieInfo.getCookieName()); + ci.setCookieValue(cookieInfo.getCookieValue()); + return; + } + } + + this.cookieList.add(cookieInfo); + } + + // Add one cookie to the store + public void addCookie(Cookie cookie) { + if (cookie == null) + return; + + if (this.cookieList == null) { + this.cookieList = new ArrayList(); + } + + CookieInfo cookieInfo = new CookieInfo(); + if (cookie.getExpiryDate() != null) + cookieInfo.setCookieDate(cookie.getExpiryDate()); + cookieInfo.setCookieName(cookie.getName()); + cookieInfo.setCookieValue(cookie.getValue()); + cookieInfo.setCookieDomain(cookie.getDomain()); + + updateCookieList(cookieInfo); + } + + public void addCookies(List cookies) { + Iterator it = cookies.iterator(); + while (it.hasNext()) { + addCookie((Cookie) it.next()); + } + } + + public void clear() { + } + + public boolean clearExpired(Date paramDate) { + return false; + } + + public Cookie convertCookie(CookieInfo paramCookieInfo) { + BasicClientCookie localBasicClientCookie = new BasicClientCookie( + paramCookieInfo.getCookieName(), + paramCookieInfo.getCookieValue()); + localBasicClientCookie.setDomain(paramCookieInfo.getCookieDomain()); + localBasicClientCookie.setExpiryDate(paramCookieInfo.getCookieDate()); + return localBasicClientCookie; + } + + public List getCookies() { + ArrayList ret = new ArrayList(); + + if (this.cookieList != null) { + for (int i = 0; i < this.cookieList.size(); i++) { + CookieInfo cookie = (CookieInfo) cookieList.get(i); + if (cookie != null) { + ret.add(convertCookie(cookie)); + } + } + } + + return ret; + } + + public void saveCookies() { + if (this.cookieList != null) + putCookie("CookieFile", this.cookieList); + } + + private void putCookie(String string, List cookieList2) { + // TODO Auto-generated method stub + } +} diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/Pair.java b/apkEditorTranslate/src/main/java/apkeditor/translate/Pair.java new file mode 100644 index 0000000..f9173bd --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/Pair.java @@ -0,0 +1,13 @@ +package apkeditor.translate; + + +public class Pair { + + public final T1 m1; + public T2 m2; + + public Pair(T1 t1, T2 t2) { + this.m1 = t1; + this.m2 = t2; + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/SSLSocketFactoryEx.java b/apkEditorTranslate/src/main/java/apkeditor/translate/SSLSocketFactoryEx.java new file mode 100644 index 0000000..f1cd247 --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/SSLSocketFactoryEx.java @@ -0,0 +1,87 @@ +package apkeditor.translate; + +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import org.apache.http.HttpVersion; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpProtocolParams; + +public class SSLSocketFactoryEx extends org.apache.http.conn.ssl.SSLSocketFactory { + SSLContext sslContext = SSLContext.getInstance("TLS"); + + public SSLSocketFactoryEx(KeyStore paramKeyStore) + throws NoSuchAlgorithmException, KeyManagementException, + KeyStoreException, UnrecoverableKeyException { + super(paramKeyStore); + TrustManager local1 = new X509TrustManager() { + public void checkClientTrusted( + X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + public void checkServerTrusted( + X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + this.sslContext.init(null, new TrustManager[] { local1 }, null); + } + + public static DefaultHttpClient getNewHttpClient() { + try { + KeyStore localKeyStore = KeyStore.getInstance(KeyStore + .getDefaultType()); + localKeyStore.load(null, null); + SSLSocketFactoryEx localSSLSocketFactoryEx = new SSLSocketFactoryEx( + localKeyStore); + localSSLSocketFactoryEx + .setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + BasicHttpParams localBasicHttpParams = new BasicHttpParams(); + HttpProtocolParams.setVersion(localBasicHttpParams, + HttpVersion.HTTP_1_1); + HttpProtocolParams.setContentCharset(localBasicHttpParams, "UTF-8"); + SchemeRegistry localSchemeRegistry = new SchemeRegistry(); + localSchemeRegistry.register(new Scheme("http", PlainSocketFactory + .getSocketFactory(), 80)); + localSchemeRegistry.register(new Scheme("https", + localSSLSocketFactoryEx, 443)); + DefaultHttpClient localDefaultHttpClient = new DefaultHttpClient( + new ThreadSafeClientConnManager(localBasicHttpParams, + localSchemeRegistry), localBasicHttpParams); + return localDefaultHttpClient; + } catch (Exception localException) { + } + return new DefaultHttpClient(); + } + + public Socket createSocket() throws IOException { + return this.sslContext.getSocketFactory().createSocket(); + } + + public Socket createSocket(Socket paramSocket, String paramString, + int paramInt, boolean paramBoolean) throws IOException, + UnknownHostException { + return this.sslContext.getSocketFactory().createSocket(paramSocket, + paramString, paramInt, paramBoolean); + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateActivity.java b/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateActivity.java new file mode 100644 index 0000000..cdf8561 --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateActivity.java @@ -0,0 +1,340 @@ +package apkeditor.translate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gmail.heagoo.apkeditor.translate.TranslateItem; +import com.gmail.heagoo.common.ActivityUtil; +import com.gmail.heagoo.common.IOUtils; + +public class TranslateActivity extends Activity implements OnClickListener { + + // Standard code like "-zh-rCN" + private String targetLanguageCode; + private String translatedFilePath; + private LinearLayout stringLayout; + + // All the string views + private Map etMap = new HashMap(); + private LinearLayout translatingLayout; + private LinearLayout translatedLayout; + private TextView translatingMsg; + private TextView translatedMsg; + private Button stopOrSaveBtn; + + private boolean translateFinished = false; + private boolean translationSaved = false; + + // Translate list includes items already translated + private List translatedList; + private List untranslatedList; + private TranslateTask translatingTask; + + // How many items need to be translated + private int numToTranslate = 0; + private int numSucceed = 0; + private int numFailed = 0; + + // Style control + private boolean isFullScreen; + private boolean isDark; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + + this.isFullScreen = false; + this.isDark = false; + Intent intent = getIntent(); + if (intent.getExtras() != null) { + isFullScreen = ActivityUtil.getBoolParam(intent, "isFullScreen"); + isDark = ActivityUtil.getBoolParam(intent, "isDark"); + } + + if (isFullScreen) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + if (isDark) { + setTheme(android.R.style.Theme_Black_NoTitleBar); + setContentView(R.layout.activity_autotranslate_dark); + } else { + setContentView(R.layout.activity_autotranslate); + } + + initData(intent); + + initView(translatedList); + + // Start the translating + this.startTranslating(); + } + + @SuppressWarnings("unchecked") + private void initData(Intent intent) { + if (intent.getExtras() != null) { + this.targetLanguageCode = ActivityUtil.getParam(intent, + "targetLanguageCode"); + this.translatedFilePath = ActivityUtil.getParam(intent, + "translatedList_file"); + this.translatedList = (List) IOUtils + .readObjectFromFile(translatedFilePath); + String path = ActivityUtil + .getParam(intent, "untranslatedList_file"); + this.untranslatedList = (List) IOUtils + .readObjectFromFile(path); + } + } + + private void initView(List strings) { + this.stringLayout = (LinearLayout) this + .findViewById(R.id.strings_layout); + + this.translatingLayout = (LinearLayout) this + .findViewById(R.id.translating_layout); + this.translatedLayout = (LinearLayout) this + .findViewById(R.id.translated_layout); + this.translatingMsg = (TextView) translatingLayout + .findViewById(R.id.translating_msg); + this.translatedMsg = (TextView) translatedLayout + .findViewById(R.id.translated_msg); + + if (strings != null) { + for (int i = 0; i < strings.size(); i++) { + TranslateItem item = strings.get(i); + View strView = createStringView(item); + stringLayout.addView(strView); + } + } + + this.stopOrSaveBtn = (Button) this.findViewById(R.id.btn_stop_or_save); + stopOrSaveBtn.setOnClickListener(this); + } + + // Transfer modified files to parent activity + private void setResult(List stringValues) { + Intent intent = new Intent(); + intent.putExtra("targetLanguageCode", this.targetLanguageCode); + IOUtils.writeObjectToFile(this.translatedFilePath, stringValues); + intent.putExtra("translatedList_file", this.translatedFilePath); + + this.setResult(RESULT_OK, intent); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.btn_stop_or_save) { + if (this.translateFinished) { + saveStringAsResource(); + this.translationSaved = true; + this.finish(); + } else { + stopTranslating(); + } + } + } + + private void showSaveDialog(final boolean bStartNewTranslation) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.save_translation_title); + builder.setMessage(R.string.save_translation_msg); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // First save the translation and then do the + // translate + saveStringAsResource(); + TranslateActivity.this.translationSaved = true; + if (bStartNewTranslation) { + // newTranslationTask(); + } + } + }); + builder.setNegativeButton(android.R.string.no, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // Show "x strings are discarded" and start a + // new translation + String msg = getResources().getString( + R.string.string_notsaved_msg); + msg = String.format(msg, numSucceed); + Toast.makeText(TranslateActivity.this, msg, + Toast.LENGTH_LONG).show(); + // newTranslationTask(); + } + }); + builder.show(); + } + + // private void newTranslationTask() { + // this.hide(); + // + // ApkInfoActivity activity = activityRef.get(); + // activity.startNewTranslation(); + // } + + // Forcely stop it + private void stopTranslating() { + translatingTask.cancel(true); + translateCompleted(); + } + + // To save the translation result + private void saveStringAsResource() { + // Prepare translated values (collect from the edit text) + List stringValues = new ArrayList(); + for (Map.Entry entry : etMap.entrySet()) { + String name = entry.getKey(); + String translatedVal = entry.getValue().getText().toString(); + if (!"".equals(translatedVal)) { + stringValues.add(new TranslateItem(name, null, translatedVal)); + } + } + + // No translated string + if (stringValues.isEmpty()) { + // Toast.makeText(this, R.string.error_no_string_tosave, + // Toast.LENGTH_LONG).show(); + return; + } + + setResult(stringValues); + } + + @SuppressLint("InflateParams") + protected View createStringView(TranslateItem item) { + + int itemLayoutId = this.isDark ? R.layout.item_stringvalue_translate_dark + : R.layout.item_stringvalue_translate; + View stringView = getLayoutInflater() + .inflate(itemLayoutId, null, false); + + TextView tv = (TextView) stringView.findViewById(R.id.string_name); + tv.setText(item.name); + + tv = (TextView) stringView.findViewById(R.id.origin_value); + tv.setText(item.originValue); + + EditText et = (EditText) stringView.findViewById(R.id.translated_value); + etMap.put(item.name, et); // Record it + if (item.translatedValue != null) { + et.setText(item.translatedValue); + } + + return stringView; + } + + // Update views + @SuppressLint("DefaultLocale") + public void updateView(List items) { + for (TranslateItem item : items) { + View v = this.createStringView(item); + this.stringLayout.addView(v); + + if (item.translatedValue != null) { + this.numSucceed += 1; + } else { + this.numFailed += 1; + } + } + + String strTranslated = this.getString(R.string.translated); + int total = this.numToTranslate - this.numFailed; + String msg = String.format("%d / %d " + strTranslated, this.numSucceed, + total); + this.translatingMsg.setText(msg); + } + + // Naturally completed, not by force stop + public void translateCompleted() { + this.translateFinished = true; + this.translatingLayout.setVisibility(View.GONE); + this.translatedLayout.setVisibility(View.VISIBLE); + + String msg = null; + if (numToTranslate == 0) { + msg = getString(R.string.error_no_string_totranslate); + } else { + msg = String.format(getString(R.string.translated_format), + numSucceed); + } + + // Failed number + if (numFailed > 0) { + msg += String.format(", " + getString(R.string.failed_format), + numFailed); + } + + // Untranslated number + int untranslatedNum = numToTranslate - numSucceed - numFailed; + if (untranslatedNum > 0) { + msg += String.format( + ", " + getString(R.string.untranslated_format), + untranslatedNum); + } + + this.translatedMsg.setText(msg); + + // Change the button text + if (numSucceed > 0) { + stopOrSaveBtn.setText(R.string.save_and_close); + } else { + stopOrSaveBtn.setText(R.string.close); + } + } + + private void startTranslating() { + + // Update the view + this.translatingMsg.setText(R.string.translating); + this.translatingLayout.setVisibility(View.VISIBLE); + this.translatedLayout.setVisibility(View.GONE); + this.stopOrSaveBtn.setText(R.string.stop); + + this.translationSaved = false; + this.translateFinished = false; + this.numToTranslate = (untranslatedList != null ? untranslatedList.size() : 0); + this.numSucceed = 0; + this.numFailed = 0; + + if (numToTranslate > 0) { + this.translatingTask = new TranslateTask(untranslatedList, this); + translatingTask.execute(); + } else { + translateCompleted(); + } + } + + // Get the google language code + // Convert -zh-rCN to zh-CN + public String getGoogleLangCode() { + String code = this.targetLanguageCode.substring(1); + int pos = code.indexOf("-"); + if (pos != -1) { + code = code.substring(0, pos + 1) + code.substring(pos + 2); + } + return code; + } + +} diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateTask.java b/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateTask.java new file mode 100644 index 0000000..4312dfa --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/TranslateTask.java @@ -0,0 +1,152 @@ +package apkeditor.translate; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.gmail.heagoo.apkeditor.translate.TranslateItem; + +import android.content.Context; +import android.os.AsyncTask; +import android.webkit.WebSettings; +import android.webkit.WebView; + +public class TranslateTask extends + AsyncTask, Boolean> { + + private List untranslated; + private WeakReference activityRef; + + Random r = new Random(); + private String userAgent; + + public TranslateTask(List untranslated, + TranslateActivity activity) { + this.untranslated = untranslated; + this.activityRef = new WeakReference(activity); + } + + @Override + protected void onPreExecute() { + this.userAgent = getUserAgent(activityRef.get()); + } + + @Override + protected void onPostExecute(Boolean result) { + activityRef.get().translateCompleted(); + } + + @Override + protected Boolean doInBackground(Void... params) { + Random r = new Random(System.currentTimeMillis()); + final int maxItems = 10 + r.nextInt(5); + final int maxChars = 900; + + String code = activityRef.get().getGoogleLangCode(); + Translator translator = new Translator(userAgent, code); + + List todo = new ArrayList(); + for (TranslateItem item : untranslated) { + if (this.isCancelled()) { + return false; + } + + // Multiple lines + if (item.originValue.contains("\n")) { + if (!todo.isEmpty()) { + doTranslate(translator, todo); + } + + todo.add(item); + doTranslate(translator, todo); + } else if (todo.size() >= maxItems + || (getTotalCharaters(todo) + item.originValue.length()) > maxChars) { + doTranslate(translator, todo); + todo.add(item); + } else { + todo.add(item); + } + } + + if (this.isCancelled()) { + return todo.isEmpty(); + } + + // Remaining + if (!todo.isEmpty()) { + doTranslate(translator, todo); + } + + return true; + } + + // Compute how many chars + private int getTotalCharaters(List todo) { + int totalLen = 0; + for (TranslateItem item : todo) { + totalLen += item.originValue.length(); + } + return totalLen; + } + + private void doTranslate(Translator translator, List todo) { + // No string need to be translated + if (todo.isEmpty()) { + return; + } + + // Manually sleep awhile, so that I am not taken as a robot + try { + Thread.sleep(300 + r.nextInt(500)); + } catch (InterruptedException e) { + } + + if (this.isCancelled()) { + return; + } + + translator.translate(todo); + checkResult(todo); + todo.clear(); + } + + // Check how many items are successfully translated + @SuppressWarnings("unchecked") + private void checkResult(List translatedItems) { + ArrayList copied = new ArrayList(); + copied.addAll(translatedItems); + this.publishProgress(copied); + } + + @Override + protected void onProgressUpdate(ArrayList... args) { + ArrayList translated = args[0]; + activityRef.get().updateView(translated); + } + + private static String getUserAgent(Context ctx) { + String ua = null; + + WebView webview = new WebView(ctx); + webview.layout(0, 0, 0, 0); + WebSettings settings = webview.getSettings(); + if (settings != null) { + ua = settings.getUserAgentString(); + } + if (ua != null) { + String strNT = " NX"; + StringBuffer sb = new StringBuffer(); + sb.append("Mozilla/5.0"); + sb.append(" (Windows"); + strNT = strNT.replace('X', 'T'); + sb.append(strNT.concat(" 6.1; WOW64) ")); + sb.append("AppleWebKit/537.11 (KHTML, like Gecko) "); + sb.append("Chrome/23.0.1271.97 "); + sb.append("Safari/537.11"); + ua = sb.toString(); + } + + return ua; + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/Translator.java b/apkEditorTranslate/src/main/java/apkeditor/translate/Translator.java new file mode 100644 index 0000000..8704260 --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/Translator.java @@ -0,0 +1,314 @@ +package apkeditor.translate; + +import java.net.URLEncoder; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONTokener; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.Scriptable; + +import com.gmail.heagoo.apkeditor.translate.TranslateItem; + +public class Translator { + + private WebBrowser browser; + private String tkk; + private String startUrl; + + // This is a temporary var + private int jsonIndex = 0; + + private String targetLangCode; + + public Translator(String userAgent, String _target) { + this.browser = new WebBrowser(userAgent); + this.startUrl = "https://translate.google.com/m/translate"; + this.targetLangCode = _target; + + String mainPageContent = browser.get("main", startUrl, null); + + // Can not get the content of the main page + if (mainPageContent == null) { + return; + } + + final String keyword = "tkk:'"; + int startPos = mainPageContent.indexOf(keyword); + // ERROR + if (startPos == -1) { + return; + } + + // Extract the tkk + startPos += keyword.length(); + int endPos = mainPageContent.indexOf("'", startPos); + this.tkk = mainPageContent.substring(startPos, endPos); + } + + // javaScriptCode is like: ((function(){var a\x3d3253064315;var b\x3d-757794981;return 415855+\x27.\x27+(a+b)})()) + private static String unescapeTkkScript(String javaScriptCode) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < javaScriptCode.length(); i++) { + char c = javaScriptCode.charAt(i); + if (c == '\\' && (i + 3 < javaScriptCode.length()) + && javaScriptCode.charAt(i + 1) == 'x') { + char dc = decodeChar(javaScriptCode.charAt(i + 2), + javaScriptCode.charAt(i + 3)); + sb.append(dc); + i += 3; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + private static char decodeChar(char c1, char c2) { + int i1 = hex2Int(c1); + int i2 = hex2Int(c2); + return (char)(i1 * 16 + i2); + } + + private static int hex2Int(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else { + return c - 'A' + 10; + } + } + + protected String encode(String str) { + try { + return URLEncoder.encode(str, "UTF-8"); + } catch (Exception e) { + return str; + } + } + + protected static String getToken(String tkk, String q) { + String tkkScript = unescapeTkkScript(tkk); + + String javaScriptCode = "var Wl=function(a, b) {" + + "for (var c = 0; c < b.length - 2; c += 3) {" + + "var d = b.charAt(c + 2)" + + " , d = \"a\" <= d ? d.charCodeAt(0) - 87 : Number(d)" + + " , d = \"+\" == b.charAt(c + 1) ? a >>> d : a << d;" + + "a = \"+\" == b.charAt(c) ? a + d & 4294967295 : a ^ d" + + "}" + + "return a" + + "}," + + + "Yl = function(b,a) {" + + "var c,d;" + + "d = b.split(\".\");" + + "b = Number(d[0]) || 0;" + + "for (var e = [], f = 0, g = 0; g < a.length; g++) {" + + "var k = a.charCodeAt(g);" + + "128 > k ? e[f++] = k : (2048 > k ? e[f++] = k >> 6 | 192 : (55296 == (k & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (k = 65536 + ((k & 1023) << 10) + (a.charCodeAt(++g) & 1023)," + + "e[f++] = k >> 18 | 240," + + "e[f++] = k >> 12 & 63 | 128) : e[f++] = k >> 12 | 224," + + "e[f++] = k >> 6 & 63 | 128)," + + "e[f++] = k & 63 | 128)" + + "}" + + "a = b;" + + "for (f = 0; f < e.length; f++)" + + "a += e[f]," + + "a = Wl(a, \"+-a^+6\");" + + "a = Wl(a, \"+-3^+b+-f\");" + + "a ^= Number(d[1]) || 0;" + + "0 > a && (a = (a & 2147483647) + 2147483648);" + + "a = a % 1E6;" + + "return a.toString() + \".\" +" + + "(a ^ b)" + +"};"; + + // Every Rhino VM begins with the enter() + // This Context is not Android's Context + Context rhino = Context.enter(); + + // Turn off optimization to make Rhino Android compatible + rhino.setOptimizationLevel(-1); + try { + Scriptable scope = rhino.initStandardObjects(); + + // Note the forth argument is 1, which means the JavaScript source + // has + // been compressed to only one line using something like YUI + Object ret = rhino.evaluateString(scope, tkkScript, + "JavaScript", 1, null); + + rhino.evaluateString(scope, javaScriptCode, + "JavaScript", 1, null); + + // Get the functionName defined in JavaScriptCode + Object obj = scope.get("Yl", scope); + + if (obj instanceof Function) { + Function jsFunction = (Function) obj; + + // Call the function with params + Object jsResult = jsFunction.call(rhino, scope, scope, new Object[] {ret.toString(), q}); + + // Parse the jsResult object to a String + String result = Context.toString(jsResult); + return result; + } + } finally { + Context.exit(); + } + + return null; + } + +// protected static void getToken_Old(String tkk, String a) { +// String originStr = decodeTkk(tkk); +// String[] d = new String[2]; +// int dotPos = originStr.charAt('.'); +// if (dotPos != -1) { +// d[0] = originStr.substring(0, dotPos); +// d[1] = originStr.substring(dotPos + 1); +// } +// +// int c = Integer.valueOf(tkk); +// int b = Integer.valueOf(d[0]); +// int g = 0; +// long new_c = 0; +// StringBuffer d = new StringBuffer(); +// for (; g < a.length(); g++) { +// int k = (int) a.charAt(g); +// if (k < 128) { +// d.append((char) k); +// } else { +// if (k < 2048) { +// d.append((char) ((k >> 6) | 192)); +// } else { +// d.append((char) ((k >> 12) | 224)); +// d.append((char) ((k >> 6) & 63 | 128)); +// } +// d.append((char) (k & 63 | 128)); +// } +// } +// for (int i = 0; i < d.length(); i++) { +// c += (int) d.charAt(i); +// c += c << 10; +// c ^= c >>> 6; +// } +// c += c << 3; +// c ^= c >>> 11; +// c = c + (c << 15) & 0xffffffff; +// if (c < 0) { +// new_c = (c & 0x7fffffff) + 0x80000000L; +// } else { +// new_c = c; +// } +// new_c %= 1E6; +// return String.valueOf(new_c) + "|" + String.valueOf(new_c ^ b); +// } + + public void translate(List items) { + // This may be caused by main page loading fail + if (tkk == null) { + return; + } + + // Concat the string + StringBuffer queryBuf = new StringBuffer(); + for (TranslateItem item : items) { + queryBuf.append(item.originValue); + queryBuf.append('\n'); + } + queryBuf.deleteCharAt(queryBuf.length() - 1); + String q = queryBuf.toString(); + + String url = "https://translate.google.com/translate_a/single?" + + "client=webapp&sl=auto&tl=" + + targetLangCode + + "&hl=en&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&otf=1&ssel=0&tsel=0&kc=1&tk=" + + encode(getToken(tkk, q)) + "&q=" + encode(q); + Debug.log("url=%s", url); + String content = browser.get("translate", url, startUrl); + + // Succeed + if (content != null && content.startsWith("[[[\"")) { + int position = content.indexOf("]]"); + if (position != -1) { + parseContent(content.substring(1, position + 2), items); + } + } + } + + // Parse the content and save result to items + private void parseContent(String str, List items) { + try { + JSONTokener jsonParser = new JSONTokener(str); + JSONArray values = (JSONArray) jsonParser.nextValue(); + // Only one item, all the translation content should save to it + if (items.size() == 1) { + items.get(0).translatedValue = extractAllValueFromJson(values); +// Log.d("DEBUG", +// items.get(0).originValue + " ---> " +// + items.get(0).translatedValue); + } else { + int srcNum = items.size(); + this.jsonIndex = 0; + for (int i = 0; i < srcNum; i++) { + TranslateItem item = items.get(i); + item.translatedValue = extractOneItemFromJson(values); +// Log.d("DEBUG", item.originValue + " ---> " +// + item.translatedValue); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // In Json, one item may be splited into several arrays + // jsonIndex will be used + private String extractOneItemFromJson(JSONArray values) + throws JSONException { + StringBuffer sb = new StringBuffer(); + while (jsonIndex < values.length() - 1) { + JSONArray oneArray = (JSONArray) values.get(jsonIndex++); + String curVal = (String) oneArray.get(0); + if (curVal == null) { + break; + } + + sb.append(curVal); + if (curVal.endsWith("\n")) { + sb.deleteCharAt(sb.length() - 1); + break; + } + } + if (sb.length() > 0) { + return sb.toString(); + } + return null; + } + + private String extractAllValueFromJson(JSONArray values) + throws JSONException { + int jsonIndex = 0; + StringBuffer sb = new StringBuffer(); + while (jsonIndex < values.length() - 1) { + JSONArray oneArray = (JSONArray) values.get(jsonIndex++); + String curVal = (String) oneArray.get(0); + if (curVal == null) { + break; + } + + sb.append(curVal); + } + if (sb.length() > 0) { + return sb.toString(); + } + return null; + } +} diff --git a/apkEditorTranslate/src/main/java/apkeditor/translate/WebBrowser.java b/apkEditorTranslate/src/main/java/apkeditor/translate/WebBrowser.java new file mode 100644 index 0000000..a94465b --- /dev/null +++ b/apkEditorTranslate/src/main/java/apkeditor/translate/WebBrowser.java @@ -0,0 +1,190 @@ +package apkeditor.translate; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.DefaultHttpClient; + +import android.util.Log; + +public class WebBrowser { + private MyCookieStore cookieStore = new MyCookieStore(); + // HttpHost proxy = new HttpHost("proxy-shz.intel.com", 911, "http"); + HttpHost proxy = new HttpHost("xxx", 911, "http"); + private boolean useProxy = false; + private boolean useSSL = false; + + private String userAgent = null; + + public WebBrowser() { + this(false); + } + + public WebBrowser(String userAgent) { + this.userAgent = userAgent; + } + + public WebBrowser(boolean paramBoolean) { + this.useSSL = paramBoolean; + } + + private DefaultHttpClient getHttpClient() { + if (this.useSSL) + return SSLSocketFactoryEx.getNewHttpClient(); + return new DefaultHttpClient(); + } + + private String getString(InputStream input) { + int bufferSize = 256 * 1024; + int readSize = 0; + + try { + byte[] buffer = new byte[bufferSize]; + int maxStrSize = bufferSize - 1; + while (readSize < maxStrSize) { + int ret = input.read(buffer, readSize, maxStrSize - readSize); + if (ret <= 0) { + break; + } + readSize += ret; + } + + if (readSize > 0) { + String str = new String(buffer, 0, readSize, "UTF-8"); + return str; + } + } catch (IOException e) { + e.printStackTrace(); + } + + return ""; + } + + public String get(String tag, String strUrl, String referUrl) { + String str = null; + try { + HttpGet httpGet = new HttpGet(strUrl); + httpGet.getParams().setParameter("http.protocol.cookie-policy", + "compatibility"); + DefaultHttpClient httpClient = getHttpClient(); + if (userAgent != null) + httpGet.addHeader("User-Agent", userAgent); + if (referUrl != null) { + httpGet.addHeader("Referer", referUrl); + } + MyCookieStore cookieStore = this.cookieStore; + str = null; + if (cookieStore != null) { + httpClient.setCookieStore(this.cookieStore); + } + if (this.useProxy) { + httpClient.getParams().setParameter("http.route.default-proxy", + this.proxy); + } + httpClient.getParams().setParameter("http.connection.timeout", + Integer.valueOf(15000)); + httpClient.getParams().setParameter("http.socket.timeout", + Integer.valueOf(15000)); + str = getString(httpClient.execute(httpGet).getEntity() + .getContent()); + // Debug.dump(tag + ".html", str); + List newCookies = httpClient.getCookieStore().getCookies(); + this.cookieStore.addCookies(newCookies); + return str; + } catch (Exception e) { + e.printStackTrace(); + Debug.dump(tag + ".error", e.getMessage()); + } + return str; + } + + public MyCookieStore getCookieStore() { + return this.cookieStore; + } + + public String post(String tag, String uri, List paramList) { + HttpPost httpPost = new HttpPost(uri); + // httpPost.addHeader("Origin", "http://home.guahao.cn"); + httpPost.addHeader("Content-Type", + "application/x-www-form-urlencoded; charset=\"UTF-8\""); + httpPost.addHeader("X-Requested-With", "XMLHttpRequest"); + httpPost.addHeader( + "User-Agent", + "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36"); + httpPost.addHeader("Accept", + "application/json, text/javascript, */*; q=0.01"); + // httpPost.addHeader("Referer", + // "http://home.guahao.cn/expert/97bf49b0-ca4c-476d-b780-d2f0c2d4b126"); + httpPost.addHeader("Accept-Encoding", "gzip,deflate,sdch"); + httpPost.addHeader("Accept-Language", "en-US,en;q=0.8"); + httpPost.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3"); + return post(tag, httpPost, paramList); + } + + public String post(String tag, HttpPost httpPost, + List paramList) { + String str = null; + try { + int k = paramList.size(); + str = null; + if (k > 0) + httpPost.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8")); + if (!httpPost.containsHeader("Content-Type")) + httpPost.addHeader("Content-Type", + "application/x-www-form-urlencoded; charset=\"UTF-8\""); + if (!httpPost.containsHeader("User-Agent") && userAgent != null) { + httpPost.addHeader("User-Agent", userAgent); + } + httpPost.getParams().setParameter("http.protocol.cookie-policy", + "compatibility"); + DefaultHttpClient localDefaultHttpClient = getHttpClient(); + MyCookieStore localMyCookieStore = this.cookieStore; + str = null; + if (localMyCookieStore != null) + localDefaultHttpClient.setCookieStore(this.cookieStore); + boolean bool = this.useProxy; + str = null; + if (bool) + localDefaultHttpClient.getParams().setParameter( + "http.route.default-proxy", this.proxy); + localDefaultHttpClient.getParams().setParameter( + "http.connection.timeout", Integer.valueOf(15000)); + localDefaultHttpClient.getParams().setParameter( + "http.socket.timeout", Integer.valueOf(15000)); + //Log.d("DEBUG", "Will call httpClient.execute"); + HttpResponse localHttpResponse = localDefaultHttpClient + .execute(httpPost); + //Log.d("DEBUG", "After call httpClient.execute"); + str = getString(localHttpResponse.getEntity().getContent()); + //Log.d("DEBUG", "Response got!"); + Header[] arrayOfHeader = localHttpResponse.getAllHeaders(); + StringBuffer localStringBuffer = new StringBuffer(); + int i = arrayOfHeader.length; + for (int j = 0;; j++) { + if (j >= i) { + Debug.dump(tag + ".header", localStringBuffer.toString()); + Debug.dump(tag + ".html", str); + List newCookies = localDefaultHttpClient + .getCookieStore().getCookies(); + this.cookieStore.addCookies(newCookies); + return str; + } + Header localHeader = arrayOfHeader[j]; + localStringBuffer.append(localHeader.getName() + ": " + + localHeader.getValue() + "\n"); + } + } catch (Exception localException) { + Debug.dump(tag + ".error", localException.getMessage()); + } + return str; + } +} \ No newline at end of file diff --git a/apkEditorTranslate/src/main/java/com/gmail/heagoo/apkeditor/translate/TranslateItem.java b/apkEditorTranslate/src/main/java/com/gmail/heagoo/apkeditor/translate/TranslateItem.java new file mode 100644 index 0000000..612cd10 --- /dev/null +++ b/apkEditorTranslate/src/main/java/com/gmail/heagoo/apkeditor/translate/TranslateItem.java @@ -0,0 +1,22 @@ +package com.gmail.heagoo.apkeditor.translate; + +import java.io.Serializable; + +public class TranslateItem implements Serializable { + + private static final long serialVersionUID = -3101805950698159689L; + public String name; + public String originValue; + public String translatedValue; + + public TranslateItem(String _n, String _o) { + this.name = _n; + this.originValue = _o; + } + + public TranslateItem(String _n, String _o, String _t) { + this.name = _n; + this.originValue = _o; + this.translatedValue = _t; + } +} diff --git a/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/ActivityUtil.java b/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/ActivityUtil.java new file mode 100644 index 0000000..03442b9 --- /dev/null +++ b/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/ActivityUtil.java @@ -0,0 +1,126 @@ +package com.gmail.heagoo.common; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import android.content.Intent; +import android.os.Bundle; + +public class ActivityUtil { + + public static Bundle attachParam(Intent intent, String key, String value) { + Bundle bundle = new Bundle(); + bundle.putString(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static Bundle attachParam(Intent intent, String key, boolean value) { + Bundle bundle = new Bundle(); + bundle.putBoolean(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static Bundle attachParam(Intent intent, String key, ArrayList value) { + Bundle bundle = new Bundle(); + bundle.putStringArrayList(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static Bundle attachParam2(Intent intent, String key, ArrayList value) { + Bundle bundle = new Bundle(); + bundle.putIntegerArrayList(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static Bundle attachParam(Intent intent, String key, int value) { + Bundle bundle = new Bundle(); + bundle.putInt(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static Bundle attachBoolParam(Intent intent, String key, boolean value) { + Bundle bundle = new Bundle(); + bundle.putBoolean(key, value); + intent.putExtras(bundle); + return bundle; + } + + public static String getParam(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + return bundle.getString(key); + } + return null; + } + + public static boolean getBoolParam(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + return bundle.getBoolean(key, false); + } + return false; + } + + public static int getIntParam(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + return bundle.getInt(key, 0); + } + return 0; + } + + public static ArrayList getStringArray(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + return bundle.getStringArrayList(key); + } + return null; + } + + public static ArrayList getIntArray(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + return bundle.getIntegerArrayList(key); + } + return null; + } + + public static void attachParam(Intent intent, String key, + Map mapValue) { + Bundle bundle = new Bundle(); + ArrayList keyList = new ArrayList(); + ArrayList valueList = new ArrayList(); + for (String strKey : mapValue.keySet()) { + String strVal = mapValue.get(strKey); + keyList.add(strKey); + valueList.add(strVal); + } + bundle.putStringArrayList(key + "_keys", keyList); + bundle.putStringArrayList(key + "_values", valueList); + intent.putExtras(bundle); + } + + public static Map getMapParam(Intent intent, String key) { + Bundle bundle = intent.getExtras(); + if (bundle != null) { + Map mapVal = new HashMap(); + ArrayList strKeys = bundle + .getStringArrayList(key + "_keys"); + ArrayList strValues = bundle.getStringArrayList(key + + "_values"); + if (strKeys != null && strValues != null) { + for (int i = 0; i < strKeys.size(); i++) { + mapVal.put(strKeys.get(i), strValues.get(i)); + } + return mapVal; + } + } + return null; + } +} diff --git a/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/IOUtils.java b/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/IOUtils.java new file mode 100644 index 0000000..8f0993b --- /dev/null +++ b/apkEditorTranslate/src/main/java/com/gmail/heagoo/common/IOUtils.java @@ -0,0 +1,115 @@ +package com.gmail.heagoo.common; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +public class IOUtils { + + public static void copy(InputStream in, OutputStream out) + throws IOException { + byte[] buffer = new byte[4096]; + int count = 0; + while ((count = in.read(buffer)) != -1) { + out.write(buffer, 0, count); + } + } + + public static byte[] toByteArray(InputStream in) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(in, output); + return output.toByteArray(); + } + + public static void writeZero(OutputStream out, int size) throws IOException { + int blocks = size / 1024; + int remain = size % 1024; + + byte[] buffer = new byte[1024]; + for (int i = 0; i < 1024; i++) { + buffer[i] = 0; + } + + for (int i = 0; i < blocks; i++) { + out.write(buffer); + } + + if (remain > 0) { + out.write(buffer, 0, remain); + } + } + + public static void readFully(InputStream is, byte[] buf) throws IOException { + int read = 0; + while (read < buf.length) { + int ret = is.read(buf, read, buf.length - read); + if (ret != -1) { + read += ret; + } else { + break; + } + } + } + + public static void writeObjectToFile(String filePath, Object obj) { + File file = new File(filePath); + ObjectOutputStream objOut = null; + try { + objOut = new ObjectOutputStream(new FileOutputStream(file)); + objOut.writeObject(obj); + objOut.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + closeWithoutThrow(objOut); + } + } + + public static Object readObjectFromFile(String filePath) { + Object result = null; + File file = new File(filePath); + ObjectInputStream objIn = null; + try { + objIn = new ObjectInputStream(new FileInputStream(file)); + result = objIn.readObject(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } finally { + closeWithoutThrow(objIn); + } + return result; + } + + public static String readString(InputStream input) throws IOException { + StringBuilder sb = new StringBuilder(); + BufferedReader br = new BufferedReader(new InputStreamReader(input)); + String line = br.readLine(); + while (line != null) { + sb.append(line); + sb.append("\n"); + line = br.readLine(); + } + return sb.toString(); + + } + + private static void closeWithoutThrow(Closeable c) { + if (c != null) { + try { + c.close(); + } catch (IOException e) { + } + } + } +} diff --git a/apkEditorTranslate/src/main/res/drawable/applistutil_btn_custom.xml b/apkEditorTranslate/src/main/res/drawable/applistutil_btn_custom.xml new file mode 100644 index 0000000..5b5dc98 --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/applistutil_btn_custom.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/applistutil_button.9.png b/apkEditorTranslate/src/main/res/drawable/applistutil_button.9.png new file mode 100644 index 0000000..e7da9e4 Binary files /dev/null and b/apkEditorTranslate/src/main/res/drawable/applistutil_button.9.png differ diff --git a/apkEditorTranslate/src/main/res/drawable/applistutil_button_hilight.9.png b/apkEditorTranslate/src/main/res/drawable/applistutil_button_hilight.9.png new file mode 100644 index 0000000..0787270 Binary files /dev/null and b/apkEditorTranslate/src/main/res/drawable/applistutil_button_hilight.9.png differ diff --git a/apkEditorTranslate/src/main/res/drawable/bg_button_style.xml b/apkEditorTranslate/src/main/res/drawable/bg_button_style.xml new file mode 100644 index 0000000..304a7ce --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_button_style.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext.xml new file mode 100644 index 0000000..cd828ad --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext_dark.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext_dark.xml new file mode 100644 index 0000000..57ea8da --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext_dark.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused.xml new file mode 100644 index 0000000..043fb2f --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused_dark.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused_dark.xml new file mode 100644 index 0000000..1d3ce64 --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext_focused_dark.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal.xml new file mode 100644 index 0000000..5b11198 --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal_dark.xml b/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal_dark.xml new file mode 100644 index 0000000..b9b25f1 --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/bg_edittext_normal_dark.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/drawable/blue.png b/apkEditorTranslate/src/main/res/drawable/blue.png new file mode 100644 index 0000000..3abcf46 Binary files /dev/null and b/apkEditorTranslate/src/main/res/drawable/blue.png differ diff --git a/apkEditorTranslate/src/main/res/drawable/commonutil_progressbar.xml b/apkEditorTranslate/src/main/res/drawable/commonutil_progressbar.xml new file mode 100644 index 0000000..aed3665 --- /dev/null +++ b/apkEditorTranslate/src/main/res/drawable/commonutil_progressbar.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/apkEditorTranslate/src/main/res/layout/activity_autotranslate.xml b/apkEditorTranslate/src/main/res/layout/activity_autotranslate.xml new file mode 100644 index 0000000..a4635e9 --- /dev/null +++ b/apkEditorTranslate/src/main/res/layout/activity_autotranslate.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +