From f32005f29d91ce8b27a07cd66af12e9c3c7fb85f Mon Sep 17 00:00:00 2001 From: Steven Bazyl Date: Tue, 14 Dec 2021 13:13:34 -0700 Subject: [PATCH] Remove obsolete android sample, deprecated ~3 years ago --- android/AndroidManifest.xml | 9 - android/MyAddOnActivity.java | 54 -- android/README.md | 9 - android/mobile-translate/Code.gs | 260 ------ android/mobile-translate/README.md | 118 --- android/mobile-translate/app/build.gradle | 48 - .../app/src/main/AndroidManifest.xml | 46 - .../DefaultLaunchActivity.java | 50 -- .../mobiledoctranslate/MainActivity.java | 848 ------------------ .../main/res/layout-land/activity_main.xml | 72 -- .../app/src/main/res/layout/activity_main.xml | 63 -- .../app/src/main/res/layout/buttons.xml | 28 - .../src/main/res/layout/input_text_pane.xml | 19 - .../src/main/res/layout/launch_default.xml | 28 - .../src/main/res/layout/output_text_pane.xml | 22 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 4266 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2436 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 5736 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 9451 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 13259 -> 0 bytes .../app/src/main/res/values/colors.xml | 4 - .../app/src/main/res/values/dimens.xml | 22 - .../app/src/main/res/values/strings.xml | 61 -- .../app/src/main/res/values/styles.xml | 26 - 24 files changed, 1787 deletions(-) delete mode 100644 android/AndroidManifest.xml delete mode 100644 android/MyAddOnActivity.java delete mode 100644 android/README.md delete mode 100644 android/mobile-translate/Code.gs delete mode 100644 android/mobile-translate/README.md delete mode 100644 android/mobile-translate/app/build.gradle delete mode 100644 android/mobile-translate/app/src/main/AndroidManifest.xml delete mode 100644 android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/DefaultLaunchActivity.java delete mode 100644 android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/MainActivity.java delete mode 100644 android/mobile-translate/app/src/main/res/layout-land/activity_main.xml delete mode 100644 android/mobile-translate/app/src/main/res/layout/activity_main.xml delete mode 100644 android/mobile-translate/app/src/main/res/layout/buttons.xml delete mode 100644 android/mobile-translate/app/src/main/res/layout/input_text_pane.xml delete mode 100644 android/mobile-translate/app/src/main/res/layout/launch_default.xml delete mode 100644 android/mobile-translate/app/src/main/res/layout/output_text_pane.xml delete mode 100644 android/mobile-translate/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/mobile-translate/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/mobile-translate/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/mobile-translate/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/mobile-translate/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/mobile-translate/app/src/main/res/values/colors.xml delete mode 100644 android/mobile-translate/app/src/main/res/values/dimens.xml delete mode 100644 android/mobile-translate/app/src/main/res/values/strings.xml delete mode 100644 android/mobile-translate/app/src/main/res/values/styles.xml diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml deleted file mode 100644 index 91c1a45dc..000000000 --- a/android/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/android/MyAddOnActivity.java b/android/MyAddOnActivity.java deleted file mode 100644 index 25207d78d..000000000 --- a/android/MyAddOnActivity.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// [START apps_script_android_activity] -import android.accounts.Account; -import android.app.Activity; - -public class MyAddOnActivity extends Activity { - // Your activity... - - String sessionState; - String docId; - Account account; - - @Override - protected void onCreate(Bundle state) { - super.onCreate(state); - docId = getIntent().getStringExtra( - "com.google.android.apps.docs.addons.DocumentId"); - sessionState = getIntent().getStringExtra( - "com.google.android.apps.docs.addons.SessionState"); - account = (Account) getIntent().getParcelableExtra( - "com.google.android.apps.docs.addons.Account"); - // Your activity’s initialization... - } - - // [START apps_script_android_execution] - protected void makeRequest() { - // Acquire the session state String from the calling Intent. - sessionState = getIntent().getStringExtra( - "com.google.android.apps.docs.addons.SessionState"); - // ... - // Construct the API request. - ExecutionRequest request = new ExecutionRequest() - .setFunction(functionName) - .setSessionState(sessionState) - .setParameters(params) // Only needed if the function requires parameters - .setDevMode(true); // Optional - } - // [END apps_script_android_execution] -} -// [END apps_script_android_activity] \ No newline at end of file diff --git a/android/README.md b/android/README.md deleted file mode 100644 index bb9ebeb4c..000000000 --- a/android/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Apps Scripts for Android - -## [Converting Android Apps into Android Add-ons](https://developers.google.com/apps-script/add-ons/mobile/android) - -This sample describes how to convert an existing Android app into an Android add-on. - -## Mobile Doc Translate Add-on - -A sample Google Apps Script mobile add-on for Google Docs. diff --git a/android/mobile-translate/Code.gs b/android/mobile-translate/Code.gs deleted file mode 100644 index 3f147683e..000000000 --- a/android/mobile-translate/Code.gs +++ /dev/null @@ -1,260 +0,0 @@ -/** - * Copyright Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @OnlyCurrentDoc - * - * The above comment directs Apps Script to limit the scope of file - * access for this add-on. It specifies that this add-on will only - * attempt to read or modify the files in which the add-on is used, - * and not all of the user's files. The authorization request message - * presented to users will reflect this limited scope. - */ - -/** - * Creates a menu entry in the Google Docs UI when the document is opened. - * This method is only used by the regular add-on, and is never called by - * the mobile add-on version. - * - * @param {object} e The event parameter for a simple onOpen trigger. To - * determine which authorization mode (ScriptApp.AuthMode) the trigger is - * running in, inspect e.authMode. - */ -function onOpen(e) { - DocumentApp.getUi().createAddonMenu() - .addItem('Start', 'showSidebar') - .addToUi(); -} - -/** - * Runs when the add-on is installed. - * This method is only used by the regular add-on, and is never called by - * the mobile add-on version. - * - * @param {object} e The event parameter for a simple onInstall trigger. To - * determine which authorization mode (ScriptApp.AuthMode) the trigger is - * running in, inspect e.authMode. (In practice, onInstall triggers always - * run in AuthMode.FULL, but onOpen triggers may be AuthMode.LIMITED or - * AuthMode.NONE.) - */ -function onInstall(e) { - onOpen(e); -} - -/** - * Opens a sidebar in the document containing the add-on's user interface. - * This method is only used by the regular add-on, and is never called by - * the mobile add-on version. - */ -function showSidebar() { - var ui = HtmlService.createHtmlOutputFromFile('Sidebar') - .setTitle('Translate'); - DocumentApp.getUi().showSidebar(ui); -} - -/** - * Gets the text the user has selected. If there is no selection, - * this function displays an error message. - * - * @return {Array.} The selected text. - */ -function getSelectedText() { - var selection = DocumentApp.getActiveDocument().getSelection(); - if (selection) { - var text = []; - var elements = selection.getSelectedElements(); - for (var i = 0; i < elements.length; i++) { - if (elements[i].isPartial()) { - var element = elements[i].getElement().asText(); - var startIndex = elements[i].getStartOffset(); - var endIndex = elements[i].getEndOffsetInclusive(); - - text.push(element.getText().substring(startIndex, endIndex + 1)); - } else { - var element = elements[i].getElement(); - // Only translate elements that can be edited as text; skip images and - // other non-text elements. - if (element.editAsText) { - var elementText = element.asText().getText(); - // This check is necessary to exclude images, which return a blank - // text element. - if (elementText != '') { - text.push(elementText); - } - } - } - } - if (text.length) { - throw new Error('Please select some text.'); - } - return text; - } else { - throw new Error('Please select some text.'); - } -} - -/** - * Gets the stored user preferences for the origin and destination languages, - * if they exist. - * This method is only used by the regular add-on, and is never called by - * the mobile add-on version. - * - * @return {Object} The user's origin and destination language preferences, if - * they exist. - */ -function getPreferences() { - var userProperties = PropertiesService.getUserProperties(); - var languagePrefs = { - originLang: userProperties.getProperty('originLang'), - destLang: userProperties.getProperty('destLang') - }; - return languagePrefs; -} - -/** - * Gets the user-selected text and translates it from the origin language to the - * destination language. The languages are notated by their two-letter short - * form. For example, English is 'en', and Spanish is 'es'. The origin language - * may be specified as an empty string to indicate that Google Translate should - * auto-detect the language. - * - * @param {string} origin The two-letter short form for the origin language. - * @param {string} dest The two-letter short form for the destination language. - * @param {boolean} savePrefs Whether to save the origin and destination - * language preferences. - * @return {Object} Object containing the original text and the result of the - * translation. - */ -function getTextAndTranslation(origin, dest, savePrefs) { - var result = {}; - var text = getSelectedText(); - result['text'] = text.join('\n'); - - if (savePrefs == true) { - var userProperties = PropertiesService.getUserProperties(); - userProperties.setProperty('originLang', origin); - userProperties.setProperty('destLang', dest); - } - - result['translation'] = translateText(result['text'], origin, dest); - - return result; -} - -/** - * Replaces the text of the current selection with the provided text, or - * inserts text at the current cursor location. (There will always be either - * a selection or a cursor.) If multiple elements are selected, only inserts the - * translated text in the first element that can contain text and removes the - * other elements. - * - * @param {string} newText The text with which to replace the current selection. - */ -function insertText(newText) { - var selection = DocumentApp.getActiveDocument().getSelection(); - if (selection) { - var replaced = false; - var elements = selection.getSelectedElements(); - if (elements.length == 1 && - elements[0].getElement().getType() == - DocumentApp.ElementType.INLINE_IMAGE) { - throw new Error('Can\'t insert text into an image.'); - } - for (var i = 0; i < elements.length; i++) { - if (elements[i].isPartial()) { - var element = elements[i].getElement().asText(); - var startIndex = elements[i].getStartOffset(); - var endIndex = elements[i].getEndOffsetInclusive(); - - var remainingText = element.getText().substring(endIndex + 1); - element.deleteText(startIndex, endIndex); - if (!replaced) { - element.insertText(startIndex, newText); - replaced = true; - } else { - // This block handles a selection that ends with a partial element. We - // want to copy this partial text to the previous element so we don't - // have a line-break before the last partial. - var parent = element.getParent(); - parent.getPreviousSibling().asText().appendText(remainingText); - // We cannot remove the last paragraph of a doc. If this is the case, - // just remove the text within the last paragraph instead. - if (parent.getNextSibling()) { - parent.removeFromParent(); - } else { - element.removeFromParent(); - } - } - } else { - var element = elements[i].getElement(); - if (!replaced && element.editAsText) { - // Only translate elements that can be edited as text, removing other - // elements. - element.clear(); - element.asText().setText(newText); - replaced = true; - } else { - // We cannot remove the last paragraph of a doc. If this is the case, - // just clear the element. - if (element.getNextSibling()) { - element.removeFromParent(); - } else { - element.clear(); - } - } - } - } - } else { - var cursor = DocumentApp.getActiveDocument().getCursor(); - var surroundingText = cursor.getSurroundingText().getText(); - var surroundingTextOffset = cursor.getSurroundingTextOffset(); - - // If the cursor follows or preceds a non-space character, insert a space - // between the character and the translation. Otherwise, just insert the - // translation. - if (surroundingTextOffset > 0) { - if (surroundingText.charAt(surroundingTextOffset - 1) != ' ') { - newText = ' ' + newText; - } - } - if (surroundingTextOffset < surroundingText.length) { - if (surroundingText.charAt(surroundingTextOffset) != ' ') { - newText += ' '; - } - } - cursor.insertText(newText); - } -} - - -/** - * Given text, translate it from the origin language to the destination - * language. The languages are notated by their two-letter short form. For - * example, English is 'en', and Spanish is 'es'. The origin language may be - * specified as an empty string to indicate that Google Translate should - * auto-detect the language. - * - * @param {string} text text to translate. - * @param {string} origin The two-letter short form for the origin language. - * @param {string} dest The two-letter short form for the destination language. - * @return {string} The result of the translation, or the original text if - * origin and dest languages are the same. - */ -function translateText(text, origin, dest) { - if (origin === dest) { - return text; - } - return LanguageApp.translate(text, origin, dest); -} diff --git a/android/mobile-translate/README.md b/android/mobile-translate/README.md deleted file mode 100644 index 83c245640..000000000 --- a/android/mobile-translate/README.md +++ /dev/null @@ -1,118 +0,0 @@ -Mobile Doc Translate Add-on -=========================== - -A sample Google Apps Script mobile add-on for Google Docs. This add-on is -essentially a mobile version of the Docs -[Translate Add-on Quickstart](https://developers.google.com/apps-script/quickstart/docs). - -Introduction ------------- - -Google Apps Script now allows developers to construct Mobile Add-ons -- Android -applications which extend and support Google Docs and Sheets. - -This sample shows how to construct a mobile add-on called -**Mobile Doc Translate**. This add-on allows users to select text in a -Google Doc on their mobile device and see a translation of that text in one -of several languages. The user can then edit the translation as needed and -replace the original selected text in the Doc with the translation. - - -Getting Started ---------------- - -The add-on will need to call an Apps Script project to get Doc text, make -translations, and insert text into the Doc. Users can access this add-on from -the Google Docs Android app by highlighting text and selecting the add-on in the -text context menu. - -The Apps Script code file for this project is `Code.gs`. This is the same code -used in the [Translate Add-on Quickstart](https://developers.google.com/apps-script/quickstart/docs), -but does not include the HTML code that defines the quickstart's sidebar. - -The mobile add-on will make use of the -[Apps Script Execution API](https://developers.google.com/apps-script/guides/rest/) -to call the `Code.gs` functions. The -[Execution API quickstart for Android](https://developers.google.com/apps-script/guides/rest/quickstart/android) -describes how to call Apps Script functions from Android applications. - -To build this sample: - -1. The `app/` folder in this repository contains all the required Android files - for this add-on. These can be manually copied or imported into a new Android - Studio project. -1. Create a new Apps Script project. -1. Replace the code in the new project's `Code.gs` file with the code from this - repo. -1. Save the project. -1. In the code editor, select **Publish > Deploy as API** executable. -1. In the dialog that opens, leave the **Version** as "New" and enter - "Target-v1" into the text box. Click **Deploy**. -1. Follow the - [Keytool SHA1 Fingerprint](https://developers.google.com/apps-script/guides/rest/quickstart/android#step_1_acquire_a_sha1_fingerprint) - instructions to acquire a SHA1 fingerprint for your project. -1. Using that SHA code, follow the - [Turn on the Execution API](https://developers.google.com/apps-script/guides/rest/quickstart/android#step_2_turn_on_the_api_name) - instructions to enable the API for your script project and create OAuth - credentials. Be sure to match the same package name used in your Android - code. -1. Edit the `MainActivity.java` file so that the `SCRIPT_ID` constant is set to - your Apps Script project ID (in the script editor, select - **File > Project properties**, and use the **Project key**). - - These steps should allow you to build the Android app and have it successfully - call the Apps Script code. You can test it by: - - 1. Install the app on a test Android device. - 1. Set the app as the debug app on the device by running this - [ADB](https://developer.android.com/studio/command-line/adb.html) - command: - `$ adb shell am set-debug-app --persistent ` - 1. Open a docucment using the Google Docs app on the device. - 1. Highlight some text in the doc and select the three-dot icon to open the - context menu, and then select **Mobile Doc Translate**. - -Learn more ----------- - -To continue learning about mobile add-ons for Google Docs and Sheets, -take a look at the following resources: - -* [Mobile Add-ons](https://developers.google.com/apps-script/add-ons/mobile) -* [Apps Script Execution API](https://developers.google.com/apps-script/guides/) - -Support -------- - -For general Apps Script support, check the following: - -- Stack Overflow Tag: [google-apps-script](http://stackoverflow.com/questions/tagged/google-apps-script) -- Issue Tracker: [google-apps-script-issues](https://code.google.com/p/google-apps-script-issues/issues/list) - -If you've found an error in this sample, please file an issue: -https://github.com/googlesamples/apps-script-mobile-addons - -Patches are encouraged, and may be submitted by forking this project and -submitting a pull request through GitHub. - -License -------- - -Copyright 2016 Google, Inc. - -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. \ No newline at end of file diff --git a/android/mobile-translate/app/build.gradle b/android/mobile-translate/app/build.gradle deleted file mode 100644 index 5a3e94242..000000000 --- a/android/mobile-translate/app/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -apply plugin: 'com.android.application' - -def keystorePropertiesFile = rootProject.file("keystore.properties") -def keystoreProperties = new Properties() -keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) - -android { - signingConfigs { - mainRelease { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile file(keystoreProperties['storeFile']) - storePassword keystoreProperties['storePassword'] - } - } - compileSdkVersion 23 - buildToolsVersion "24.0.0 rc4" - defaultConfig { - applicationId "com.google.samples.mobiledoctranslate" - minSdkVersion 17 - targetSdkVersion 23 - versionCode 2 - versionName "1.0.1" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), - 'proguard-rules.pro' - signingConfig signingConfigs.mainRelease - } - } -} - -dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.google.android.gms:play-services-auth:9.0.2' - compile 'com.android.support:cardview-v7:23.4.0' - compile 'pub.devrel:easypermissions:0.1.5' - compile('com.google.api-client:google-api-client-android:1.20.0') { - exclude group: 'org.apache.httpcomponents' - } - compile('com.google.apis:google-api-services-script:v1-rev1-1.20.0') { - exclude group: 'org.apache.httpcomponents' - } -} diff --git a/android/mobile-translate/app/src/main/AndroidManifest.xml b/android/mobile-translate/app/src/main/AndroidManifest.xml deleted file mode 100644 index 6bffeaec7..000000000 --- a/android/mobile-translate/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/DefaultLaunchActivity.java b/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/DefaultLaunchActivity.java deleted file mode 100644 index e5dd3bfb9..000000000 --- a/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/DefaultLaunchActivity.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.samples.mobiledoctranslate; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; - -/** - * Since this add-on needs context from the Docs editor app, it should only be - * launched from that app (via context menus). - * - * This activity handles the edge case where the app is (erroneously) launched - * from the home screen or a notification. This activity simply presents a - * message to the user and provides an Exit button. - */ -public class DefaultLaunchActivity extends Activity { - - /** - * Create the default launch activity. - * @param savedInstanceState previously saved instance data - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.launch_default); - } - - /** - * Cancel the add-on and return without action. - * @param v The button's View context - */ - public void cancel(View v) { - setResult(Activity.RESULT_CANCELED); - finish(); - } -} diff --git a/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/MainActivity.java b/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/MainActivity.java deleted file mode 100644 index 1995695aa..000000000 --- a/android/mobile-translate/app/src/main/java/com/google/samples/mobiledoctranslate/MainActivity.java +++ /dev/null @@ -1,848 +0,0 @@ -/** - * Copyright Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.samples.mobiledoctranslate; - -import com.google.android.gms.auth.GoogleAuthException; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GoogleApiAvailability; -import com.google.api.client.extensions.android.http.AndroidHttp; -import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; -import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; -import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; -import com.google.api.client.http.HttpRequest; -import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.client.util.ExponentialBackOff; -import com.google.api.services.script.model.*; -import com.google.api.services.script.Script; - -import android.Manifest; -import android.accounts.Account; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.text.method.ScrollingMovementMethod; -import android.view.View; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.Toast; - -import java.io.IOException; -import java.lang.StringBuilder; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import pub.devrel.easypermissions.AfterPermissionGranted; -import pub.devrel.easypermissions.EasyPermissions; - -/** - * This is the main (and only) activity of the add-on. It shows the user what - * text or cells were selected, the results of translation and provides some - * UI controls. - */ -public class MainActivity extends Activity - implements EasyPermissions.PermissionCallbacks { - - /** - * The script ID for the Apps Script the add-on will call - */ - private static final String SCRIPT_ID = "ENTER_YOUR_SCRIPT_ID_HERE"; - - // Constants - private static final String FUNCTION_GET_TEXT = "getTextAndTranslation"; - private static final String FUNCTION_TRANSLATE_TEXT = "translateText"; - private static final String FUNCTION_INSERT_TEXT = "insertText"; - static final int REQUEST_AUTHORIZATION = 1001; - static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002; - static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003; - private static final String[] SCOPES = { - "https://www.googleapis.com/auth/documents.currentonly", - "https://www.googleapis.com/auth/script.scriptapp", - "https://www.googleapis.com/auth/script.storage" - }; - static final String SAVED_ORIG_LANG = "origLangPosition"; - static final String SAVED_DEST_LANG = "destLangPosition"; - private static final int CALL_GET_TEXT = 0; - private static final int CALL_TRANSLATE_TEXT = 1; - private static final int CALL_REPLACE_TEXT = 2; - - /** - * An Apps Script API service object used to access the API, and related - * objects - */ - Script mService = null; - GoogleAccountCredential mCredential = null; - final HttpTransport mTransport = AndroidHttp.newCompatibleTransport(); - final JsonFactory mJsonFactory = JacksonFactory.getDefaultInstance(); - - // Layout components - private TextView mSelectedText; - private EditText mTranslationText; - private Button mReplaceButton; - private ProgressDialog mProgress; - - // Translation language controls - private String mOrigLang; - private String mDestLang; - private int mPrevOrigSpinnerPos; - private int mPrevDestSpinnerPos; - - // Other variables - private NetworkReceiver mReceiver; - private boolean mConnectionAvailable; - private int mLastFunctionCalled; - private String mState; - private Account mAccount; - - /** - * Create the main activity. - * @param savedInstanceState previously saved instance data - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - // Verify the add-on was called from the Docs editor. - if (! "com.google.android.apps.docs.editors.docs".equals( - getCallingPackage())) { - showErrorDialog(getString(R.string.unexpected_app) - + getCallingPackage()); - } - - // Acquire the doc/sheet state from the incoming intent. - // It's also possible to acquire the docId from the intent; - // that is not used in this example, however. - mState = getIntent().getStringExtra( - "com.google.android.apps.docs.addons.SessionState"); - mAccount = getIntent().getParcelableExtra( - "com.google.android.apps.docs.addons.Account"); - - // Load previously chosen language selections, if any - SharedPreferences settings = getPreferences(Context.MODE_PRIVATE); - mPrevOrigSpinnerPos = settings.getInt(SAVED_ORIG_LANG, 0); - mOrigLang = getLangIdFromSpinnerPosition(mPrevOrigSpinnerPos, false); - mPrevDestSpinnerPos = settings.getInt(SAVED_DEST_LANG, 0); - mDestLang = getLangIdFromSpinnerPosition(mPrevDestSpinnerPos, true); - - // Initialize layout objects - mProgress = new ProgressDialog(MainActivity.this); - - mSelectedText = (TextView) findViewById(R.id.selected_text); - mSelectedText.setVerticalScrollBarEnabled(true); - mSelectedText.setMovementMethod(new ScrollingMovementMethod()); - - mTranslationText = (EditText) findViewById(R.id.translated_text); - mTranslationText.setVerticalScrollBarEnabled(true); - mTranslationText.setMovementMethod(new ScrollingMovementMethod()); - - mReplaceButton = (Button) findViewById(R.id.replace_button); - - Spinner origLangSpinner = (Spinner) findViewById(R.id.origin_lang); - Spinner destLangSpinner = (Spinner) findViewById(R.id.dest_lang); - origLangSpinner.setSelection(mPrevOrigSpinnerPos); - destLangSpinner.setSelection(mPrevDestSpinnerPos); - origLangSpinner.setOnItemSelectedListener( - new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected( - AdapterView parent, View view, int pos, long id) { - if (pos != mPrevOrigSpinnerPos) { - mPrevOrigSpinnerPos = pos; - mOrigLang = getLangIdFromSpinnerPosition(pos, false); - SharedPreferences settings = - getPreferences(Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(SAVED_ORIG_LANG, pos); - editor.apply(); - translate(); - } - } - - @Override - public void onNothingSelected(AdapterView parent) {} - }); - destLangSpinner.setOnItemSelectedListener( - new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected( - AdapterView parent, View view, int pos, long id) { - if (pos != mPrevDestSpinnerPos) { - mPrevDestSpinnerPos = pos; - mDestLang = getLangIdFromSpinnerPosition(pos, true); - SharedPreferences settings = - getPreferences(Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(SAVED_DEST_LANG, pos); - editor.apply(); - translate(); - } - } - - @Override - public void onNothingSelected(AdapterView parent) {} - }); - - // Register BroadcastReceiver to track connection changes, and - // determine if a connection is initially available - IntentFilter filter = - new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mReceiver = new NetworkReceiver(); - MainActivity.this.registerReceiver(mReceiver, filter); - updateButtonEnableStatus(); - - // Start the add-on by attempting to retrieve the selected text from - // the Doc that fired the add-on - callAppsScriptTask(CALL_GET_TEXT); - } - - /** - * Extend the given HttpRequestInitializer (usually a Credentials object) - * with additional initialize() instructions. - * - * @param requestInitializer the initializer to copy and adjust; typically - * a Credential object - * @return an initializer with an extended read timeout - */ - private static HttpRequestInitializer setHttpTimeout( - final HttpRequestInitializer requestInitializer) { - return new HttpRequestInitializer() { - @Override - public void initialize(HttpRequest httpRequest) - throws java.io.IOException { - requestInitializer.initialize(httpRequest); - // This allows the API to call (and avoid timing out on) - // functions that take up to 30 seconds to complete. Note that - // the maximum allowed script run time is 6 minutes. - httpRequest.setReadTimeout(30000); - } - }; - } - - /** - * Clean up and destroy the main activity. - */ - @Override - public void onDestroy() { - super.onDestroy(); - // Unregister the connectivity broadcast receiver. - if (mReceiver != null) { - MainActivity.this.unregisterReceiver(mReceiver); - } - } - - /** - * Called when an activity launched here (specifically, AccountPicker - * and authorization) exits, giving you the requestCode you started it with, - * the resultCode it returned, and any additional data from it. - * @param requestCode code indicating which activity result is incoming - * @param resultCode code indicating the result of the incoming - * activity result - * @param data Intent (containing result data) returned by incoming - * activity result - */ - @Override - protected void onActivityResult( - int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch(requestCode) { - case REQUEST_GOOGLE_PLAY_SERVICES: - if (resultCode == RESULT_OK) { - callAppsScriptTask(mLastFunctionCalled); - } else { - showErrorDialog(getString(R.string.gps_required)); - } - break; - case REQUEST_AUTHORIZATION: - if (resultCode == RESULT_OK) { - callAppsScriptTask(mLastFunctionCalled); - } else { - showErrorDialog(getString(R.string.no_auth_provided)); - } - break; - } - } - - /** - * Call the API to execute an Apps Script function, after verifying - * all the preconditions are satisfied. The preconditions are: Google - * Play Services is installed, the device has a network connection, and - * the Execution API service and credentials have been created. - * @param functionToCall code indicating which function to call using - * the API - */ - private void callAppsScriptTask(int functionToCall) { - mLastFunctionCalled = functionToCall; - if (! isGooglePlayServicesAvailable()) { - toast(getString(R.string.gps_required)); - acquireGooglePlayServices(); - } else if (! mConnectionAvailable) { - toast(getString(R.string.no_network)); - } else if (! hasValidCredentials()) { - createCredentialsAndService(); - } else { - switch (functionToCall) { - case CALL_GET_TEXT: - new GetTextTask().execute(mOrigLang, mDestLang, false); - break; - case CALL_TRANSLATE_TEXT: - String originalText = mSelectedText.getText().toString(); - new TranslateTextTask().execute( - originalText, mOrigLang, mDestLang); - break; - case CALL_REPLACE_TEXT: - String translation = mTranslationText.getText().toString(); - new ReplaceTextTask().execute(translation); - break; - } - } - } - - /** - * Attempts to initialize credentials and service object (prior to a call - * to the API); uses the account provided by the calling app. This - * requires the GET_ACCOUNTS permission to be explicitly granted by the - * user; this will be requested here if it is not already granted. The - * AfterPermissionGranted annotation indicates that this function will be - * rerun automatically whenever the GET_ACCOUNTS permission is granted. - */ - @AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS) - private void createCredentialsAndService() { - if (EasyPermissions.hasPermissions( - MainActivity.this, Manifest.permission.GET_ACCOUNTS)) { - mCredential = GoogleAccountCredential.usingOAuth2( - getApplicationContext(), Arrays.asList(SCOPES)) - .setBackOff(new ExponentialBackOff()) - .setSelectedAccountName(mAccount.name); - mService = new com.google.api.services.script.Script.Builder( - mTransport, mJsonFactory, setHttpTimeout(mCredential)) - .setApplicationName(getString(R.string.app_name)) - .build(); - updateButtonEnableStatus(); - - // Callback to retry the API call with valid service/credentials - callAppsScriptTask(mLastFunctionCalled); - } else { - // Request the GET_ACCOUNTS permission via a user dialog - EasyPermissions.requestPermissions( - MainActivity.this, - getString(R.string.get_accounts_rationale), - REQUEST_PERMISSION_GET_ACCOUNTS, - Manifest.permission.GET_ACCOUNTS); - } - } - - /** - * Returns true if a valid service object has been created and instantiated - * with valid OAuth credentials; returns false otherwise. - * @return true if the service and credentials are valid; false otherwise. - */ - private boolean hasValidCredentials() { - return mService != null - && mCredential != null - && mCredential.getSelectedAccountName() != null; - } - - /** - * Respond to requests for permissions at runtime for SDK 23 and above. - * @param requestCode The request code passed in - * requestPermissions(android.app.Activity, String, int, String[]) - * @param permissions The requested permissions. Never null. - * @param grantResults The grant results for the corresponding permissions - * which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null. - */ - @Override - public void onRequestPermissionsResult(int requestCode, - @NonNull String[] permissions, - @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - EasyPermissions.onRequestPermissionsResult( - requestCode, permissions, grantResults, MainActivity.this); - } - - /** - * Callback for when a permission is granted using the EasyPermissions - * library. - * @param requestCode The request code associated with the requested - * permission - * @param list The requested permission list. Never null. - */ - @Override - public void onPermissionsGranted(int requestCode, List list) { - // Do nothing. - } - - /** - * Callback for when a permission is denied using the EasyPermissions - * library. Displays status message and disables functionality that - * would require that permission. - * @param requestCode The request code associated with the requested - * permission - * @param list The requested permission list. Never null. - */ - @Override - public void onPermissionsDenied(int requestCode, List list) { - toast(getString(R.string.get_accounts_denied_message)); - updateButtonEnableStatus(); - } - - /** - * Given the position of one of the language spinners, return the language - * id corresponding to that position. - * @param pos spinner position - * @param omitAutoDetect true if the spinner does not include 'Auto-detect' - * as the first option - * @return String two-letter language id - */ - private String getLangIdFromSpinnerPosition(int pos, boolean omitAutoDetect) { - String id; - if (omitAutoDetect) { - pos++; - } - switch (pos) { - case 0: id = ""; break; // Auto-detect (input language only) - case 1: id = "ar"; break; // Arabic - case 2: id = "zh-CN"; break; // Chinese (Simplified) - case 3: id = "en"; break; // English - case 4: id = "fr"; break; // French - case 5: id = "de"; break; // German - case 6: id = "hi"; break; // Hindi - case 7: id = "ja"; break; // Japanese - case 8: id = "pt"; break; // Portuguese - case 9: id = "es"; break; // Spanish - default: id = "en"; break; - } - return id; - } - - /** - * Call the API to translate the selected text. - */ - private void translate() { - String originalText = mSelectedText.getText().toString(); - if (originalText.length() != 0) { - callAppsScriptTask(CALL_TRANSLATE_TEXT); - } - } - - /** - * Call the API to replace the translated text back to the original - * document. - * @param v The button's View context - */ - public void replace(View v) { - String translation = mTranslationText.getText().toString(); - if (translation.length() != 0) { - callAppsScriptTask(CALL_REPLACE_TEXT); - } - } - - /** - * Cancel the add-on and return without action to the calling app. - * @param v The button's View context - */ - public void cancel(View v) { - finishWithState(Activity.RESULT_CANCELED); - } - - /** - * End the add-on and return to the calling application. - * @param state result code for add-on: one of Activity.RESULT_CANCELED or - * Activity.RESULT_OK - */ - private void finishWithState(int state) { - dismissProgressDialog(); - setResult(state); - finish(); - } - - /** - * Display a short toast message. - * @param message text to display - */ - private void toast(String message) { - Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); - } - - /** - * Checks whether the device currently has a network connection. - * @return true if the device has a network connection, false otherwise - */ - private boolean isDeviceOnline() { - ConnectivityManager connMgr = - (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); - return (networkInfo != null && networkInfo.isConnected()); - } - - /** - * Check that Google Play services APK is installed and up to date. - * @return true if Google Play Services is available and up to - * date on this device; false otherwise. - */ - private boolean isGooglePlayServicesAvailable() { - GoogleApiAvailability apiAvailability = - GoogleApiAvailability.getInstance(); - final int connectionStatusCode = - apiAvailability.isGooglePlayServicesAvailable(MainActivity.this); - return connectionStatusCode == ConnectionResult.SUCCESS; - } - - /** - * Attempt to resolve a missing, out-of-date, invalid or disabled Google - * Play Services installation via a user dialog, if possible. - */ - private void acquireGooglePlayServices() { - GoogleApiAvailability apiAvailability = - GoogleApiAvailability.getInstance(); - final int connectionStatusCode = - apiAvailability.isGooglePlayServicesAvailable(MainActivity.this); - if (apiAvailability.isUserResolvableError(connectionStatusCode)) { - showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode); - } - } - /** - * Display an error dialog showing that Google Play Services is missing - * or out of date. - * @param connectionStatusCode code describing the presence (or lack of) - * Google Play Services on this device - */ - private void showGooglePlayServicesAvailabilityErrorDialog( - final int connectionStatusCode) { - Dialog dialog = - GoogleApiAvailability.getInstance().getErrorDialog( - MainActivity.this, - connectionStatusCode, - REQUEST_GOOGLE_PLAY_SERVICES); - dialog.show(); - } - - /** - * Check the current connectivity status of the device and enable/disable - * the highlight buttons if the device is online/offline, respectively. - */ - private void updateButtonEnableStatus() { - mConnectionAvailable = isDeviceOnline(); - boolean enable = mConnectionAvailable && hasValidCredentials(); - mReplaceButton.setEnabled(enable); - } - - /** - * Show a dialog with an error message, with a button to cancel out of - * the add-on. - * @param errorMessage Error message to display - */ - protected void showErrorDialog(String errorMessage) { - AlertDialog.Builder alertDialogBuilder = - new AlertDialog.Builder(MainActivity.this); - alertDialogBuilder.setTitle(getString(R.string.error_occurred)); - alertDialogBuilder - .setMessage(errorMessage) - .setCancelable(false) - .setNegativeButton( - getString(R.string.exit_button), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - finishWithState(Activity.RESULT_CANCELED); - } - }); - dismissProgressDialog(); - AlertDialog alertDialog = alertDialogBuilder.create(); - alertDialog.show(); - } - - /** - * Dismiss the ProgressDialog, if it is visible. - */ - public void dismissProgressDialog() { - if (mProgress != null && mProgress.isShowing()) { - Context context = - ((ContextWrapper) mProgress.getContext()).getBaseContext(); - // Dismiss only if launching activity hasn't been finished or - // destroyed - if(! (context instanceof Activity && - ((Activity)context).isFinishing() || - ((Activity)context).isDestroyed())) { - mProgress.dismiss(); - } - } - } - - /** - * This BroadcastReceiver intercepts the - * android.net.ConnectivityManager.CONNECTIVITY_ACTION, which indicates a - * connection change. This is used to determine if the API can be called. - */ - public class NetworkReceiver extends BroadcastReceiver { - /** - * Responds to a connection change, recording whether a connection is - * available. - * @param context The Context in which the receiver is running - * @param intent The Intent being received - */ - @Override - public void onReceive(Context context, Intent intent) { - // Checks the network connection. Based on the - // result, enables/disables flag to allow API calls and - // enables/disables buttons. - updateButtonEnableStatus(); - if (!mConnectionAvailable) { - toast(getString(R.string.no_network)); - } - } - } - - /** - * Abstract class for handling Execution API calls. Typically a subclass of - * this is created for each Apps Script function that will be called. - * Placing the API calls in their own task ensures the UI stays responsive. - */ - public abstract class CallApiTask extends AsyncTask { - - private Exception mLastError = null; - protected String mFunctionName; - - /** - * Background task to call Apps Script API. - * @param params Object parameters; used as parameters for that - * function, in the given order - * @return an object returned by the API; may be null - */ - @Override - protected Object doInBackground(Object... params) { - try { - return executeCall(mFunctionName, Arrays.asList(params)); - } catch (Exception e) { - mLastError = e; - cancel(true); - return null; - } - } - - /** - * Handle cancel requests -- specifically, those caused by exceptions - * raised when attempting to call the API. - */ - @Override - protected void onCancelled() { - mProgress.hide(); - if (mLastError != null) { - if (mLastError instanceof GooglePlayServicesAvailabilityIOException) { - showGooglePlayServicesAvailabilityErrorDialog( - ((GooglePlayServicesAvailabilityIOException) mLastError).getConnectionStatusCode()); - } else if (mLastError instanceof UserRecoverableAuthIOException) { - startActivityForResult( - ((UserRecoverableAuthIOException) mLastError).getIntent(), - MainActivity.REQUEST_AUTHORIZATION); - } else { - showErrorDialog(mLastError.toString()); - } - } - } - - /** - * Interpret an error response returned by the API and return a String - * summary. The summary will include the general error message and - * (in most cases) a stack trace. - * @param op the Operation returning an error response - * @return summary of error response, or null if Operation returned no - * error - */ - protected String getScriptError(Operation op) { - if (op.getError() == null) { - return null; - } - - // Extract the first (and only) set of error details and cast as a - // Map. The values of this map are the script's 'errorMessage' and - // 'errorType', and an array of stack trace elements (which also - // need to be cast as Maps). - Map detail = op.getError().getDetails().get(0); - List> stacktrace = - (List>)detail.get("scriptStackTraceElements"); - - StringBuilder sb = - new StringBuilder(getString(R.string.script_error)); - sb.append(detail.get("errorMessage")); - - if (stacktrace != null) { - // There may not be a stacktrace if the script didn't start - // executing. - sb.append(getString(R.string.script_error_trace)); - for (Map elem : stacktrace) { - sb.append("\n "); - sb.append(elem.get("function")); - sb.append(":"); - sb.append(elem.get("lineNumber")); - } - } - sb.append("\n"); - return sb.toString(); - } - - /** - * Given a script function and a list of parameter objects, create a - * request and run it with the API. - * @param functionName script function name to call - * @param params parameters needed by that function; may be null - * @return Object returned from a successful execution; may be null - * @throws IOException - * @throws GoogleAuthException - */ - protected Object executeCall(String functionName, List params) - throws IOException, GoogleAuthException { - // Create execution request. - ExecutionRequest request = new ExecutionRequest() - .setFunction(functionName) - .setSessionState(mState); - if (params != null) { - request.setParameters(params); - } - - // Call the API and return the results (as an Operation object). - Operation op = mService.scripts().run(SCRIPT_ID, request).execute(); - - // If the response from the API contains an error, throw an - // exception to display it. - if (op.getError() != null) { - throw new IOException(getScriptError(op)); - } - - // Return null if the API didn't yield a result. - if (op.getResponse() == null || - op.getResponse().get("result") == null) { - return null; - } - - return op.getResponse().get("result"); - } - } - - /** - * An asynchronous task that handles the Apps Script API call to get - * selected text data, and the translation of it to the previously chosen - * destination language (or the default destination language). - */ - public class GetTextTask extends CallApiTask { - /** - * Clear the display and show the progress bar prior to calling the - * API. - */ - @Override - protected void onPreExecute() { - mFunctionName = FUNCTION_GET_TEXT; - mProgress.setMessage(getString(R.string.retrieve_status)); - mProgress.show(); - } - - /** - * Take the text output and display it. If no data is returned, update - * the status bar accordingly. - * @param scriptResult object returned by the script function; may be - * null - */ - @Override - protected void onPostExecute(Object scriptResult) { - mProgress.hide(); - if (scriptResult != null) { - // Place the original text and default translation into the UI. - Map data = (Map) scriptResult; - mSelectedText.setText(data.get("text")); - mTranslationText.setText(data.get("translation")); - } - } - } - - /** - * An asynchronous task that handles the Apps Script API call to - * translate text data. - */ - public class TranslateTextTask extends CallApiTask { - /** - * Clear the display and show the progress bar prior to calling the - * API. - */ - @Override - protected void onPreExecute() { - mFunctionName = FUNCTION_TRANSLATE_TEXT; - mProgress.setMessage(getString(R.string.translate_status)); - mProgress.show(); - } - - /** - * Take the text output and display it. If no data is returned, update - * the status bar accordingly. - * @param scriptResult object returned by the script function; may be - * null - */ - @Override - protected void onPostExecute(Object scriptResult) { - mProgress.hide(); - if (scriptResult != null) { - String data = (String) scriptResult; - mTranslationText.setText(data); - } - } - } - - /** - * An asynchronous task that handles the Apps Script API call to send - * (translated) text back into the document, replacing the previous - * selection. - */ - public class ReplaceTextTask extends CallApiTask { - /** - * Show the progress bar prior to calling the API. - */ - @Override - protected void onPreExecute() { - mFunctionName = FUNCTION_INSERT_TEXT; - mProgress.setMessage(getString(R.string.replace_status)); - mProgress.show(); - } - - /** - * After finishing the API call, clear the progress bar and close - * the add-on. - * @param scriptResult object returned by the script function; should - * always be null for this script function - */ - @Override - protected void onPostExecute(Object scriptResult) { - mProgress.hide(); - finishWithState(Activity.RESULT_OK); - } - } -} diff --git a/android/mobile-translate/app/src/main/res/layout-land/activity_main.xml b/android/mobile-translate/app/src/main/res/layout-land/activity_main.xml deleted file mode 100644 index 80647ff0d..000000000 --- a/android/mobile-translate/app/src/main/res/layout-land/activity_main.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/mobile-translate/app/src/main/res/layout/activity_main.xml b/android/mobile-translate/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index caf9e4548..000000000 --- a/android/mobile-translate/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/mobile-translate/app/src/main/res/layout/buttons.xml b/android/mobile-translate/app/src/main/res/layout/buttons.xml deleted file mode 100644 index 6b336e14f..000000000 --- a/android/mobile-translate/app/src/main/res/layout/buttons.xml +++ /dev/null @@ -1,28 +0,0 @@ - -