commit 64692ff14da77e72cf4e34b7e573de1e30fc60da Author: bim dsnake@protonmail.com Date: Tue Sep 8 13:01:19 2020 -0400
First stab at modularizing shared code between the app and app mini projects --- app-mini/build.gradle | 6 +- app-mini/src/debug/AndroidManifest.xml | 2 +- app-mini/src/main/AndroidManifest.xml | 29 +- .../integration/android/IntentIntegrator.java | 506 ----------- .../org/torproject/android/mini/MainConstants.java | 15 - .../torproject/android/mini/MiniMainActivity.java | 995 +++++++++------------ .../torproject/android/mini/OnBootReceiver.java | 39 - .../org/torproject/android/mini/OrbotMiniApp.java | 79 +- .../android/mini/settings/Languages.java | 228 ----- .../android/mini/settings/LocaleHelper.java | 86 -- .../android/mini/settings/SettingsPreferences.java | 72 -- .../mini/ui/NoPersonalizedLearningEditText.java | 13 - .../android/mini/ui/Rotate3dAnimation.java | 76 -- .../mini/ui/onboarding/OnboardingActivity.java | 3 +- .../src/main/res/layout/content_app_config.xml | 1 - app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 4 +- .../zxing/integration/android/IntentResult.java | 95 -- .../org/torproject/android/OnBootReceiver.java | 42 - .../main/java/org/torproject/android/OrbotApp.java | 6 +- .../org/torproject/android/OrbotMainActivity.java | 12 +- .../org/torproject/android/settings/Languages.java | 195 ---- .../torproject/android/settings/LocaleHelper.java | 80 -- .../android/settings/SettingsPreferences.java | 68 -- .../android/ui/NoPersonalizedLearningEditText.java | 13 - .../torproject/android/ui/Rotate3dAnimation.java | 76 -- .../ui/hiddenservices/ClientCookiesActivity.java | 2 +- .../ui/hiddenservices/HiddenServicesActivity.java | 2 +- .../ui/hiddenservices/backup/BackupUtils.java | 2 +- .../dialogs/SelectCookieBackupDialog.java | 2 +- .../dialogs/SelectHSBackupDialog.java | 2 +- .../ui/hiddenservices/storage/ExternalStorage.java | 28 - .../ui/onboarding/BridgeWizardActivity.java | 4 +- .../android/ui/onboarding/OnboardingActivity.java | 2 +- .../res/layout/layout_add_client_cookie_dialog.xml | 4 +- app/src/main/res/layout/layout_hs_data_dialog.xml | 6 +- appcore/.gitignore | 1 + appcore/build.gradle | 41 + appcore/consumer-rules.pro | 0 appcore/proguard-rules.pro | 21 + .../android/core/ExampleInstrumentedTest.kt | 24 + appcore/src/main/AndroidManifest.xml | 3 + .../org/torproject/android/core/ExternalStorage.kt | 15 + .../java/org/torproject/android/core/Languages.kt | 174 ++++ .../org/torproject/android/core/LocaleHelper.kt | 55 ++ .../org/torproject/android/core/OnBootReceiver.kt | 31 + .../core/ui/NoPersonalizedLearningEditText.kt | 12 + .../android/core/ui/Rotate3dAnimation.kt | 48 + .../android/core/ui/SettingsPreferencesActivity.kt | 65 ++ .../org/torproject/android/core/ExampleUnitTest.kt | 17 + build.gradle | 4 + intentintegrator/.gitignore | 1 + intentintegrator/build.gradle | 30 + intentintegrator/consumer-rules.pro | 0 intentintegrator/proguard-rules.pro | 21 + intentintegrator/src/main/AndroidManifest.xml | 5 + .../integration/android/IntentIntegrator.java | 0 .../zxing/integration/android/IntentResult.java | 0 settings.gradle | 2 + 59 files changed, 1017 insertions(+), 2350 deletions(-)
diff --git a/app-mini/build.gradle b/app-mini/build.gradle index 140011cc..6cf3d7f3 100644 --- a/app-mini/build.gradle +++ b/app-mini/build.gradle @@ -109,8 +109,12 @@ dependencies { implementation project(':orbotservice') implementation 'com.github.apl-devs:appintro:v4.2.2' implementation 'androidx.palette:palette:1.0.0' - implementation 'com.github.javiersantos:AppUpdater:2.7' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation project(path: ':appcore') + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation 'com.google.android.material:material:1.2.1' + implementation project(path: ':intentintegrator') androidTestImplementation "tools.fastlane:screengrab:1.2.0" }
diff --git a/app-mini/src/debug/AndroidManifest.xml b/app-mini/src/debug/AndroidManifest.xml index a04afa83..a06b3fe8 100644 --- a/app-mini/src/debug/AndroidManifest.xml +++ b/app-mini/src/debug/AndroidManifest.xml @@ -72,7 +72,7 @@ android:exported="false" android:label="@string/app_name" /> <activity - android:name=".settings.SettingsPreferences" + android:name=".settings.SettingsPreferencesActivity" android:label="@string/app_name" /> <activity android:name=".ui.AppManagerActivity" diff --git a/app-mini/src/main/AndroidManifest.xml b/app-mini/src/main/AndroidManifest.xml index 6e73081a..dda8d0bf 100644 --- a/app-mini/src/main/AndroidManifest.xml +++ b/app-mini/src/main/AndroidManifest.xml @@ -51,7 +51,7 @@ android:stateNotNeeded="true" android:theme="@android:style/Theme.Translucent" /> <activity - android:name=".settings.SettingsPreferences" + android:name="org.torproject.android.core.ui.SettingsPreferencesActivity" android:label="@string/app_name" /> <activity android:name=".ui.AppManagerActivity" @@ -61,36 +61,11 @@ <activity android:name=".ui.onboarding.OnboardingActivity" />
- <receiver - android:name=".OnBootReceiver" - android:enabled="true" - android:exported="true"> - <intent-filter> - <action android:name="android.intent.action.BOOT_COMPLETED" /> - - <category android:name="android.intent.category.HOME" /> - </intent-filter> - <intent-filter> - <action android:name="android.intent.action.QUICKBOOT_POWERON" /> - - <category android:name="android.intent.category.HOME" /> - </intent-filter> - <intent-filter> - <action android:name="android.intent.action.MEDIA_MOUNTED" /> - - <category android:name="android.intent.category.HOME" /> - </intent-filter> - </receiver> - <service android:name="org.torproject.android.service.OrbotService" android:enabled="true" android:permission="android.permission.BIND_VPN_SERVICE" - android:stopWithTask="false" /> - <service - android:name="org.torproject.android.service.vpn.TorVpnService" - android:enabled="true" - android:permission="android.permission.BIND_VPN_SERVICE"> + android:stopWithTask="false"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> diff --git a/app-mini/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java b/app-mini/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java deleted file mode 100644 index d5628e87..00000000 --- a/app-mini/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.integration.android; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; - -/** - * <p>A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple - * way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the - * project's source code.</p> - * - * <h2>Initiating a barcode scan</h2> - * - * <p>To integrate, create an instance of {@code IntentIntegrator} and call {@link #initiateScan()} and wait - * for the result in your app.</p> - * - * <p>It does require that the Barcode Scanner (or work-alike) application is installed. The - * {@link #initiateScan()} method will prompt the user to download the application, if needed.</p> - * - * <p>There are a few steps to using this integration. First, your {@link Activity} must implement - * the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p> - * - * <pre>{@code - * public void onActivityResult(int requestCode, int resultCode, Intent intent) { - * IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); - * if (scanResult != null) { - * // handle scan result - * } - * // else continue with any other code you need in the method - * ... - * } - * }</pre> - * - * <p>This is where you will handle a scan result.</p> - * - * <p>Second, just call this in response to a user action somewhere to begin the scan process:</p> - * - * <pre>{@code - * IntentIntegrator integrator = new IntentIntegrator(yourActivity); - * integrator.initiateScan(); - * }</pre> - * - * <p>Note that {@link #initiateScan()} returns an {@link AlertDialog} which is non-null if the - * user was prompted to download the application. This lets the calling app potentially manage the dialog. - * In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()} - * method.</p> - * - * <p>You can use {@link #setTitle(String)} to customize the title of this download prompt dialog (or, use - * {@link #setTitleByID(int)} to set the title by string resource ID.) Likewise, the prompt message, and - * yes/no button labels can be changed.</p> - * - * <p>Finally, you can use {@link #addExtra(String, Object)} to add more parameters to the Intent used - * to invoke the scanner. This can be used to set additional options not directly exposed by this - * simplified API.</p> - * - * <p>By default, this will only allow applications that are known to respond to this intent correctly - * do so. The apps that are allowed to response can be set with {@link #setTargetApplications(List)}. - * For example, set to {@link #TARGET_BARCODE_SCANNER_ONLY} to only target the Barcode Scanner app itself.</p> - * - * <h2>Sharing text via barcode</h2> - * - * <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(CharSequence)}.</p> - * - * <p>Some code, particularly download integration, was contributed from the Anobiit application.</p> - * - * <h2>Enabling experimental barcode formats</h2> - * - * <p>Some formats are not enabled by default even when scanning with {@link #ALL_CODE_TYPES}, such as - * PDF417. Use {@link #initiateScan(java.util.Collection)} with - * a collection containing the names of formats to scan for explicitly, like "PDF_417", to use such - * formats.</p> - * - * @author Sean Owen - * @author Fred Lin - * @author Isaac Potoczny-Jones - * @author Brad Drehmer - * @author gcstang - */ -public class IntentIntegrator { - - public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits - private static final String TAG = IntentIntegrator.class.getSimpleName(); - - public static final String DEFAULT_TITLE = "Install Barcode Scanner?"; - public static final String DEFAULT_MESSAGE = - "This application requires Barcode Scanner. Would you like to install it?"; - public static final String DEFAULT_YES = "Yes"; - public static final String DEFAULT_NO = "No"; - - private static final String BS_PACKAGE = "com.google.zxing.client.android"; - private static final String BSPLUS_PACKAGE = "com.srowen.bs.android"; - - // supported barcode formats - public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14"); - public static final Collection<String> ONE_D_CODE_TYPES = - list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128", - "ITF", "RSS_14", "RSS_EXPANDED"); - public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE"); - public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX"); - - public static final Collection<String> ALL_CODE_TYPES = null; - - public static final List<String> TARGET_BARCODE_SCANNER_ONLY = Collections.singletonList(BS_PACKAGE); - public static final List<String> TARGET_ALL_KNOWN = list( - BSPLUS_PACKAGE, // Barcode Scanner+ - BSPLUS_PACKAGE + ".simple", // Barcode Scanner+ Simple - BS_PACKAGE // Barcode Scanner - // What else supports this intent? - ); - - private final Activity activity; - private final Fragment fragment; - - private String title; - private String message; - private String buttonYes; - private String buttonNo; - private List<String> targetApplications; - private final Map<String,Object> moreExtras = new HashMap<String,Object>(3); - - /** - * @param activity {@link Activity} invoking the integration - */ - public IntentIntegrator(Activity activity) { - this.activity = activity; - this.fragment = null; - initializeConfiguration(); - } - - /** - * @param fragment {@link Fragment} invoking the integration. - * {@link #startActivityForResult(Intent, int)} will be called on the {@link Fragment} instead - * of an {@link Activity} - */ - public IntentIntegrator(Fragment fragment) { - this.activity = fragment.getActivity(); - this.fragment = fragment; - initializeConfiguration(); - } - - private void initializeConfiguration() { - title = DEFAULT_TITLE; - message = DEFAULT_MESSAGE; - buttonYes = DEFAULT_YES; - buttonNo = DEFAULT_NO; - targetApplications = TARGET_ALL_KNOWN; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setTitleByID(int titleID) { - title = activity.getString(titleID); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public void setMessageByID(int messageID) { - message = activity.getString(messageID); - } - - public String getButtonYes() { - return buttonYes; - } - - public void setButtonYes(String buttonYes) { - this.buttonYes = buttonYes; - } - - public void setButtonYesByID(int buttonYesID) { - buttonYes = activity.getString(buttonYesID); - } - - public String getButtonNo() { - return buttonNo; - } - - public void setButtonNo(String buttonNo) { - this.buttonNo = buttonNo; - } - - public void setButtonNoByID(int buttonNoID) { - buttonNo = activity.getString(buttonNoID); - } - - public Collection<String> getTargetApplications() { - return targetApplications; - } - - public final void setTargetApplications(List<String> targetApplications) { - if (targetApplications.isEmpty()) { - throw new IllegalArgumentException("No target applications"); - } - this.targetApplications = targetApplications; - } - - public void setSingleTargetApplication(String targetApplication) { - this.targetApplications = Collections.singletonList(targetApplication); - } - - public Map<String,?> getMoreExtras() { - return moreExtras; - } - - public final void addExtra(String key, Object value) { - moreExtras.put(key, value); - } - - /** - * Initiates a scan for all known barcode types with the default camera. - * - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise. - */ - public final AlertDialog initiateScan() { - return initiateScan(ALL_CODE_TYPES, -1); - } - - /** - * Initiates a scan for all known barcode types with the specified camera. - * - * @param cameraId camera ID of the camera to use. A negative value means "no preference". - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise. - */ - public final AlertDialog initiateScan(int cameraId) { - return initiateScan(ALL_CODE_TYPES, cameraId); - } - - /** - * Initiates a scan, using the default camera, only for a certain set of barcode types, given as strings corresponding - * to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants - * like {@link #PRODUCT_CODE_TYPES} for example. - * - * @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise. - */ - public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats) { - return initiateScan(desiredBarcodeFormats, -1); - } - - /** - * Initiates a scan, using the specified camera, only for a certain set of barcode types, given as strings corresponding - * to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants - * like {@link #PRODUCT_CODE_TYPES} for example. - * - * @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for - * @param cameraId camera ID of the camera to use. A negative value means "no preference". - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise - */ - public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats, int cameraId) { - Intent intentScan = new Intent(BS_PACKAGE + ".SCAN"); - intentScan.addCategory(Intent.CATEGORY_DEFAULT); - - // check which types of codes to scan for - if (desiredBarcodeFormats != null) { - // set the desired barcode types - StringBuilder joinedByComma = new StringBuilder(); - for (String format : desiredBarcodeFormats) { - if (joinedByComma.length() > 0) { - joinedByComma.append(','); - } - joinedByComma.append(format); - } - intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString()); - } - - // check requested camera ID - if (cameraId >= 0) { - intentScan.putExtra("SCAN_CAMERA_ID", cameraId); - } - - String targetAppPackage = findTargetAppPackage(intentScan); - if (targetAppPackage == null) { - return showDownloadDialog(); - } - intentScan.setPackage(targetAppPackage); - intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); - attachMoreExtras(intentScan); - startActivityForResult(intentScan, REQUEST_CODE); - return null; - } - - /** - * Start an activity. This method is defined to allow different methods of activity starting for - * newer versions of Android and for compatibility library. - * - * @param intent Intent to start. - * @param code Request code for the activity - * @see android.app.Activity#startActivityForResult(Intent, int) - * @see android.app.Fragment#startActivityForResult(Intent, int) - */ - protected void startActivityForResult(Intent intent, int code) { - if (fragment == null) { - activity.startActivityForResult(intent, code); - } else { - fragment.startActivityForResult(intent, code); - } - } - - private String findTargetAppPackage(Intent intent) { - PackageManager pm = activity.getPackageManager(); - List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - if (availableApps != null) { - for (String targetApp : targetApplications) { - if (contains(availableApps, targetApp)) { - return targetApp; - } - } - } - return null; - } - - private static boolean contains(Iterable<ResolveInfo> availableApps, String targetApp) { - for (ResolveInfo availableApp : availableApps) { - String packageName = availableApp.activityInfo.packageName; - if (targetApp.equals(packageName)) { - return true; - } - } - return false; - } - - private AlertDialog showDownloadDialog() { - AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity); - downloadDialog.setTitle(title); - downloadDialog.setMessage(message); - downloadDialog.setPositiveButton(buttonYes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - String packageName; - if (targetApplications.contains(BS_PACKAGE)) { - // Prefer to suggest download of BS if it's anywhere in the list - packageName = BS_PACKAGE; - } else { - // Otherwise, first option: - packageName = targetApplications.get(0); - } - Uri uri = Uri.parse("market://details?id=" + packageName); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - try { - if (fragment == null) { - activity.startActivity(intent); - } else { - fragment.startActivity(intent); - } - } catch (ActivityNotFoundException anfe) { - // Hmm, market is not installed - Log.w(TAG, "Google Play is not installed; cannot install " + packageName); - } - } - }); - downloadDialog.setNegativeButton(buttonNo, null); - downloadDialog.setCancelable(true); - return downloadDialog.show(); - } - - - /** - * <p>Call this from your {@link Activity}'s - * {@link Activity#onActivityResult(int, int, Intent)} method.</p> - * - * @param requestCode request code from {@code onActivityResult()} - * @param resultCode result code from {@code onActivityResult()} - * @param intent {@link Intent} from {@code onActivityResult()} - * @return null if the event handled here was not related to this class, or - * else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning, - * the fields will be null. - */ - public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) { - if (requestCode == REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK) { - String contents = intent.getStringExtra("SCAN_RESULT"); - String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT"); - byte[] rawBytes = intent.getByteArrayExtra("SCAN_RESULT_BYTES"); - int intentOrientation = intent.getIntExtra("SCAN_RESULT_ORIENTATION", Integer.MIN_VALUE); - Integer orientation = intentOrientation == Integer.MIN_VALUE ? null : intentOrientation; - String errorCorrectionLevel = intent.getStringExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL"); - return new IntentResult(contents, - formatName, - rawBytes, - orientation, - errorCorrectionLevel); - } - return new IntentResult(); - } - return null; - } - - - /** - * Defaults to type "TEXT_TYPE". - * - * @param text the text string to encode as a barcode - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise - * @see #shareText(CharSequence, CharSequence) - */ - public final AlertDialog shareText(CharSequence text) { - return shareText(text, "TEXT_TYPE"); - } - - /** - * Shares the given text by encoding it as a barcode, such that another user can - * scan the text off the screen of the device. - * - * @param text the text string to encode as a barcode - * @param type type of data to encode. See {@code com.google.zxing.client.android.Contents.Type} constants. - * @return the {@link AlertDialog} that was shown to the user prompting them to download the app - * if a prompt was needed, or null otherwise - */ - public final AlertDialog shareText(CharSequence text, CharSequence type) { - Intent intent = new Intent(); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setAction(BS_PACKAGE + ".ENCODE"); - intent.putExtra("ENCODE_TYPE", type); - intent.putExtra("ENCODE_DATA", text); - String targetAppPackage = findTargetAppPackage(intent); - if (targetAppPackage == null) { - return showDownloadDialog(); - } - intent.setPackage(targetAppPackage); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); - attachMoreExtras(intent); - if (fragment == null) { - activity.startActivity(intent); - } else { - fragment.startActivity(intent); - } - return null; - } - - private static List<String> list(String... values) { - return Collections.unmodifiableList(Arrays.asList(values)); - } - - private void attachMoreExtras(Intent intent) { - for (Map.Entry<String,Object> entry : moreExtras.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - // Kind of hacky - if (value instanceof Integer) { - intent.putExtra(key, (Integer) value); - } else if (value instanceof Long) { - intent.putExtra(key, (Long) value); - } else if (value instanceof Boolean) { - intent.putExtra(key, (Boolean) value); - } else if (value instanceof Double) { - intent.putExtra(key, (Double) value); - } else if (value instanceof Float) { - intent.putExtra(key, (Float) value); - } else if (value instanceof Bundle) { - intent.putExtra(key, (Bundle) value); - } else { - intent.putExtra(key, value.toString()); - } - } - } - -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/MainConstants.java b/app-mini/src/main/java/org/torproject/android/mini/MainConstants.java deleted file mode 100644 index b4d64147..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/MainConstants.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.torproject.android.mini; - -public interface MainConstants { - - //EXIT COUNTRY CODES - String[] COUNTRY_CODES = {"DE","AT","SE","CH","IS","CA","US","ES","FR","BG","PL","AU","BR","CZ","DK","FI","GB","HU","NL","JP","RO","RU","SG","SK"}; - - //path to check Tor against - String URL_TOR_CHECK = "https://check.torproject.org"; - - String URL_TOR_BRIDGES = "https://bridges.torproject.org/bridges?transport="; - - int RESULT_CLOSE_ALL = 0; - -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/MiniMainActivity.java b/app-mini/src/main/java/org/torproject/android/mini/MiniMainActivity.java index 4566031d..26b17fdf 100644 --- a/app-mini/src/main/java/org/torproject/android/mini/MiniMainActivity.java +++ b/app-mini/src/main/java/org/torproject/android/mini/MiniMainActivity.java @@ -3,8 +3,6 @@
package org.torproject.android.mini;
-import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -39,6 +37,7 @@ import android.view.animation.AccelerateInterpolator; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; + import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.Toolbar; @@ -47,15 +46,17 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.palette.graphics.Palette; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; + import org.json.JSONArray; -import org.torproject.android.mini.settings.Languages; -import org.torproject.android.mini.settings.LocaleHelper; -import org.torproject.android.mini.settings.SettingsPreferences; +import org.torproject.android.core.Languages; +import org.torproject.android.core.LocaleHelper; +import org.torproject.android.core.ui.Rotate3dAnimation; +import org.torproject.android.core.ui.SettingsPreferencesActivity; import org.torproject.android.mini.ui.AppConfigActivity; import org.torproject.android.mini.ui.AppManagerActivity; -import org.torproject.android.mini.ui.Rotate3dAnimation; import org.torproject.android.mini.ui.onboarding.OnboardingActivity; import org.torproject.android.service.OrbotConstants; import org.torproject.android.service.OrbotService; @@ -73,108 +74,83 @@ import java.util.ArrayList; import java.util.Locale; import java.util.StringTokenizer;
-import static org.torproject.android.mini.MainConstants.RESULT_CLOSE_ALL; import static org.torproject.android.service.vpn.VpnPrefs.PREFS_KEY_TORIFIED;
-public class MiniMainActivity extends AppCompatActivity - implements OrbotConstants, OnLongClickListener { +public class MiniMainActivity extends AppCompatActivity implements OrbotConstants, OnLongClickListener {
+ private static final int RESULT_CLOSE_ALL = 0; + private final static int REQUEST_VPN = 8888; + private final static int REQUEST_SETTINGS = 0x9874; + private final static int REQUEST_VPN_APPS_SELECT = 8889; + private final static int LOG_DRAWER_GRAVITY = Gravity.END; + // message types for mStatusUpdateHandler + private final static int STATUS_UPDATE = 1; + private static final int MESSAGE_TRAFFIC_COUNT = 2; + private static final int MESSAGE_PORTS = 3; + private static final float ROTATE_FROM = 0.0f; + private static final float ROTATE_TO = 360.0f * 4f;// 3.141592654f * 32.0f; + ArrayList<String> pkgIds = new ArrayList<>(); + AlertDialog aDialog = null; /* Useful UI bits */ // private TextView lblStatus = null; //the main text display widget private ImageView imgStatus = null; //the main touchable image for activating Orbot - private TextView downloadText = null; private TextView uploadText = null; private TextView mTxtOrbotLog = null; - - private SwitchCompat mBtnVPN = null; - - private DrawerLayout mDrawer; - + private SwitchCompat mBtnVPN = null; + private DrawerLayout mDrawer; /* Some tracking bits */ private String torStatus = null; //latest status reported from the tor service private Intent lastStatusIntent; // the last ACTION_STATUS Intent received - private SharedPreferences mPrefs = null; - private boolean autoStartFromIntent = false; - - private final static int REQUEST_VPN = 8888; - private final static int REQUEST_SETTINGS = 0x9874; - private final static int REQUEST_VPN_APPS_SELECT = 8889; - - private final static int LOG_DRAWER_GRAVITY = Gravity.END; - - // message types for mStatusUpdateHandler - private final static int STATUS_UPDATE = 1; - private static final int MESSAGE_TRAFFIC_COUNT = 2; - private static final int MESSAGE_PORTS = 3; - - private RecyclerView rv; + // this is what takes messages or values from the callback threads or other non-mainUI threads +//and passes them back into the main UI thread for display to the user + private Handler mStatusUpdateHandler = new Handler() {
- ArrayList<String> pkgIds = new ArrayList<>(); - - /** - * Called when the activity is first created. - */ - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mPrefs = Prefs.getSharedPrefs(getApplicationContext()); - - /* Create the widgets before registering for broadcasts to guarantee - * that the widgets exist when the status updates try to update them */ - doLayout(); - - /* receive the internal status broadcasts, which are separate from the public - * status broadcasts to prevent other apps from sending fake/wrong status - * info to this app */ - LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); - lbm.registerReceiver(mLocalBroadcastReceiver, - new IntentFilter(TorServiceConstants.ACTION_STATUS)); - lbm.registerReceiver(mLocalBroadcastReceiver, - new IntentFilter(TorServiceConstants.LOCAL_ACTION_BANDWIDTH)); - lbm.registerReceiver(mLocalBroadcastReceiver, - new IntentFilter(TorServiceConstants.LOCAL_ACTION_LOG)); - lbm.registerReceiver(mLocalBroadcastReceiver, - new IntentFilter(TorServiceConstants.LOCAL_ACTION_PORTS)); - + @Override + public void handleMessage(final Message msg) {
- boolean showFirstTime = mPrefs.getBoolean("connect_first_time", true); + Bundle data = msg.getData();
- if (showFirstTime) - { - Editor pEdit = mPrefs.edit(); - pEdit.putBoolean("connect_first_time", false); - pEdit.commit(); - startActivity(new Intent(this,OnboardingActivity.class)); - } + switch (msg.what) { + case MESSAGE_TRAFFIC_COUNT:
- /** - * Resets previous DNS Port to the default - */ - mPrefs.edit().putInt(VpnPrefs.PREFS_DNS_PORT, - TorServiceConstants.TOR_DNS_PORT_DEFAULT).apply(); + DataCount datacount = new DataCount(data.getLong("upload"), data.getLong("download"));
- } + long totalRead = data.getLong("readTotal"); + long totalWrite = data.getLong("writeTotal");
- private void sendIntentToService(final String action) { +// downloadText.setText(formatCount(datacount.Download) + " / " + formatTotal(totalRead)); + // uploadText.setText(formatCount(datacount.Upload) + " / " + formatTotal(totalWrite));
- Intent intent = new Intent(MiniMainActivity.this, OrbotService.class); - intent.setAction(action); - startService(intent); + downloadText.setText(formatTotal(totalRead) + " \u2193"); + uploadText.setText(formatTotal(totalWrite) + " \u2191");
- } + break; + case MESSAGE_PORTS:
- private void stopTor() { + int socksPort = data.getInt("socks"); + int httpPort = data.getInt("http");
- Intent intent = new Intent(MiniMainActivity.this, OrbotService.class); - stopService(intent); + break; + default: + String newTorStatus = msg.getData().getString("status"); + String log = (String) msg.obj;
- } + if (torStatus == null && newTorStatus != null) //first time status + { + updateStatus(log, newTorStatus);
+ } else + updateStatus(log, newTorStatus); + super.handleMessage(msg); + break; + } + } + }; /** * The state and log info from {@link OrbotService} are sent to the UI here in * the form of a local broadcast. Regular broadcasts can be sent by any app, @@ -212,61 +188,171 @@ public class MiniMainActivity extends AppCompatActivity
} else if (action.equals(TorServiceConstants.ACTION_STATUS)) { lastStatusIntent = intent; - + Message msg = mStatusUpdateHandler.obtainMessage(STATUS_UPDATE); msg.getData().putString("status", intent.getStringExtra(TorServiceConstants.EXTRA_STATUS));
mStatusUpdateHandler.sendMessage(msg); - } - else if (action.equals(TorServiceConstants.LOCAL_ACTION_PORTS)) { + } else if (action.equals(TorServiceConstants.LOCAL_ACTION_PORTS)) {
Message msg = mStatusUpdateHandler.obtainMessage(MESSAGE_PORTS); - msg.getData().putInt("socks",intent.getIntExtra(OrbotService.EXTRA_SOCKS_PROXY_PORT,-1)); - msg.getData().putInt("http",intent.getIntExtra(OrbotService.EXTRA_HTTP_PROXY_PORT,-1)); + msg.getData().putInt("socks", intent.getIntExtra(OrbotService.EXTRA_SOCKS_PROXY_PORT, -1)); + msg.getData().putInt("http", intent.getIntExtra(OrbotService.EXTRA_HTTP_PROXY_PORT, -1));
mStatusUpdateHandler.sendMessage(msg);
} } }; - - private void doLayout () - { + + private static String readFromAssets(Context context, String filename) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename))); + + // do reading, usually loop until end of file reading + StringBuilder sb = new StringBuilder(); + String mLine = reader.readLine(); + while (mLine != null) { + sb.append(mLine + '\n'); // process line + mLine = reader.readLine(); + } + reader.close(); + return sb.toString(); + } + + public static TorifiedApp getApp(Context context, ApplicationInfo aInfo) { + TorifiedApp app = new TorifiedApp(); + + PackageManager pMgr = context.getPackageManager(); + + + try { + app.setName(pMgr.getApplicationLabel(aInfo).toString()); + } catch (Exception e) { + return null; + } + + + app.setEnabled(aInfo.enabled); + app.setUid(aInfo.uid); + app.setUsername(pMgr.getNameForUid(app.getUid())); + app.setProcname(aInfo.processName); + app.setPackageName(aInfo.packageName); + + app.setTorified(true); + + try { + app.setIcon(pMgr.getApplicationIcon(app.getPackageName())); + + + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return app; + } + + public static Bitmap drawableToBitmap(Drawable drawable) { + Bitmap bitmap = null; + + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if (bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + /** + * Called when the activity is first created. + */ + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mPrefs = Prefs.getSharedPrefs(getApplicationContext()); + + /* Create the widgets before registering for broadcasts to guarantee + * that the widgets exist when the status updates try to update them */ + doLayout(); + + /* receive the internal status broadcasts, which are separate from the public + * status broadcasts to prevent other apps from sending fake/wrong status + * info to this app */ + LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); + lbm.registerReceiver(mLocalBroadcastReceiver, + new IntentFilter(TorServiceConstants.ACTION_STATUS)); + lbm.registerReceiver(mLocalBroadcastReceiver, + new IntentFilter(TorServiceConstants.LOCAL_ACTION_BANDWIDTH)); + lbm.registerReceiver(mLocalBroadcastReceiver, + new IntentFilter(TorServiceConstants.LOCAL_ACTION_LOG)); + lbm.registerReceiver(mLocalBroadcastReceiver, + new IntentFilter(TorServiceConstants.LOCAL_ACTION_PORTS)); + + + boolean showFirstTime = mPrefs.getBoolean("connect_first_time", true); + + if (showFirstTime) { + Editor pEdit = mPrefs.edit(); + pEdit.putBoolean("connect_first_time", false); + pEdit.commit(); + startActivity(new Intent(this, OnboardingActivity.class)); + } + + /** + * Resets previous DNS Port to the default + */ + mPrefs.edit().putInt(VpnPrefs.PREFS_DNS_PORT, TorServiceConstants.TOR_DNS_PORT_DEFAULT).apply(); + + } + + private void sendIntentToService(final String action) { + + Intent intent = new Intent(MiniMainActivity.this, OrbotService.class); + intent.setAction(action); + startService(intent); + + } + + private void stopTor() { + + Intent intent = new Intent(MiniMainActivity.this, OrbotService.class); + stopService(intent); + + } + + private void doLayout() { setContentView(R.layout.layout_main); - + setTitle(R.string.app_name);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); - - mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
- mTxtOrbotLog = (TextView)findViewById(R.id.orbotLog); + mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
- /** - lblStatus = (TextView)findViewById(R.id.lblStatus); - lblStatus.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mDrawer.openDrawer(LOG_DRAWER_GRAVITY); - } - });**/ + mTxtOrbotLog = (TextView) findViewById(R.id.orbotLog);
- imgStatus = (ImageView)findViewById(R.id.imgStatus); + imgStatus = (ImageView) findViewById(R.id.imgStatus); imgStatus.setOnLongClickListener(this);
- downloadText = (TextView)findViewById(R.id.trafficDown); - uploadText = (TextView)findViewById(R.id.trafficUp); + downloadText = (TextView) findViewById(R.id.trafficDown); + uploadText = (TextView) findViewById(R.id.trafficUp);
- // downloadText.setText(formatCount(0) + " / " + formatTotal(0)+ " \u2193"); - // uploadText.setText(formatCount(0) + " / " + formatTotal(0)+ " \u2191"); - - downloadText.setText(formatTotal(0) +" \u2193"); + downloadText.setText(formatTotal(0) + " \u2193"); uploadText.setText(formatTotal(0) + " \u2191");
- mBtnVPN = (SwitchCompat)findViewById(R.id.btnVPN); - + mBtnVPN = (SwitchCompat) findViewById(R.id.btnVPN); + boolean useVPN = Prefs.useVpn(); mBtnVPN.setChecked(useVPN);
@@ -287,26 +373,17 @@ public class MiniMainActivity extends AppCompatActivity LinearLayoutManager llm = new LinearLayoutManager(this); llm.setOrientation(LinearLayoutManager.VERTICAL); rv.setLayoutManager(llm); - - /** - findViewById(R.id.btnAdd).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startActivityForResult(new Intent(MiniMainActivity.this, AppManagerActivity.class), REQUEST_VPN_APPS_SELECT); - } - });**/ }
- @Override protected void attachBaseContext(Context base) { super.attachBaseContext(LocaleHelper.onAttach(base)); }
- /* - * Create the UI Options Menu (non-Javadoc) - * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) - */ + /* + * Create the UI Options Menu (non-Javadoc) + * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) + */ @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); @@ -314,111 +391,52 @@ public class MiniMainActivity extends AppCompatActivity inflater.inflate(R.menu.orbot_main, menu); return true; } - -
@Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.menu_newnym) - { + if (item.getItemId() == R.id.menu_newnym) { requestNewTorIdentity(); + } else if (item.getItemId() == R.id.menu_settings) { + Intent intent = SettingsPreferencesActivity.createIntent(this, R.xml.preferences); + startActivityForResult(intent, REQUEST_SETTINGS); } - else if (item.getItemId() == R.id.menu_settings) - { - Intent intent = new Intent(MiniMainActivity.this, SettingsPreferences.class); - startActivityForResult(intent, REQUEST_SETTINGS); - } - /** - else if (item.getItemId() == R.id.menu_exit) - { - //exit app - doExit(); - - }**/ - else if (item.getItemId() == R.id.menu_about) - { - showAbout(); - - - } - /** - else if (item.getItemId() == R.id.menu_scan) - { - IntentIntegrator integrator = new IntentIntegrator(MiniMainActivity.this); - integrator.initiateScan(); - } - else if (item.getItemId() == R.id.menu_share_bridge) - { - - String bridges = Prefs.getBridgesList(); - - if (bridges != null && bridges.length() > 0) - { - try { - bridges = "bridge://" + URLEncoder.encode(bridges,"UTF-8"); - - IntentIntegrator integrator = new IntentIntegrator(MiniMainActivity.this); - integrator.shareText(bridges); - - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - }**/ - - return super.onOptionsItemSelected(item); - } - - private void showAbout () - { - - LayoutInflater li = LayoutInflater.from(this); - View view = li.inflate(R.layout.layout_about, null); - - String version = ""; - - try { - version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName + " (Tor " + OrbotService.BINARY_TOR_VERSION + ")"; - } catch (NameNotFoundException e) { - version = "Version Not Found"; - } - - TextView versionName = (TextView)view.findViewById(R.id.versionName); - versionName.setText(version); + else if (item.getItemId() == R.id.menu_about) { + showAbout(); + } + return super.onOptionsItemSelected(item); + }
- TextView aboutOther = (TextView)view.findViewById(R.id.aboutother); + private void showAbout() {
- try - { - String aboutText = readFromAssets(this,"LICENSE"); - aboutText = aboutText.replace("\n","<br/>"); - aboutOther.setText(Html.fromHtml(aboutText)); - } - catch (Exception e){} - - new AlertDialog.Builder(this) - .setTitle(getString(R.string.button_about)) - .setView(view) - .show(); + LayoutInflater li = LayoutInflater.from(this); + View view = li.inflate(R.layout.layout_about, null); + + String version = ""; + + try { + version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName + " (Tor " + OrbotService.BINARY_TOR_VERSION + ")"; + } catch (NameNotFoundException e) { + version = "Version Not Found"; }
- private static String readFromAssets(Context context, String filename) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename))); + TextView versionName = (TextView) view.findViewById(R.id.versionName); + versionName.setText(version);
- // do reading, usually loop until end of file reading - StringBuilder sb = new StringBuilder(); - String mLine = reader.readLine(); - while (mLine != null) { - sb.append(mLine + '\n'); // process line - mLine = reader.readLine(); + TextView aboutOther = (TextView) view.findViewById(R.id.aboutother); + + try { + String aboutText = readFromAssets(this, "LICENSE"); + aboutText = aboutText.replace("\n", "<br/>"); + aboutOther.setText(Html.fromHtml(aboutText)); + } catch (Exception e) { } - reader.close(); - return sb.toString(); - }
+ new AlertDialog.Builder(this) + .setTitle(getString(R.string.button_about)) + .setView(view) + .show(); + }
/** * This is our attempt to REALLY exit Orbot, and stop the background service @@ -434,43 +452,36 @@ public class MiniMainActivity extends AppCompatActivity finish(); }
- protected void onPause() { - try - { - super.onPause(); - - if (aDialog != null) - aDialog.dismiss(); - } - catch (IllegalStateException ise) - { - //can happen on exit/shutdown - } - } + protected void onPause() { + try { + super.onPause();
+ if (aDialog != null) + aDialog.dismiss(); + } catch (IllegalStateException ise) { + //can happen on exit/shutdown + } + }
@Override public void onBackPressed() { // check to see if the log is open, if so close it if (mDrawer.isDrawerOpen(LOG_DRAWER_GRAVITY)) { mDrawer.closeDrawers(); - } - else { + } else { super.onBackPressed(); } }
- private void refreshVPNApps() { + private void refreshVPNApps() { sendIntentToService(TorServiceConstants.ACTION_STOP_VPN); sendIntentToService(TorServiceConstants.ACTION_START_VPN); }
- private void enableVPN (boolean enable) - { + private void enableVPN(boolean enable) { if (enable && pkgIds.size() == 0) { showAppPicker(); - } - else { + } else { Prefs.putUseVpn(enable); Prefs.putStartOnBoot(enable);
@@ -491,7 +502,6 @@ public class MiniMainActivity extends AppCompatActivity } }
- private synchronized void handleIntents() { if (getIntent() == null) return; @@ -510,9 +520,7 @@ public class MiniMainActivity extends AppCompatActivity
if (urlString != null) {
- if (urlString.toLowerCase().startsWith("bridge://")) - - { + if (urlString.toLowerCase().startsWith("bridge://")) { String newBridgeValue = urlString.substring(9); //remove the bridge protocol piece newBridgeValue = URLDecoder.decode(newBridgeValue); //decode the value here
@@ -542,58 +550,53 @@ public class MiniMainActivity extends AppCompatActivity enableBridges(true); }
- /* - * Launch the system activity for Uri viewing with the provided url - */ - private void openBrowser(final String browserLaunchUrl,boolean forceExternal, String pkgId) { - if (pkgId != null) { - startIntent(pkgId,Intent.ACTION_VIEW,Uri.parse(browserLaunchUrl)); + /* + * Launch the system activity for Uri viewing with the provided url + */ + private void openBrowser(final String browserLaunchUrl, boolean forceExternal, String pkgId) { + if (pkgId != null) { + startIntent(pkgId, Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); + } else if (mBtnVPN.isChecked() || forceExternal) { + //use the system browser since VPN is on + startIntent(null, Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); } - else if (mBtnVPN.isChecked()||forceExternal) { - //use the system browser since VPN is on - startIntent(null,Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); - } - } - - private void startIntent (String pkg, String action, Uri data) - { + } + + private void startIntent(String pkg, String action, Uri data) { Intent i; - PackageManager pm = getPackageManager(); + PackageManager pm = getPackageManager();
try { - if (pkg != null) { - i = pm.getLaunchIntentForPackage(pkg); - if (i == null) - throw new PackageManager.NameNotFoundException(); - } - else - { - i = new Intent(); - } + if (pkg != null) { + i = pm.getLaunchIntentForPackage(pkg); + if (i == null) + throw new PackageManager.NameNotFoundException(); + } else { + i = new Intent(); + }
i.setAction(action); i.setData(data);
- if (i.resolveActivity(pm)!=null) - startActivity(i); + if (i.resolveActivity(pm) != null) + startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
} } - + @Override protected void onActivityResult(int request, int response, Intent data) { super.onActivityResult(request, response, data);
- if (request == REQUEST_SETTINGS && response == RESULT_OK) - { + if (request == REQUEST_SETTINGS && response == RESULT_OK) { if (data != null && (!TextUtils.isEmpty(data.getStringExtra("locale")))) {
String newLocale = data.getStringExtra("locale"); Prefs.setDefaultLocale(newLocale); Languages.setLanguage(this, newLocale, true); - // Language.setFromPreference(this, "pref_default_locale"); + // Language.setFromPreference(this, "pref_default_locale");
finish();
@@ -609,8 +612,7 @@ public class MiniMainActivity extends AppCompatActivity
} - } else if (request == REQUEST_VPN_APPS_SELECT) - { + } else if (request == REQUEST_VPN_APPS_SELECT) { if (response == RESULT_OK && torStatus == TorServiceConstants.STATUS_ON) { refreshVPNApps(); @@ -625,104 +627,78 @@ public class MiniMainActivity extends AppCompatActivity Prefs.putUseVpn(false); }
- + IntentResult scanResult = IntentIntegrator.parseActivityResult(request, response, data); if (scanResult != null) { - // handle scan result - - String results = scanResult.getContents(); - - if (results != null && results.length() > 0) - { - try { - - int urlIdx = results.indexOf("://"); - - if (urlIdx!=-1) - { - results = URLDecoder.decode(results, "UTF-8"); - results = results.substring(urlIdx+3); - - showAlert(getString(R.string.bridges_updated),getString(R.string.restart_orbot_to_use_this_bridge_) + results,false); - - setNewBridges(results); - } - else - { - JSONArray bridgeJson = new JSONArray(results); - StringBuffer bridgeLines = new StringBuffer(); - - for (int i = 0; i < bridgeJson.length(); i++) - { - String bridgeLine = bridgeJson.getString(i); - bridgeLines.append(bridgeLine).append("\n"); - } - - setNewBridges(bridgeLines.toString()); - } - - - } catch (Exception e) { - Log.e(TAG,"unsupported",e); - } - } - - } - - } + // handle scan result
- /** - public void promptSetupBridges () - { + String results = scanResult.getContents(); + + if (results != null && results.length() > 0) { + try { + + int urlIdx = results.indexOf("://"); + + if (urlIdx != -1) { + results = URLDecoder.decode(results, "UTF-8"); + results = results.substring(urlIdx + 3); + + showAlert(getString(R.string.bridges_updated), getString(R.string.restart_orbot_to_use_this_bridge_) + results, false); + + setNewBridges(results); + } else { + JSONArray bridgeJson = new JSONArray(results); + StringBuffer bridgeLines = new StringBuffer(); + + for (int i = 0; i < bridgeJson.length(); i++) { + String bridgeLine = bridgeJson.getString(i); + bridgeLines.append(bridgeLine).append("\n"); + } + + setNewBridges(bridgeLines.toString()); + } + + + } catch (Exception e) { + Log.e(TAG, "unsupported", e); + } + }
- if (mBtnBridges.isChecked()) - { - Prefs.putBridgesEnabled(true); - startActivity(new Intent(this, BridgeWizardActivity.class)); } - else - { - enableBridges(false); + + } + + private void enableBridges(boolean enable) { + Prefs.putBridgesEnabled(enable); + + if (torStatus == TorServiceConstants.STATUS_ON) { + String bridgeList = Prefs.getBridgesList(); + if (bridgeList != null && bridgeList.length() > 0) { + requestTorRereadConfig(); + } } - - }**/ - - - private void enableBridges (boolean enable) - { - Prefs.putBridgesEnabled(enable); - - if (torStatus == TorServiceConstants.STATUS_ON) - { - String bridgeList = Prefs.getBridgesList(); - if (bridgeList != null && bridgeList.length() > 0) - { - requestTorRereadConfig (); - } - } }
private void requestTorRereadConfig() { sendIntentToService(TorServiceConstants.CMD_SIGNAL_HUP); }
- @Override protected void onResume() { super.onResume();
- if (mBtnVPN.isChecked()!=Prefs.useVpn()) + if (mBtnVPN.isChecked() != Prefs.useVpn()) mBtnVPN.setChecked(Prefs.useVpn());
- requestTorStatus(); + requestTorStatus();
- if (torStatus == null) - updateStatus("", TorServiceConstants.STATUS_STOPPING); + if (torStatus == null) + updateStatus("", TorServiceConstants.STATUS_STOPPING); else updateStatus(null, torStatus);
- //now you can handle the intents properly - handleIntents(); + //now you can handle the intents properly + handleIntents();
pkgIds.clear(); String tordAppString = mPrefs.getString(PREFS_KEY_TORIFIED, ""); @@ -735,40 +711,33 @@ public class MiniMainActivity extends AppCompatActivity
}
- AlertDialog aDialog = null; - //general alert dialog for mostly Tor warning messages //sometimes this can go haywire or crazy with too many error //messages from Tor, and the user cannot stop or exit Orbot //so need to ensure repeated error messages are not spamming this method - private void showAlert(String title, String msg, boolean button) - { - try - { - if (aDialog != null && aDialog.isShowing()) - aDialog.dismiss(); - } - catch (Exception e){} //swallow any errors - - if (button) - { - aDialog = new AlertDialog.Builder(MiniMainActivity.this) - .setIcon(R.drawable.onion32) - .setTitle(title) - .setMessage(msg) - .setPositiveButton(R.string.btn_okay, null) - .show(); - } - else - { - aDialog = new AlertDialog.Builder(MiniMainActivity.this) - .setIcon(R.drawable.onion32) - .setTitle(title) - .setMessage(msg) - .show(); - } - - aDialog.setCanceledOnTouchOutside(true); + private void showAlert(String title, String msg, boolean button) { + try { + if (aDialog != null && aDialog.isShowing()) + aDialog.dismiss(); + } catch (Exception e) { + } //swallow any errors + + if (button) { + aDialog = new AlertDialog.Builder(MiniMainActivity.this) + .setIcon(R.drawable.onion32) + .setTitle(title) + .setMessage(msg) + .setPositiveButton(R.string.btn_okay, null) + .show(); + } else { + aDialog = new AlertDialog.Builder(MiniMainActivity.this) + .setIcon(R.drawable.onion32) + .setTitle(title) + .setMessage(msg) + .show(); + } + + aDialog.setCanceledOnTouchOutside(true); }
/** @@ -777,10 +746,9 @@ public class MiniMainActivity extends AppCompatActivity */ private void updateStatus(String torServiceMsg, String newTorStatus) {
- if (!TextUtils.isEmpty(torServiceMsg)) - { + if (!TextUtils.isEmpty(torServiceMsg)) { if (torServiceMsg.contains(TorServiceConstants.LOG_NOTICE_HEADER)) { - // lblStatus.setText(torServiceMsg); + // lblStatus.setText(torServiceMsg); }
mTxtOrbotLog.append(torServiceMsg + '\n'); @@ -790,18 +758,16 @@ public class MiniMainActivity extends AppCompatActivity if (torStatus == null || (newTorStatus != null && newTorStatus.equals(torStatus))) { torStatus = newTorStatus; return; - } - else - torStatus = newTorStatus; + } else + torStatus = newTorStatus;
if (torStatus == TorServiceConstants.STATUS_ON) { - + imgStatus.setImageResource(R.drawable.toron);
//lblStatus.setText(getString(R.string.status_activated));
- if (autoStartFromIntent) - { + if (autoStartFromIntent) { autoStartFromIntent = false; Intent resultIntent = lastStatusIntent;
@@ -810,7 +776,7 @@ public class MiniMainActivity extends AppCompatActivity
resultIntent.putExtra( TorServiceConstants.EXTRA_STATUS, - torStatus == null?TorServiceConstants.STATUS_OFF:torStatus + torStatus == null ? TorServiceConstants.STATUS_OFF : torStatus );
setResult(RESULT_OK, resultIntent); @@ -818,35 +784,33 @@ public class MiniMainActivity extends AppCompatActivity finish(); Log.d(TAG, "autoStartFromIntent finish"); } - - +
} else if (torStatus == TorServiceConstants.STATUS_STARTING) {
imgStatus.setImageResource(R.drawable.torstarting);
- if (torServiceMsg != null) - { - if (torServiceMsg.contains(TorServiceConstants.LOG_NOTICE_BOOTSTRAPPED)) { + if (torServiceMsg != null) { + if (torServiceMsg.contains(TorServiceConstants.LOG_NOTICE_BOOTSTRAPPED)) { // lblStatus.setText(torServiceMsg); } } - // else - // lblStatus.setText(getString(R.string.status_starting_up)); + // else + // lblStatus.setText(getString(R.string.status_starting_up));
} else if (torStatus == TorServiceConstants.STATUS_STOPPING) {
- // if (torServiceMsg != null && torServiceMsg.contains(TorServiceConstants.LOG_NOTICE_HEADER)) - // lblStatus.setText(torServiceMsg); - + // if (torServiceMsg != null && torServiceMsg.contains(TorServiceConstants.LOG_NOTICE_HEADER)) + // lblStatus.setText(torServiceMsg); + imgStatus.setImageResource(R.drawable.torstarting); // lblStatus.setText(torServiceMsg);
} else if (torStatus == TorServiceConstants.STATUS_OFF) {
imgStatus.setImageResource(R.drawable.toroff); - // lblStatus.setText("Tor v" + OrbotService.BINARY_TOR_VERSION); + // lblStatus.setText("Tor v" + OrbotService.BINARY_TOR_VERSION);
} @@ -863,7 +827,7 @@ public class MiniMainActivity extends AppCompatActivity sendIntentToService(TorServiceConstants.ACTION_START); mTxtOrbotLog.setText(""); } - + /** * Request tor status without starting it * {@link TorServiceConstants#ACTION_START} {@link Intent} to @@ -873,16 +837,6 @@ public class MiniMainActivity extends AppCompatActivity sendIntentToService(TorServiceConstants.ACTION_STATUS); }
- private boolean isTorServiceRunning() { - ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (OrbotService.class.getName().equals(service.service.getClassName())) { - return true; - } - } - return false; - } - public boolean onLongClick(View view) {
if (torStatus == TorServiceConstants.STATUS_OFF) { @@ -890,92 +844,18 @@ public class MiniMainActivity extends AppCompatActivity } else { stopTor(); } - - return true; - - } - -// this is what takes messages or values from the callback threads or other non-mainUI threads -//and passes them back into the main UI thread for display to the user - private Handler mStatusUpdateHandler = new Handler() { - - @Override - public void handleMessage(final Message msg) { - - - Bundle data = msg.getData(); - - switch (msg.what) { - case MESSAGE_TRAFFIC_COUNT: - - DataCount datacount = new DataCount(data.getLong("upload"),data.getLong("download")); - - long totalRead = data.getLong("readTotal"); - long totalWrite = data.getLong("writeTotal"); - -// downloadText.setText(formatCount(datacount.Download) + " / " + formatTotal(totalRead)); - // uploadText.setText(formatCount(datacount.Upload) + " / " + formatTotal(totalWrite)); - - downloadText.setText(formatTotal(totalRead) +" \u2193"); - uploadText.setText(formatTotal(totalWrite) + " \u2191"); - - break; - case MESSAGE_PORTS: - - int socksPort = data.getInt("socks"); - int httpPort = data.getInt("http"); - - break; - default: - String newTorStatus = msg.getData().getString("status"); - String log = (String)msg.obj;
- if (torStatus == null && newTorStatus != null) //first time status - { - updateStatus(log, newTorStatus); + return true;
- } - else - updateStatus(log, newTorStatus); - super.handleMessage(msg); - break; - } - } - }; + }
@Override protected void onDestroy() { super.onDestroy(); - LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver);
}
- public class DataCount { - // data uploaded - public long Upload; - // data downloaded - public long Download; - - DataCount(long Upload, long Download){ - this.Upload = Upload; - this.Download = Download; - } - } - - private String formatCount(long count) { - NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault()); - // Converts the supplied argument into a string. - // Under 2Mb, returns "xxx.xKb" - // Over 2Mb, returns "xxx.xxMb" - if (count < 1e6) - return numberFormat.format(Math.round(((float) ((int) (count * 10 / 1024)) / 10))) - + getString(R.string.kbps); - else - return numberFormat.format(Math - .round(((float) ((int) (count * 100 / 1024 / 1024)) / 100))) - + getString(R.string.mbps); - } - private String formatTotal(long count) { NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault()); // Converts the supplied argument into a string. @@ -983,57 +863,59 @@ public class MiniMainActivity extends AppCompatActivity // Over 2Mb, returns "xxx.xxMb" if (count < 1e6) return numberFormat.format(Math.round( - (int)(((float)count)) * 10f / 1024f / 10f) - ) + (int) (((float) count)) * 10f / 1024f / 10f) + ) + getString(R.string.kb); else return numberFormat.format(Math .round( - ((float)count)) * 100f / 1024f / 1024f / 100f - ) + ((float) count)) * 100f / 1024f / 1024f / 100f + ) + getString(R.string.mb); }
- private static final float ROTATE_FROM = 0.0f; - private static final float ROTATE_TO = 360.0f*4f;// 3.141592654f * 32.0f; + private void requestNewTorIdentity() { + sendIntentToService(TorServiceConstants.CMD_NEWNYM);
- private void requestNewTorIdentity () - { - sendIntentToService (TorServiceConstants.CMD_NEWNYM); - - Rotate3dAnimation rotation = new Rotate3dAnimation(ROTATE_FROM, ROTATE_TO, imgStatus.getWidth()/2f,imgStatus.getWidth()/2f,20f,false); + Rotate3dAnimation rotation = new Rotate3dAnimation(ROTATE_FROM, ROTATE_TO, imgStatus.getWidth() / 2f, imgStatus.getWidth() / 2f, 20f, false); rotation.setFillAfter(true); rotation.setInterpolator(new AccelerateInterpolator()); - rotation.setDuration((long) 2*1000); + rotation.setDuration((long) 2 * 1000); rotation.setRepeatCount(0); imgStatus.startAnimation(rotation); // lblStatus.setText(getString(R.string.newnym)); }
+ public void showAppPicker() { + startActivityForResult(new Intent(MiniMainActivity.this, AppManagerActivity.class), REQUEST_VPN_APPS_SELECT);
- public class RVAdapter extends RecyclerView.Adapter<RVAdapter.AppViewHolder>{ - - - public class AppViewHolder extends RecyclerView.ViewHolder { + }
- ImageView iv; - TextView tv; - View parent; + public void showAppConfig(String pkgId) { + Intent data = new Intent(this, AppConfigActivity.class); + data.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgId); + startActivityForResult(data, REQUEST_VPN_APPS_SELECT); + }
- AppViewHolder(View itemView) { - super(itemView); - parent = itemView; - iv = itemView.findViewById(R.id.itemicon); - tv = itemView.findViewById(R.id.itemtext); + public class DataCount { + // data uploaded + public long Upload; + // data downloaded + public long Download; + + DataCount(long Upload, long Download) { + this.Upload = Upload; + this.Download = Download; + } + }
- } + public class RVAdapter extends RecyclerView.Adapter<RVAdapter.AppViewHolder> {
- }
@Override public int getItemCount() {
- return pkgIds.size()+1; + return pkgIds.size() + 1; }
@Override @@ -1043,7 +925,6 @@ public class MiniMainActivity extends AppCompatActivity final AppViewHolder avh = new AppViewHolder(v);
- return avh; }
@@ -1051,10 +932,10 @@ public class MiniMainActivity extends AppCompatActivity public void onBindViewHolder(final AppViewHolder avh, int i) {
- if (i < getItemCount()-1) { + if (i < getItemCount() - 1) { final String pkgId = pkgIds.get(i);
- ApplicationInfo aInfo = null; + ApplicationInfo aInfo; try { aInfo = getPackageManager().getApplicationInfo(pkgId, 0); TorifiedApp app = getApp(MiniMainActivity.this, aInfo); @@ -1085,9 +966,7 @@ public class MiniMainActivity extends AppCompatActivity } catch (NameNotFoundException e) { e.printStackTrace(); } - } - else - { + } else { avh.iv.setVisibility(View.INVISIBLE); avh.tv.setText("+ ADD APP"); avh.parent.setOnClickListener(new View.OnClickListener() { @@ -1101,80 +980,20 @@ public class MiniMainActivity extends AppCompatActivity } }
+ public class AppViewHolder extends RecyclerView.ViewHolder {
- } - - public static TorifiedApp getApp (Context context, ApplicationInfo aInfo) - { - TorifiedApp app = new TorifiedApp(); - - PackageManager pMgr = context.getPackageManager(); - - - try - { - app.setName(pMgr.getApplicationLabel(aInfo).toString()); - } - catch (Exception e) - { - return null; - } - - - app.setEnabled(aInfo.enabled); - app.setUid(aInfo.uid); - app.setUsername(pMgr.getNameForUid(app.getUid())); - app.setProcname(aInfo.processName); - app.setPackageName(aInfo.packageName); - - app.setTorified(true); - - try { - app.setIcon(pMgr.getApplicationIcon(app.getPackageName())); - - - } catch (NameNotFoundException e) { - e.printStackTrace(); - } - return app; - } - - - public void showAppPicker () - { - startActivityForResult(new Intent(MiniMainActivity.this, AppManagerActivity.class), REQUEST_VPN_APPS_SELECT); - - } - - public void showAppConfig (String pkgId) - { - Intent data = new Intent(this, AppConfigActivity.class); - data.putExtra(Intent.EXTRA_PACKAGE_NAME,pkgId); - startActivityForResult(data,REQUEST_VPN_APPS_SELECT); - } - + ImageView iv; + TextView tv; + View parent;
- public static Bitmap drawableToBitmap (Drawable drawable) { - Bitmap bitmap = null; + AppViewHolder(View itemView) { + super(itemView); + parent = itemView; + iv = itemView.findViewById(R.id.itemicon); + tv = itemView.findViewById(R.id.itemtext);
- if (drawable instanceof BitmapDrawable) { - BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; - if(bitmapDrawable.getBitmap() != null) { - return bitmapDrawable.getBitmap(); } - }
- if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { - bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel - } else { - bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); } - - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - return bitmap; } - - } diff --git a/app-mini/src/main/java/org/torproject/android/mini/OnBootReceiver.java b/app-mini/src/main/java/org/torproject/android/mini/OnBootReceiver.java deleted file mode 100644 index c958df8b..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/OnBootReceiver.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.torproject.android.mini; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Build; - -import org.torproject.android.service.OrbotService; -import org.torproject.android.service.TorServiceConstants; -import org.torproject.android.service.util.Prefs; - -public class OnBootReceiver extends BroadcastReceiver { - - private static boolean sReceivedBoot = false; - - @Override - public void onReceive(Context context, Intent intent) { - if (Prefs.startOnBoot() && (!sReceivedBoot)) { - startService(TorServiceConstants.ACTION_START_ON_BOOT, context); - sReceivedBoot = true; - } - } - - private void startService (String action, Context context) { - Intent intent = new Intent(context, OrbotService.class); - intent.setAction(action); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent); - } - else - { - context.startService(intent); - } - - } - - -} - diff --git a/app-mini/src/main/java/org/torproject/android/mini/OrbotMiniApp.java b/app-mini/src/main/java/org/torproject/android/mini/OrbotMiniApp.java index 41bd0697..f0612cc5 100644 --- a/app-mini/src/main/java/org/torproject/android/mini/OrbotMiniApp.java +++ b/app-mini/src/main/java/org/torproject/android/mini/OrbotMiniApp.java @@ -1,32 +1,18 @@ - package org.torproject.android.mini;
-import android.annotation.SuppressLint; -import android.app.Activity; import android.app.Application; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; import android.content.res.Configuration; -import androidx.core.app.NotificationCompat; -import com.github.javiersantos.appupdater.AppUpdater; -import com.github.javiersantos.appupdater.enums.Display; -import com.github.javiersantos.appupdater.enums.UpdateFrom; -import org.torproject.android.mini.settings.Languages; -import org.torproject.android.mini.settings.LocaleHelper; + +import org.torproject.android.core.Languages; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.service.OrbotConstants; import org.torproject.android.service.util.Prefs;
import java.util.Locale;
- public class OrbotMiniApp extends Application implements OrbotConstants {
- private Locale locale; - @Override public void onCreate() { super.onCreate(); @@ -35,18 +21,12 @@ public class OrbotMiniApp extends Application implements OrbotConstants { if (!Prefs.getDefaultLocale().equals(Locale.getDefault().getLanguage())) { Languages.setLanguage(this, Prefs.getDefaultLocale(), true); } - - //check for updates via github, since it is unlikely to be blocked; notify the user of places where upgrades can be found - new AppUpdater(this) - .setUpdateFrom(UpdateFrom.JSON) - .setUpdateJSON("https://raw.githubusercontent.com/n8fr8/orbot/master/update.json") - .setDisplay(Display.NOTIFICATION).start(); }
@Override protected void attachBaseContext(Context base) { Prefs.setContext(base); - super.attachBaseContext(LocaleHelper.onAttach(base, Prefs.getDefaultLocale())); + super.attachBaseContext(LocaleHelper.onAttach(base)); }
@Override @@ -56,53 +36,4 @@ public class OrbotMiniApp extends Application implements OrbotConstants { if (!Prefs.getDefaultLocale().equals(Locale.getDefault().getLanguage())) Languages.setLanguage(this, Prefs.getDefaultLocale(), true); } - /** - public static void forceChangeLanguage(Activity activity) { - Intent intent = activity.getIntent(); - if (intent == null) // when launched as LAUNCHER - intent = new Intent(activity, OrbotMainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - activity.finish(); - activity.overridePendingTransition(0, 0); - activity.startActivity(intent); - activity.overridePendingTransition(0, 0); - }**/ - - public static Languages getLanguages(Activity activity) { - return Languages.get(activity); - } - - - @SuppressLint("NewApi") - protected void showToolbarNotification (String shortMsg, String notifyMsg, int notifyId, int icon) - { - - NotificationCompat.Builder notifyBuilder; - - //Reusable code. - PackageManager pm = getPackageManager(); - Intent intent = pm.getLaunchIntentForPackage(getPackageName()); - PendingIntent pendIntent = PendingIntent.getActivity(this, 0, intent, 0); - - NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - - notifyBuilder = new NotificationCompat.Builder(this) - .setContentTitle(getString(org.torproject.android.service.R.string.app_name)); - - - notifyBuilder.setContentIntent(pendIntent); - - notifyBuilder.setContentText(shortMsg); - notifyBuilder.setSmallIcon(icon); - notifyBuilder.setTicker(notifyMsg); - - notifyBuilder.setOngoing(false); - - notifyBuilder.setStyle(new NotificationCompat.BigTextStyle() - .bigText(notifyMsg).setBigContentTitle(getString(org.torproject.android.service.R.string.app_name))); - - Notification notification = notifyBuilder.build(); - - notificationManager.notify(notifyId, notification); - } -} +} \ No newline at end of file diff --git a/app-mini/src/main/java/org/torproject/android/mini/settings/Languages.java b/app-mini/src/main/java/org/torproject/android/mini/settings/Languages.java deleted file mode 100644 index 5fe04a62..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/settings/Languages.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.torproject.android.mini.settings; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.ContextWrapper; -import android.content.Intent; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Build; -import android.text.TextUtils; -import android.util.DisplayMetrics; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -public class Languages { - public static final String TAG = "Languages"; - - public static final Locale defaultLocale; - public static final Locale TIBETAN = new Locale("bo"); - static final Locale localesToTest[] = { - Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, - Locale.ITALIAN, Locale.JAPANESE, Locale.KOREAN, - Locale.TRADITIONAL_CHINESE, Locale.SIMPLIFIED_CHINESE, - TIBETAN, new Locale("af"), new Locale("am"), - new Locale("ar"), new Locale("ay"), new Locale("az"), new Locale("bg"), - new Locale("bn"), new Locale("ca"), new Locale("cs"), - new Locale("da"), new Locale("el"), new Locale("es"), - new Locale("et"), new Locale("eu"), new Locale("fa"), - new Locale("fi"), new Locale("gl"), new Locale("hi"), - new Locale("hr"), new Locale("hu"), new Locale("hy"), - new Locale("in"), new Locale("hy"), new Locale("in"), - new Locale("is"), new Locale("it"), new Locale("iw"), - new Locale("ka"), new Locale("kk"), new Locale("km"), - new Locale("kn"), new Locale("ky"), new Locale("lo"), - new Locale("lt"), new Locale("lv"), new Locale("mk"), - new Locale("ml"), new Locale("mn"), new Locale("mr"), - new Locale("ms"), new Locale("my"), new Locale("nb"), - new Locale("ne"), new Locale("nl"), new Locale("pl"), - new Locale("pt"), new Locale("rm"), new Locale("ro"), - new Locale("ru"), new Locale("si"), new Locale("sk"), - new Locale("sl"), new Locale("sn"), new Locale("sr"), - new Locale("sv"), new Locale("sw"), new Locale("ta"), - new Locale("te"), new Locale("th"), new Locale("tl"), - new Locale("tr"), new Locale("uk"), new Locale("ur"), - new Locale("uz"), new Locale("vi"), new Locale("zu"), - }; - - private static final String USE_SYSTEM_DEFAULT = ""; - private static final String defaultString = "Use System Default"; - - private static Locale locale; - private static Languages singleton; - private static Class<?> clazz; - private static int resId; - private static Map<String, String> tmpMap = new TreeMap<String, String>(); - private static Map<String, String> nameMap; - - static { - defaultLocale = Locale.getDefault(); - } - - private Languages(Activity activity) { - AssetManager assets = activity.getAssets(); - Configuration config = activity.getResources().getConfiguration(); - // Resources() requires DisplayMetrics, but they are only needed for drawables - DisplayMetrics ignored = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(ignored); - Resources resources; - Set<Locale> localeSet = new LinkedHashSet<Locale>(); - for (Locale locale : localesToTest) { - config.locale = locale; - resources = new Resources(assets, ignored, config); - if (!TextUtils.equals(defaultString, resources.getString(resId)) - || locale.equals(Locale.ENGLISH)) - localeSet.add(locale); - } - - for (Locale locale : localeSet) { - if (locale.equals(TIBETAN)) { - // include English name for devices without Tibetan font support - tmpMap.put(TIBETAN.toString(), "Tibetan བོད་སྐད།"); // Tibetan - } else if (locale.equals(Locale.SIMPLIFIED_CHINESE)) { - tmpMap.put(Locale.SIMPLIFIED_CHINESE.toString(), "中文 (中国)"); // Chinese (China) - } else if (locale.equals(Locale.TRADITIONAL_CHINESE)) { - tmpMap.put(Locale.TRADITIONAL_CHINESE.toString(), "中文 (台灣)"); // Chinese (Taiwan) - } else { - tmpMap.put(locale.toString(), locale.getDisplayLanguage(locale)); - } - } - - /* USE_SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */ - // localeSet.add(null); - // tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId)); - nameMap = Collections.unmodifiableMap(tmpMap); - } - - /** - * Get the instance of {@link Languages} to work with, providing the - * {@link Activity} that is will be working as part of, as well as the - * {@code resId} that has the exact string "Use System Default", - * i.e. {@code R.string.use_system_default}. - * <p/> - * That string resource {@code resId} is also used to find the supported - * translations: if an included translation has a translated string that - * matches that {@code resId}, then that language will be included as a - * supported language. - * - * @param clazz the {@link Class} of the default {@code Activity}, - * usually the main {@code Activity} from where the - * Settings is launched from. - * @param resId the string resource ID to for the string "Use System Default", - * e.g. {@code R.string.use_system_default} - * @return - */ - public static void setup(Class<?> clazz, int resId) { - if (Languages.clazz == null) { - Languages.clazz = clazz; - Languages.resId = resId; - } else { - throw new RuntimeException("Languages singleton was already initialized, duplicate call to Languages.setup()!"); - } - } - - /** - * Get the singleton to work with. - * - * @param activity the {@link Activity} this is working as part of - * @return - */ - public static Languages get(Activity activity) { - if (singleton == null) { - singleton = new Languages(activity); - } - return singleton; - } - - @SuppressLint("NewApi") - public static void setLanguage(final ContextWrapper contextWrapper, String language, boolean refresh) { - if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) { - return; // already configured - } else if (language == null || language == USE_SYSTEM_DEFAULT) { - locale = defaultLocale; - } else { - /* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */ - String localeSplit[] = language.split("_"); - if (localeSplit.length > 1) { - locale = new Locale(localeSplit[0], localeSplit[1]); - } else { - locale = new Locale(language); - } - } - - setLocale(contextWrapper, locale); - - } - - @SuppressWarnings("deprecation") - private static void setLocale(final ContextWrapper contextWrapper, Locale locale){ - Resources resources = contextWrapper.getResources(); - Configuration configuration = resources.getConfiguration(); - DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ - configuration.setLocale(locale); - contextWrapper.getApplicationContext().createConfigurationContext(configuration); - } - else{ - configuration.locale=locale; - resources.updateConfiguration(configuration,displayMetrics); - } - } - - /** - * Force reload the {@link Activity to make language changes take effect.} - * - * @param activity the {@code Activity} to force reload - */ - public static void forceChangeLanguage(Activity activity) { - Intent intent = activity.getIntent(); - if (intent == null) // when launched as LAUNCHER - return; - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - activity.finish(); - activity.overridePendingTransition(0, 0); - activity.startActivity(intent); - activity.overridePendingTransition(0, 0); - } - - /** - * Return the name of the language based on the locale. - * - * @param locale - * @return - */ - public String getName(String locale) { - String ret = nameMap.get(locale); - // if no match, try to return a more general name (i.e. English for - // en_IN) - if (ret == null && locale.contains("_")) - ret = nameMap.get(locale.split("_")[0]); - return ret; - } - - /** - * Return an array of the names of all the supported languages, sorted to - * match what is returned by {@link Languages#getSupportedLocales()}. - * - * @return - */ - public String[] getAllNames() { - return nameMap.values().toArray(new String[nameMap.size()]); - } - - /** - * Get sorted list of supported locales. - * - * @return - */ - public String[] getSupportedLocales() { - Set<String> keys = nameMap.keySet(); - return keys.toArray(new String[keys.size()]); - } -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/settings/LocaleHelper.java b/app-mini/src/main/java/org/torproject/android/mini/settings/LocaleHelper.java deleted file mode 100644 index e4b29be2..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/settings/LocaleHelper.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.torproject.android.mini.settings; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Build; -import org.torproject.android.service.util.Prefs; - -import java.util.Locale; - -/** - * This class is used to change your application locale and persist this change for the next time - * that your app is going to be used. - * <p/> - * You can also change the locale of your application on the fly by using the setLocale method. - * <p/> - * Created by gunhansancar on 07/10/15. - * https://gunhansancar.com/change-language-programmatically-in-android/ - */ -public class LocaleHelper { - - private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language"; - - public static Context onAttach(Context context) { - String lang = getPersistedData(context, Locale.getDefault().getLanguage()); - return setLocale(context, lang); - } - - public static Context onAttach(Context context, String defaultLanguage) { - String lang = getPersistedData(context, defaultLanguage); - return setLocale(context, lang); - } - - public static String getLanguage(Context context) { - return getPersistedData(context, Locale.getDefault().getLanguage()); - } - - public static Context setLocale(Context context, String language) { - persist(context, language); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return updateResources(context, language); - } - - return updateResourcesLegacy(context, language); - } - - private static String getPersistedData(Context context, String defaultLanguage) { - return Prefs.getDefaultLocale(); - } - - private static void persist(Context context, String language) { - Prefs.setDefaultLocale(language); - } - - @TargetApi(Build.VERSION_CODES.N) - private static Context updateResources(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - - Configuration configuration = context.getResources().getConfiguration(); - configuration.setLocale(locale); - configuration.setLayoutDirection(locale); - - return context.createConfigurationContext(configuration); - } - - @SuppressWarnings("deprecation") - private static Context updateResourcesLegacy(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - - Resources resources = context.getResources(); - - Configuration configuration = resources.getConfiguration(); - configuration.locale = locale; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - configuration.setLayoutDirection(locale); - } - - resources.updateConfiguration(configuration, resources.getDisplayMetrics()); - - return context; - } -} \ No newline at end of file diff --git a/app-mini/src/main/java/org/torproject/android/mini/settings/SettingsPreferences.java b/app-mini/src/main/java/org/torproject/android/mini/settings/SettingsPreferences.java deleted file mode 100644 index e5b5074b..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/settings/SettingsPreferences.java +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ -/* See LICENSE for licensing information */ - -package org.torproject.android.mini.settings; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import org.torproject.android.mini.R; - -public class SettingsPreferences extends PreferenceActivity { - private ListPreference prefLocale = null; - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preferences); - setNoPersonalizedLearningOnEditTextPreferences(); - getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS); - - prefLocale = (ListPreference) findPreference("pref_default_locale"); - - Languages languages = Languages.get(this); - prefLocale.setEntries(languages.getAllNames()); - prefLocale.setEntryValues(languages.getSupportedLocales()); - prefLocale.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - String language = (String) newValue; - Intent intentResult = new Intent(); - intentResult.putExtra("locale", language); - setResult(RESULT_OK, intentResult); - finish(); - return false; - } - }); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleHelper.onAttach(base)); - } - - private void setNoPersonalizedLearningOnEditTextPreferences() { - PreferenceScreen preferenceScreen = getPreferenceScreen(); - int categoryCount = preferenceScreen.getPreferenceCount(); - for (int i = 0; i < categoryCount; i++) { - Preference p = preferenceScreen.getPreference(i); - if (p instanceof PreferenceCategory) { - PreferenceCategory pc = (PreferenceCategory) p; - int preferenceCount = pc.getPreferenceCount(); - for (int j = 0; j < preferenceCount; j++) { - p = pc.getPreference(j); - if (p instanceof EditTextPreference) { - EditText editText = ((EditTextPreference) p).getEditText(); - editText.setImeOptions(editText.getImeOptions() | EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING); - } - } - } - } - } - -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/ui/NoPersonalizedLearningEditText.java b/app-mini/src/main/java/org/torproject/android/mini/ui/NoPersonalizedLearningEditText.java deleted file mode 100644 index 07d91429..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/ui/NoPersonalizedLearningEditText.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.torproject.android.mini.ui; - -import android.content.Context; -import androidx.appcompat.widget.AppCompatEditText; -import android.util.AttributeSet; -import android.view.inputmethod.EditorInfo; - -public class NoPersonalizedLearningEditText extends AppCompatEditText { - public NoPersonalizedLearningEditText(Context context, AttributeSet attrs) { - super(context, attrs); - setImeOptions(getImeOptions() | EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING); - } -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/ui/Rotate3dAnimation.java b/app-mini/src/main/java/org/torproject/android/mini/ui/Rotate3dAnimation.java deleted file mode 100644 index ac8de549..00000000 --- a/app-mini/src/main/java/org/torproject/android/mini/ui/Rotate3dAnimation.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.torproject.android.mini.ui; - -import android.graphics.Camera; -import android.graphics.Matrix; -import android.view.animation.Animation; -import android.view.animation.Transformation; - -/** - * An animation that rotates the view on the Y axis between two specified angles. - * This animation also adds a translation on the Z axis (depth) to improve the effect. - */ -public class Rotate3dAnimation extends Animation { - private final float mFromDegrees; - private final float mToDegrees; - private final float mCenterX; - private final float mCenterY; - private final float mDepthZ; - private final boolean mReverse; - private Camera mCamera; - - /** - * Creates a new 3D rotation on the Y axis. The rotation is defined by its - * start angle and its end angle. Both angles are in degrees. The rotation - * is performed around a center point on the 2D space, definied by a pair - * of X and Y coordinates, called centerX and centerY. When the animation - * starts, a translation on the Z axis (depth) is performed. The length - * of the translation can be specified, as well as whether the translation - * should be reversed in time. - * - * @param fromDegrees the start angle of the 3D rotation - * @param toDegrees the end angle of the 3D rotation - * @param centerX the X center of the 3D rotation - * @param centerY the Y center of the 3D rotation - * @param reverse true if the translation should be reversed, false otherwise - */ - public Rotate3dAnimation(float fromDegrees, float toDegrees, - float centerX, float centerY, float depthZ, boolean reverse) { - mFromDegrees = fromDegrees; - mToDegrees = toDegrees; - mCenterX = centerX; - mCenterY = centerY; - mDepthZ = depthZ; - mReverse = reverse; - } - - @Override - public void initialize(int width, int height, int parentWidth, int parentHeight) { - super.initialize(width, height, parentWidth, parentHeight); - mCamera = new Camera(); - } - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - final float fromDegrees = mFromDegrees; - float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); - - final float centerX = mCenterX; - final float centerY = mCenterY; - final Camera camera = mCamera; - - final Matrix matrix = t.getMatrix(); - - camera.save(); - if (mReverse) { - camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); - } else { - camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)); - } - camera.rotateY(degrees); - camera.getMatrix(matrix); - camera.restore(); - - matrix.preTranslate(-centerX, -centerY); - matrix.postTranslate(centerX, centerY); - } -} diff --git a/app-mini/src/main/java/org/torproject/android/mini/ui/onboarding/OnboardingActivity.java b/app-mini/src/main/java/org/torproject/android/mini/ui/onboarding/OnboardingActivity.java index bce4585a..56031c34 100644 --- a/app-mini/src/main/java/org/torproject/android/mini/ui/onboarding/OnboardingActivity.java +++ b/app-mini/src/main/java/org/torproject/android/mini/ui/onboarding/OnboardingActivity.java @@ -5,8 +5,9 @@ import android.os.Bundle; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.github.paolorotolo.appintro.AppIntro; + +import org.torproject.android.core.LocaleHelper; import org.torproject.android.mini.R; -import org.torproject.android.mini.settings.LocaleHelper;
public class OnboardingActivity extends AppIntro {
diff --git a/app-mini/src/main/res/layout/content_app_config.xml b/app-mini/src/main/res/layout/content_app_config.xml index 3a8c41a8..bdb56595 100644 --- a/app-mini/src/main/res/layout/content_app_config.xml +++ b/app-mini/src/main/res/layout/content_app_config.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".ui.AppConfigActivity" android:orientation="vertical" tools:showIn="@layout/activity_app_config" diff --git a/app/build.gradle b/app/build.gradle index 16656dc7..017315ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -125,6 +125,8 @@ dependencies { implementation 'com.google.android.material:material:1.1.0' implementation 'pl.bclogic:pulsator4droid:1.0.3' implementation 'com.github.apl-devs:appintro:v4.2.2' + implementation project(path: ':appcore') + implementation project(path: ':intentintegrator') androidTestImplementation "tools.fastlane:screengrab:1.2.0" implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' implementation 'com.android.volley:volley:1.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fa7a54d4..971fd52b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,7 +74,7 @@ android:theme="@android:style/Theme.Translucent" />
<activity - android:name=".settings.SettingsPreferences" + android:name=".core.ui.SettingsPreferencesActivity" android:label="@string/app_name" />
<activity @@ -143,7 +143,7 @@ </receiver>
<receiver - android:name=".OnBootReceiver" + android:name=".core.OnBootReceiver" android:enabled="true" android:exported="true"> <intent-filter> diff --git a/app/src/main/java/com/google/zxing/integration/android/IntentResult.java b/app/src/main/java/com/google/zxing/integration/android/IntentResult.java deleted file mode 100644 index 2469af92..00000000 --- a/app/src/main/java/com/google/zxing/integration/android/IntentResult.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.integration.android; - -/** - * <p>Encapsulates the result of a barcode scan invoked through {@link IntentIntegrator}.</p> - * - * @author Sean Owen - */ -public final class IntentResult { - - private final String contents; - private final String formatName; - private final byte[] rawBytes; - private final Integer orientation; - private final String errorCorrectionLevel; - - IntentResult() { - this(null, null, null, null, null); - } - - IntentResult(String contents, - String formatName, - byte[] rawBytes, - Integer orientation, - String errorCorrectionLevel) { - this.contents = contents; - this.formatName = formatName; - this.rawBytes = rawBytes; - this.orientation = orientation; - this.errorCorrectionLevel = errorCorrectionLevel; - } - - /** - * @return raw content of barcode - */ - public String getContents() { - return contents; - } - - /** - * @return name of format, like "QR_CODE", "UPC_A". See {@code BarcodeFormat} for more format names. - */ - public String getFormatName() { - return formatName; - } - - /** - * @return raw bytes of the barcode content, if applicable, or null otherwise - */ - public byte[] getRawBytes() { - return rawBytes; - } - - /** - * @return rotation of the image, in degrees, which resulted in a successful scan. May be null. - */ - public Integer getOrientation() { - return orientation; - } - - /** - * @return name of the error correction level used in the barcode, if applicable - */ - public String getErrorCorrectionLevel() { - return errorCorrectionLevel; - } - - @Override - public String toString() { - StringBuilder dialogText = new StringBuilder(100); - dialogText.append("Format: ").append(formatName).append('\n'); - dialogText.append("Contents: ").append(contents).append('\n'); - int rawBytesLength = rawBytes == null ? 0 : rawBytes.length; - dialogText.append("Raw bytes: (").append(rawBytesLength).append(" bytes)\n"); - dialogText.append("Orientation: ").append(orientation).append('\n'); - dialogText.append("EC level: ").append(errorCorrectionLevel).append('\n'); - return dialogText.toString(); - } - -} diff --git a/app/src/main/java/org/torproject/android/OnBootReceiver.java b/app/src/main/java/org/torproject/android/OnBootReceiver.java deleted file mode 100644 index b8d88e58..00000000 --- a/app/src/main/java/org/torproject/android/OnBootReceiver.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.torproject.android; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import org.torproject.android.service.OrbotService; -import org.torproject.android.service.TorServiceConstants; -import org.torproject.android.service.util.Prefs; - -public class OnBootReceiver extends BroadcastReceiver { - - private static boolean sReceivedBoot = false; - - @Override - public void onReceive(Context context, Intent intent) { - - if (Prefs.startOnBoot() && (!sReceivedBoot)) - { - startService(TorServiceConstants.ACTION_START_ON_BOOT, context); - sReceivedBoot = true; - } - } - - - private void startService (String action, Context context) - { - Intent intent = new Intent(context, OrbotService.class); - intent.setAction(action); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent); - } - else - { - context.startService(intent); - } - - } - - -} - diff --git a/app/src/main/java/org/torproject/android/OrbotApp.java b/app/src/main/java/org/torproject/android/OrbotApp.java index 7cb4317f..d037efa9 100644 --- a/app/src/main/java/org/torproject/android/OrbotApp.java +++ b/app/src/main/java/org/torproject/android/OrbotApp.java @@ -4,10 +4,10 @@ import android.app.Application; import android.content.Context; import android.content.res.Configuration;
+import org.torproject.android.core.LocaleHelper; import org.torproject.android.service.OrbotConstants; import org.torproject.android.service.util.Prefs; -import org.torproject.android.settings.Languages; -import org.torproject.android.settings.LocaleHelper; +import org.torproject.android.core.Languages;
import java.util.Locale;
@@ -26,7 +26,7 @@ public class OrbotApp extends Application implements OrbotConstants { @Override protected void attachBaseContext(Context base) { Prefs.setContext(base); - super.attachBaseContext(LocaleHelper.onAttach(base, Prefs.getDefaultLocale())); + super.attachBaseContext(LocaleHelper.onAttach(base)); }
@Override diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index 81631e9f..61b6333d 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -54,17 +54,17 @@ import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult;
import org.json.JSONArray; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.service.OrbotConstants; import org.torproject.android.service.OrbotService; import org.torproject.android.service.TorServiceConstants; import org.torproject.android.service.util.Prefs; import org.torproject.android.service.util.Utils; import org.torproject.android.service.vpn.VpnPrefs; -import org.torproject.android.settings.Languages; -import org.torproject.android.settings.LocaleHelper; -import org.torproject.android.settings.SettingsPreferences; +import org.torproject.android.core.Languages; +import org.torproject.android.core.ui.SettingsPreferencesActivity; import org.torproject.android.ui.AppManagerActivity; -import org.torproject.android.ui.Rotate3dAnimation; +import org.torproject.android.core.ui.Rotate3dAnimation; import org.torproject.android.ui.dialog.AboutDialogFragment; import org.torproject.android.ui.hiddenservices.ClientCookiesActivity; import org.torproject.android.ui.hiddenservices.HiddenServicesActivity; @@ -449,10 +449,10 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan if (item.getItemId() == R.id.menu_newnym) { requestNewTorIdentity(); } else if (item.getItemId() == R.id.menu_settings) { - Intent intent = new Intent(OrbotMainActivity.this, SettingsPreferences.class); + Intent intent = SettingsPreferencesActivity.createIntent(this, R.xml.preferences); startActivityForResult(intent, REQUEST_SETTINGS); } else if (item.getItemId() == R.id.menu_exit) { - doExit(); // exit appp + doExit(); // exit app } else if (item.getItemId() == R.id.menu_about) { new AboutDialogFragment().show(getSupportFragmentManager(), AboutDialogFragment.TAG); } else if (item.getItemId() == R.id.menu_scan) { diff --git a/app/src/main/java/org/torproject/android/settings/Languages.java b/app/src/main/java/org/torproject/android/settings/Languages.java deleted file mode 100644 index b9a76b91..00000000 --- a/app/src/main/java/org/torproject/android/settings/Languages.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.torproject.android.settings; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.ContextWrapper; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Build; -import android.text.TextUtils; -import android.util.DisplayMetrics; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -public class Languages { - - public static Locale defaultLocale; - public static final Locale TIBETAN = new Locale("bo"); - static final Locale localesToTest[] = { - Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, - Locale.ITALIAN, Locale.JAPANESE, Locale.KOREAN, - Locale.TRADITIONAL_CHINESE, Locale.SIMPLIFIED_CHINESE, - TIBETAN, new Locale("af"), new Locale("am"), - new Locale("ar"), new Locale("ay"), new Locale("az"), new Locale("bg"), - new Locale("bn"), new Locale("ca"), new Locale("cs"), - new Locale("da"), new Locale("el"), new Locale("es"), - new Locale("et"), new Locale("eu"), new Locale("fa"), - new Locale("fi"), new Locale("gl"), new Locale("hi"), - new Locale("hr"), new Locale("hu"), new Locale("hy"), - new Locale("in"), new Locale("hy"), new Locale("in"), - new Locale("is"), new Locale("it"), new Locale("iw"), - new Locale("ka"), new Locale("kk"), new Locale("km"), - new Locale("kn"), new Locale("ky"), new Locale("lo"), - new Locale("lt"), new Locale("lv"), new Locale("mk"), - new Locale("ml"), new Locale("mn"), new Locale("mr"), - new Locale("ms"), new Locale("my"), new Locale("nb"), - new Locale("ne"), new Locale("nl"), new Locale("pl"), - new Locale("pt"), new Locale("rm"), new Locale("ro"), - new Locale("ru"), new Locale("si"), new Locale("sk"), - new Locale("sl"), new Locale("sn"), new Locale("sr"), - new Locale("sv"), new Locale("sw"), new Locale("ta"), - new Locale("te"), new Locale("th"), new Locale("tl"), - new Locale("tr"), new Locale("uk"), new Locale("ur"), - new Locale("uz"), new Locale("vi"), new Locale("zu"), - }; - - private static final String USE_SYSTEM_DEFAULT = ""; - private static final String defaultString = "Use System Default"; - - private static Locale locale; - private static Languages singleton; - private static Class<?> clazz; - private static int resId; - private static Map<String, String> tmpMap = new TreeMap<String, String>(); - private static Map<String, String> nameMap; - - - private Languages(Activity activity) { - - - AssetManager assets = activity.getAssets(); - Configuration config = activity.getResources().getConfiguration(); - // Resources() requires DisplayMetrics, but they are only needed for drawables - DisplayMetrics ignored = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(ignored); - Resources resources; - Set<Locale> localeSet = new LinkedHashSet<>(); - for (Locale locale : localesToTest) { - resources = new Resources(assets, ignored, config); - if (!TextUtils.equals(defaultString, resources.getString(resId)) - || locale.equals(Locale.ENGLISH)) - localeSet.add(locale); - } - - for (Locale locale : localeSet) { - if (locale.equals(TIBETAN)) { - // include English name for devices without Tibetan font support - tmpMap.put(TIBETAN.toString(), "Tibetan བོད་སྐད།"); // Tibetan - } else if (locale.equals(Locale.SIMPLIFIED_CHINESE)) { - tmpMap.put(Locale.SIMPLIFIED_CHINESE.toString(), "中文 (中国)"); // Chinese (China) - } else if (locale.equals(Locale.TRADITIONAL_CHINESE)) { - tmpMap.put(Locale.TRADITIONAL_CHINESE.toString(), "中文 (台灣)"); // Chinese (Taiwan) - } else { - tmpMap.put(locale.toString(), locale.getDisplayLanguage(locale)); - } - } - - /* USE_SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */ - // localeSet.add(null); - // tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId)); - nameMap = Collections.unmodifiableMap(tmpMap); - } - - /** - * Get the instance of {@link Languages} to work with, providing the - * {@link Activity} that is will be working as part of, as well as the - * {@code resId} that has the exact string "Use System Default", - * i.e. {@code R.string.use_system_default}. - * <p/> - * That string resource {@code resId} is also used to find the supported - * translations: if an included translation has a translated string that - * matches that {@code resId}, then that language will be included as a - * supported language. - * - * @param clazz the {@link Class} of the default {@code Activity}, - * usually the main {@code Activity} from where the - * Settings is launched from. - * @param resId the string resource ID to for the string "Use System Default", - * e.g. {@code R.string.use_system_default} - * @return - */ - public static void setup(Class<?> clazz, int resId) { - defaultLocale = Locale.getDefault(); - - if (Languages.clazz == null) { - Languages.clazz = clazz; - Languages.resId = resId; - } else { - throw new RuntimeException("Languages singleton was already initialized, duplicate call to Languages.setup()!"); - } - } - - /** - * Get the singleton to work with. - * - * @param activity the {@link Activity} this is working as part of - * @return - */ - public static Languages get(Activity activity) { - if (singleton == null) { - singleton = new Languages(activity); - } - return singleton; - } - - @SuppressLint("NewApi") - public static void setLanguage(final ContextWrapper contextWrapper, String language, boolean refresh) { - if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) { - return; // already configured - } else if (language == null || language == USE_SYSTEM_DEFAULT) { - locale = defaultLocale; - } else { - /* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */ - String localeSplit[] = language.split("_"); - if (localeSplit.length > 1) { - locale = new Locale(localeSplit[0], localeSplit[1]); - } else { - locale = new Locale(language); - } - } - - setLocale(contextWrapper, locale); - - } - - @SuppressWarnings("deprecation") - private static void setLocale(final ContextWrapper contextWrapper, Locale locale){ - Resources resources = contextWrapper.getResources(); - Configuration configuration = resources.getConfiguration(); - DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ - configuration.setLocale(locale); - contextWrapper.getApplicationContext().createConfigurationContext(configuration); - } - else{ - configuration.locale=locale; - resources.updateConfiguration(configuration,displayMetrics); - } - } - - /** - * Return an array of the names of all the supported languages, sorted to - * match what is returned by {@link Languages#getSupportedLocales()}. - * - * @return - */ - public String[] getAllNames() { - return nameMap.values().toArray(new String[nameMap.size()]); - } - - /** - * Get sorted list of supported locales. - * - * @return - */ - public String[] getSupportedLocales() { - Set<String> keys = nameMap.keySet(); - return keys.toArray(new String[keys.size()]); - } -} diff --git a/app/src/main/java/org/torproject/android/settings/LocaleHelper.java b/app/src/main/java/org/torproject/android/settings/LocaleHelper.java deleted file mode 100644 index 4fb9e833..00000000 --- a/app/src/main/java/org/torproject/android/settings/LocaleHelper.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.torproject.android.settings; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Build; -import org.torproject.android.service.util.Prefs; - -import java.util.Locale; - -/** - * This class is used to change your application locale and persist this change for the next time - * that your app is going to be used. - * <p/> - * You can also change the locale of your application on the fly by using the setLocale method. - * <p/> - * Created by gunhansancar on 07/10/15. - * https://gunhansancar.com/change-language-programmatically-in-android/ - */ -public class LocaleHelper { - - public static Context onAttach(Context context) { - String lang = getPersistedData(context, Locale.getDefault().getLanguage()); - return setLocale(context, lang); - } - - public static Context onAttach(Context context, String defaultLanguage) { - String lang = getPersistedData(context, defaultLanguage); - return setLocale(context, lang); - } - - public static Context setLocale(Context context, String language) { - persist(context, language); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return updateResources(context, language); - } - - return updateResourcesLegacy(context, language); - } - - private static String getPersistedData(Context context, String defaultLanguage) { - return Prefs.getDefaultLocale(); - } - - private static void persist(Context context, String language) { - Prefs.setDefaultLocale(language); - } - - @TargetApi(Build.VERSION_CODES.N) - private static Context updateResources(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - - Configuration configuration = context.getResources().getConfiguration(); - configuration.setLocale(locale); - configuration.setLayoutDirection(locale); - - return context.createConfigurationContext(configuration); - } - - @SuppressWarnings("deprecation") - private static Context updateResourcesLegacy(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - - Resources resources = context.getResources(); - - Configuration configuration = resources.getConfiguration(); - configuration.locale = locale; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - configuration.setLayoutDirection(locale); - } - - resources.updateConfiguration(configuration, resources.getDisplayMetrics()); - - return context; - } -} \ No newline at end of file diff --git a/app/src/main/java/org/torproject/android/settings/SettingsPreferences.java b/app/src/main/java/org/torproject/android/settings/SettingsPreferences.java deleted file mode 100644 index 4279fd65..00000000 --- a/app/src/main/java/org/torproject/android/settings/SettingsPreferences.java +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ -/* See LICENSE for licensing information */ - -package org.torproject.android.settings; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import org.torproject.android.R; - -public class SettingsPreferences extends PreferenceActivity { - private ListPreference prefLocale = null; - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preferences); - setNoPersonalizedLearningOnEditTextPreferences(); - getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS); - - prefLocale = (ListPreference) findPreference("pref_default_locale"); - - Languages languages = Languages.get(this); - prefLocale.setEntries(languages.getAllNames()); - prefLocale.setEntryValues(languages.getSupportedLocales()); - prefLocale.setOnPreferenceChangeListener((preference, newValue) -> { - String language = (String) newValue; - Intent intentResult = new Intent(); - intentResult.putExtra("locale", language); - setResult(RESULT_OK, intentResult); - finish(); - return false; - }); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleHelper.onAttach(base)); - } - - private void setNoPersonalizedLearningOnEditTextPreferences() { - PreferenceScreen preferenceScreen = getPreferenceScreen(); - int categoryCount = preferenceScreen.getPreferenceCount(); - for (int i = 0; i < categoryCount; i++) { - Preference p = preferenceScreen.getPreference(i); - if (p instanceof PreferenceCategory) { - PreferenceCategory pc = (PreferenceCategory) p; - int preferenceCount = pc.getPreferenceCount(); - for (int j = 0; j < preferenceCount; j++) { - p = pc.getPreference(j); - if (p instanceof EditTextPreference) { - EditText editText = ((EditTextPreference) p).getEditText(); - editText.setImeOptions(editText.getImeOptions() | EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING); - } - } - } - } - } - -} diff --git a/app/src/main/java/org/torproject/android/ui/NoPersonalizedLearningEditText.java b/app/src/main/java/org/torproject/android/ui/NoPersonalizedLearningEditText.java deleted file mode 100644 index 7a21c7c5..00000000 --- a/app/src/main/java/org/torproject/android/ui/NoPersonalizedLearningEditText.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.torproject.android.ui; - -import android.content.Context; -import androidx.appcompat.widget.AppCompatEditText; -import android.util.AttributeSet; -import android.view.inputmethod.EditorInfo; - -public class NoPersonalizedLearningEditText extends AppCompatEditText { - public NoPersonalizedLearningEditText(Context context, AttributeSet attrs) { - super(context, attrs); - setImeOptions(getImeOptions() | EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING); - } -} diff --git a/app/src/main/java/org/torproject/android/ui/Rotate3dAnimation.java b/app/src/main/java/org/torproject/android/ui/Rotate3dAnimation.java deleted file mode 100644 index 7829d2db..00000000 --- a/app/src/main/java/org/torproject/android/ui/Rotate3dAnimation.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.torproject.android.ui; - -import android.graphics.Camera; -import android.graphics.Matrix; -import android.view.animation.Animation; -import android.view.animation.Transformation; - -/** - * An animation that rotates the view on the Y axis between two specified angles. - * This animation also adds a translation on the Z axis (depth) to improve the effect. - */ -public class Rotate3dAnimation extends Animation { - private final float mFromDegrees; - private final float mToDegrees; - private final float mCenterX; - private final float mCenterY; - private final float mDepthZ; - private final boolean mReverse; - private Camera mCamera; - - /** - * Creates a new 3D rotation on the Y axis. The rotation is defined by its - * start angle and its end angle. Both angles are in degrees. The rotation - * is performed around a center point on the 2D space, definied by a pair - * of X and Y coordinates, called centerX and centerY. When the animation - * starts, a translation on the Z axis (depth) is performed. The length - * of the translation can be specified, as well as whether the translation - * should be reversed in time. - * - * @param fromDegrees the start angle of the 3D rotation - * @param toDegrees the end angle of the 3D rotation - * @param centerX the X center of the 3D rotation - * @param centerY the Y center of the 3D rotation - * @param reverse true if the translation should be reversed, false otherwise - */ - public Rotate3dAnimation(float fromDegrees, float toDegrees, - float centerX, float centerY, float depthZ, boolean reverse) { - mFromDegrees = fromDegrees; - mToDegrees = toDegrees; - mCenterX = centerX; - mCenterY = centerY; - mDepthZ = depthZ; - mReverse = reverse; - } - - @Override - public void initialize(int width, int height, int parentWidth, int parentHeight) { - super.initialize(width, height, parentWidth, parentHeight); - mCamera = new Camera(); - } - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - final float fromDegrees = mFromDegrees; - float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); - - final float centerX = mCenterX; - final float centerY = mCenterY; - final Camera camera = mCamera; - - final Matrix matrix = t.getMatrix(); - - camera.save(); - if (mReverse) { - camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); - } else { - camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)); - } - camera.rotateY(degrees); - camera.getMatrix(matrix); - camera.restore(); - - matrix.preTranslate(-centerX, -centerY); - matrix.postTranslate(centerX, centerY); - } -} diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java index 0ed20f57..c5f8a5e1 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java @@ -20,7 +20,7 @@ import com.google.zxing.integration.android.IntentResult; import org.json.JSONException; import org.json.JSONObject; import org.torproject.android.R; -import org.torproject.android.settings.LocaleHelper; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.ui.hiddenservices.adapters.ClientCookiesAdapter; import org.torproject.android.ui.hiddenservices.dialogs.AddCookieDialog; import org.torproject.android.ui.hiddenservices.dialogs.CookieActionsDialog; diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java index 8ea67ec7..bfd29645 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java @@ -24,7 +24,7 @@ import android.widget.ListView; import android.widget.Spinner;
import org.torproject.android.R; -import org.torproject.android.settings.LocaleHelper; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.ui.hiddenservices.adapters.OnionListAdapter; import org.torproject.android.ui.hiddenservices.dialogs.HSActionsDialog; import org.torproject.android.ui.hiddenservices.dialogs.HSDataDialog; diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java index 8efa47d3..67918d13 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java @@ -13,7 +13,7 @@ import org.torproject.android.R; import org.torproject.android.service.TorServiceConstants; import org.torproject.android.ui.hiddenservices.providers.CookieContentProvider; import org.torproject.android.ui.hiddenservices.providers.HSContentProvider; -import org.torproject.android.ui.hiddenservices.storage.ExternalStorage; +import org.torproject.android.core.ExternalStorage;
import java.io.File; import java.io.FileInputStream; diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectCookieBackupDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectCookieBackupDialog.java index 120b0693..03f7b506 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectCookieBackupDialog.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectCookieBackupDialog.java @@ -10,7 +10,7 @@ import android.widget.ListView; import org.torproject.android.R; import org.torproject.android.ui.hiddenservices.adapters.BackupAdapter; import org.torproject.android.ui.hiddenservices.backup.BackupUtils; -import org.torproject.android.ui.hiddenservices.storage.ExternalStorage; +import org.torproject.android.core.ExternalStorage;
import java.io.File; import java.util.ArrayList; diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectHSBackupDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectHSBackupDialog.java index 6f02f872..642c5c17 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectHSBackupDialog.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectHSBackupDialog.java @@ -10,7 +10,7 @@ import android.widget.ListView; import org.torproject.android.R; import org.torproject.android.ui.hiddenservices.adapters.BackupAdapter; import org.torproject.android.ui.hiddenservices.backup.BackupUtils; -import org.torproject.android.ui.hiddenservices.storage.ExternalStorage; +import org.torproject.android.core.ExternalStorage;
import java.io.File; import java.util.ArrayList; diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/ExternalStorage.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/ExternalStorage.java deleted file mode 100644 index f3780f87..00000000 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/ExternalStorage.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.torproject.android.ui.hiddenservices.storage; - -import android.os.Environment; - -import java.io.File; - -public class ExternalStorage { - private static final String ORBOT_BACKUPS_DIR = "Orbot"; - - public static File getOrCreateBackupDir() { - if (!isExternalStorageWritable()) - return null; - - File dir = new File(Environment.getExternalStorageDirectory(), ORBOT_BACKUPS_DIR); - - if (!dir.isDirectory() && !dir.mkdirs()) - return null; - - return dir; - } - - /* Checks if external storage is available for read and write */ - private static boolean isExternalStorageWritable() { - String state = Environment.getExternalStorageState(); - return Environment.MEDIA_MOUNTED.equals(state); - } - -} diff --git a/app/src/main/java/org/torproject/android/ui/onboarding/BridgeWizardActivity.java b/app/src/main/java/org/torproject/android/ui/onboarding/BridgeWizardActivity.java index be8ab1bf..d8f35f86 100644 --- a/app/src/main/java/org/torproject/android/ui/onboarding/BridgeWizardActivity.java +++ b/app/src/main/java/org/torproject/android/ui/onboarding/BridgeWizardActivity.java @@ -8,7 +8,6 @@ import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; import android.view.View; -import android.widget.CompoundButton; import android.widget.RadioButton; import android.widget.TextView;
@@ -18,9 +17,8 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar;
import org.torproject.android.R; -import org.torproject.android.service.OrbotService; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.service.util.Prefs; -import org.torproject.android.settings.LocaleHelper;
import java.io.BufferedReader; import java.io.IOException; diff --git a/app/src/main/java/org/torproject/android/ui/onboarding/OnboardingActivity.java b/app/src/main/java/org/torproject/android/ui/onboarding/OnboardingActivity.java index 8e796724..7868faf5 100644 --- a/app/src/main/java/org/torproject/android/ui/onboarding/OnboardingActivity.java +++ b/app/src/main/java/org/torproject/android/ui/onboarding/OnboardingActivity.java @@ -11,8 +11,8 @@ import androidx.fragment.app.Fragment; import com.github.paolorotolo.appintro.AppIntro;
import org.torproject.android.R; +import org.torproject.android.core.LocaleHelper; import org.torproject.android.service.util.Prefs; -import org.torproject.android.settings.LocaleHelper; import org.torproject.android.ui.AppManagerActivity; import org.torproject.android.ui.hiddenservices.permissions.PermissionManager;
diff --git a/app/src/main/res/layout/layout_add_client_cookie_dialog.xml b/app/src/main/res/layout/layout_add_client_cookie_dialog.xml index 2f4b9885..c4725ff3 100644 --- a/app/src/main/res/layout/layout_add_client_cookie_dialog.xml +++ b/app/src/main/res/layout/layout_add_client_cookie_dialog.xml @@ -15,7 +15,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Widget.PopupMenu.Small" android:paddingLeft="5dp" />
- <org.torproject.android.ui.NoPersonalizedLearningEditText + <org.torproject.android.core.ui.NoPersonalizedLearningEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" @@ -29,7 +29,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Widget.PopupMenu.Small" android:paddingLeft="5dp" />
- <org.torproject.android.ui.NoPersonalizedLearningEditText + <org.torproject.android.core.ui.NoPersonalizedLearningEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" diff --git a/app/src/main/res/layout/layout_hs_data_dialog.xml b/app/src/main/res/layout/layout_hs_data_dialog.xml index a4ac590e..cf390d31 100644 --- a/app/src/main/res/layout/layout_hs_data_dialog.xml +++ b/app/src/main/res/layout/layout_hs_data_dialog.xml @@ -15,7 +15,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Widget.PopupMenu.Small" android:paddingLeft="5dp" />
- <org.torproject.android.ui.NoPersonalizedLearningEditText + <org.torproject.android.core.ui.NoPersonalizedLearningEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" @@ -29,7 +29,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Widget.PopupMenu.Small" android:paddingLeft="5dp" />
- <org.torproject.android.ui.NoPersonalizedLearningEditText + <org.torproject.android.core.ui.NoPersonalizedLearningEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" @@ -43,7 +43,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Widget.PopupMenu.Small" android:paddingLeft="5dp" />
- <org.torproject.android.ui.NoPersonalizedLearningEditText + <org.torproject.android.core.ui.NoPersonalizedLearningEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" diff --git a/appcore/.gitignore b/appcore/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/appcore/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/appcore/build.gradle b/appcore/build.gradle new file mode 100644 index 00000000..701ce2bf --- /dev/null +++ b/appcore/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.1' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation project(path: ':orbotservice') + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + +} \ No newline at end of file diff --git a/appcore/consumer-rules.pro b/appcore/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/appcore/proguard-rules.pro b/appcore/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/appcore/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/appcore/src/androidTest/java/org/torproject/android/core/ExampleInstrumentedTest.kt b/appcore/src/androidTest/java/org/torproject/android/core/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..b7e9cad1 --- /dev/null +++ b/appcore/src/androidTest/java/org/torproject/android/core/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package org.torproject.android.core + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("org.torproject.android.core.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/appcore/src/main/AndroidManifest.xml b/appcore/src/main/AndroidManifest.xml new file mode 100644 index 00000000..64220dd7 --- /dev/null +++ b/appcore/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.torproject.android.core"> +</manifest> \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/ExternalStorage.kt b/appcore/src/main/java/org/torproject/android/core/ExternalStorage.kt new file mode 100644 index 00000000..77493195 --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/ExternalStorage.kt @@ -0,0 +1,15 @@ +package org.torproject.android.core + +import android.os.Environment +import java.io.File + +object ExternalStorage { + private const val ORBOT_BACKUPS_DIR = "Orbot" + @JvmStatic + fun getOrCreateBackupDir(): File? { + // Checks if external storage is available for read and write + if (Environment.MEDIA_MOUNTED != Environment.getExternalStorageState()) return null + val dir = File(Environment.getExternalStorageDirectory(), ORBOT_BACKUPS_DIR) + return if (!dir.isDirectory && !dir.mkdirs()) null else dir + } +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/Languages.kt b/appcore/src/main/java/org/torproject/android/core/Languages.kt new file mode 100644 index 00000000..a76a816b --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/Languages.kt @@ -0,0 +1,174 @@ +package org.torproject.android.core + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.ContextWrapper +import android.content.res.Resources +import android.os.Build +import android.text.TextUtils +import android.util.DisplayMetrics +import java.util.* + +class Languages private constructor(activity: Activity) { + /** + * Return an array of the names of all the supported languages, sorted to + * match what is returned by [Languages.supportedLocales]. + * + * @return + */ + val allNames: Array<String> + get() = nameMap.values.toTypedArray() + + val supportedLocales: Array<String> + get() { + val keys = nameMap.keys + return keys.toTypedArray() + } + + companion object { + private var defaultLocale: Locale? = null + val TIBETAN = Locale("bo") + val localesToTest = arrayOf( + Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, + Locale.ITALIAN, Locale.JAPANESE, Locale.KOREAN, + Locale.TRADITIONAL_CHINESE, Locale.SIMPLIFIED_CHINESE, + TIBETAN, Locale("af"), Locale("am"), + Locale("ar"), Locale("ay"), Locale("az"), Locale("bg"), + Locale("bn"), Locale("ca"), Locale("cs"), + Locale("da"), Locale("el"), Locale("es"), + Locale("et"), Locale("eu"), Locale("fa"), + Locale("fi"), Locale("gl"), Locale("hi"), + Locale("hr"), Locale("hu"), Locale("hy"), + Locale("in"), Locale("hy"), Locale("in"), + Locale("is"), Locale("it"), Locale("iw"), + Locale("ka"), Locale("kk"), Locale("km"), + Locale("kn"), Locale("ky"), Locale("lo"), + Locale("lt"), Locale("lv"), Locale("mk"), + Locale("ml"), Locale("mn"), Locale("mr"), + Locale("ms"), Locale("my"), Locale("nb"), + Locale("ne"), Locale("nl"), Locale("pl"), + Locale("pt"), Locale("rm"), Locale("ro"), + Locale("ru"), Locale("si"), Locale("sk"), + Locale("sl"), Locale("sn"), Locale("sr"), + Locale("sv"), Locale("sw"), Locale("ta"), + Locale("te"), Locale("th"), Locale("tl"), + Locale("tr"), Locale("uk"), Locale("ur"), + Locale("uz"), Locale("vi"), Locale("zu")) + private const val USE_SYSTEM_DEFAULT = "" + private const val defaultString = "Use System Default" + private var locale: Locale? = null + private var singleton: Languages? = null + private var clazz: Class<*>? = null + private var resId = 0 + private val tmpMap: MutableMap<String, String> = TreeMap() + private lateinit var nameMap: Map<String, String> + + /** + * Get the instance of [Languages] to work with, providing the + * [Activity] that is will be working as part of, as well as the + * `resId` that has the exact string "Use System Default", + * i.e. `R.string.use_system_default`. + * + * + * That string resource `resId` is also used to find the supported + * translations: if an included translation has a translated string that + * matches that `resId`, then that language will be included as a + * supported language. + * + * @param clazz the [Class] of the default `Activity`, + * usually the main `Activity` from where the + * Settings is launched from. + * @param resId the string resource ID to for the string "Use System Default", + * e.g. `R.string.use_system_default` + * @return + */ + @JvmStatic + fun setup(clazz: Class<*>?, resId: Int) { + defaultLocale = Locale.getDefault() + if (Companion.clazz == null) { + Companion.clazz = clazz + Companion.resId = resId + } else { + throw RuntimeException("Languages singleton was already initialized, duplicate call to Languages.setup()!") + } + } + + /** + * Get the singleton to work with. + * + * @param activity the [Activity] this is working as part of + * @return + */ + @JvmStatic + operator fun get(activity: Activity): Languages? { + if (singleton == null) { + singleton = Languages(activity) + } + return singleton + } + + @JvmStatic + @SuppressLint("NewApi") + fun setLanguage(contextWrapper: ContextWrapper, language: String?, refresh: Boolean) { + locale = if (locale != null && TextUtils.equals(locale!!.language, language) && !refresh) { + return // already configured + } else if (language == null || language === USE_SYSTEM_DEFAULT) { + defaultLocale + } else { + /* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */ + val localeSplit = language.split("_".toRegex()).toTypedArray() + if (localeSplit.size > 1) { + Locale(localeSplit[0], localeSplit[1]) + } else { + Locale(language) + } + } + setLocale(contextWrapper, locale) + } + + private fun setLocale(contextWrapper: ContextWrapper, locale: Locale?) { + val resources = contextWrapper.resources + val configuration = resources.configuration + val displayMetrics = resources.displayMetrics + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLocale(locale) + contextWrapper.applicationContext.createConfigurationContext(configuration) + } else { + configuration.locale = locale + resources.updateConfiguration(configuration, displayMetrics) + } + } + } + + init { + val assets = activity.assets + val config = activity.resources.configuration + // Resources() requires DisplayMetrics, but they are only needed for drawables + val ignored = DisplayMetrics() + activity.windowManager.defaultDisplay.getMetrics(ignored) + var resources: Resources + val localeSet: MutableSet<Locale> = LinkedHashSet() + for (locale in localesToTest) { + resources = Resources(assets, ignored, config) + if (!TextUtils.equals(defaultString, resources.getString(resId)) + || locale == Locale.ENGLISH) localeSet.add(locale) + } + for (locale in localeSet) { + if (locale == TIBETAN) { + // include English name for devices without Tibetan font support + tmpMap[TIBETAN.toString()] = "Tibetan བོད་སྐད།" // Tibetan + } else if (locale == Locale.SIMPLIFIED_CHINESE) { + tmpMap[Locale.SIMPLIFIED_CHINESE.toString()] = "中文 (中国)" // Chinese (China) + } else if (locale == Locale.TRADITIONAL_CHINESE) { + tmpMap[Locale.TRADITIONAL_CHINESE.toString()] = "中文 (台灣)" // Chinese (Taiwan) + } else { + tmpMap[locale.toString()] = locale.getDisplayLanguage(locale) + } + } + + /* USE_SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */ + // localeSet.add(null); + // tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId)); + nameMap = Collections.unmodifiableMap(tmpMap) + } +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/LocaleHelper.kt b/appcore/src/main/java/org/torproject/android/core/LocaleHelper.kt new file mode 100644 index 00000000..271e1c8a --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/LocaleHelper.kt @@ -0,0 +1,55 @@ +package org.torproject.android.core + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import org.torproject.android.service.util.Prefs +import java.util.* + +/** + * This class is used to change your application locale and persist this change for the next time + * that your app is going to be used. + * + * + * You can also change the locale of your application on the fly by using the setLocale method. + * + * + * Created by gunhansancar on 07/10/15. + * https://gunhansancar.com/change-language-programmatically-in-android/ + */ +object LocaleHelper { + @JvmStatic + fun onAttach(context: Context): Context = setLocale(context, Prefs.getDefaultLocale()) + + private fun setLocale(context: Context, language: String): Context { + Prefs.setDefaultLocale(language) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + updateResources(context, language) + else + updateResourcesLegacy(context, language) + } + + @TargetApi(Build.VERSION_CODES.N) + private fun updateResources(context: Context, language: String): Context { + val locale = Locale(language) + Locale.setDefault(locale) + val configuration = context.resources.configuration + configuration.setLocale(locale) + configuration.setLayoutDirection(locale) + return context.createConfigurationContext(configuration) + } + + @SuppressWarnings("deprecation") + private fun updateResourcesLegacy(context: Context, language: String): Context { + val locale = Locale(language) + Locale.setDefault(locale) + val resources = context.resources + val configuration = resources.configuration + configuration.locale = locale + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLayoutDirection(locale) + } + resources.updateConfiguration(configuration, resources.displayMetrics) + return context + } +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/OnBootReceiver.kt b/appcore/src/main/java/org/torproject/android/core/OnBootReceiver.kt new file mode 100644 index 00000000..3602a249 --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/OnBootReceiver.kt @@ -0,0 +1,31 @@ +package org.torproject.android.core + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Build +import org.torproject.android.service.OrbotService +import org.torproject.android.service.TorServiceConstants +import org.torproject.android.service.util.Prefs + +class OnBootReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (Prefs.startOnBoot() && !sReceivedBoot) { + startService(TorServiceConstants.ACTION_START_ON_BOOT, context) + sReceivedBoot = true + } + } + + private fun startService(action: String, context: Context) { + val intent = Intent(context, OrbotService::class.java).apply { this.action = action } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + context.startForegroundService(intent) + else { + context.startService(intent) + } + } + + companion object { + private var sReceivedBoot = false + } +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/ui/NoPersonalizedLearningEditText.kt b/appcore/src/main/java/org/torproject/android/core/ui/NoPersonalizedLearningEditText.kt new file mode 100644 index 00000000..d9e7dfb7 --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/ui/NoPersonalizedLearningEditText.kt @@ -0,0 +1,12 @@ +package org.torproject.android.core.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.inputmethod.EditorInfo +import androidx.appcompat.widget.AppCompatEditText + +class NoPersonalizedLearningEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) { + init { + imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING + } +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/ui/Rotate3dAnimation.kt b/appcore/src/main/java/org/torproject/android/core/ui/Rotate3dAnimation.kt new file mode 100644 index 00000000..3e4a484b --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/ui/Rotate3dAnimation.kt @@ -0,0 +1,48 @@ +package org.torproject.android.core.ui + +import android.graphics.Camera +import android.view.animation.Animation +import android.view.animation.Transformation + +/** + * An animation that rotates the view on the Y axis between two specified angles. + * This animation also adds a translation on the Z axis (depth) to improve the effect. + */ +class Rotate3dAnimation +/** + * Creates a new 3D rotation on the Y axis. The rotation is defined by its + * start angle and its end angle. Both angles are in degrees. The rotation + * is performed around a center point on the 2D space, defined by a pair + * of X and Y coordinates, called centerX and centerY. When the animation + * starts, a translation on the Z axis (depth) is performed. The length + * of the translation can be specified, as well as whether the translation + * should be reversed in time. + * + * @param fromDegrees the start angle of the 3D rotation + * @param toDegrees the end angle of the 3D rotation + * @param centerX the X center of the 3D rotation + * @param centerY the Y center of the 3D rotation + * @param reverse true if the translation should be reversed, false otherwise + */(private val mFromDegrees: Float, private val mToDegrees: Float, + private val mCenterX: Float, private val mCenterY: Float, private val mDepthZ: Float, private val mReverse: Boolean) : Animation() { + private lateinit var mCamera: Camera + override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) { + super.initialize(width, height, parentWidth, parentHeight) + mCamera = Camera() + } + + override fun applyTransformation(interpolatedTime: Float, t: Transformation) { + val degrees = mFromDegrees + (mToDegrees - mFromDegrees) * interpolatedTime + with(mCamera) { + save() + if (mReverse) translate(0.0f, 0.0f, mDepthZ * interpolatedTime) + else translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)) + rotateY(degrees) + getMatrix(t.matrix) + restore() + } + t.matrix.preTranslate(-mCenterX, -mCenterY) + t.matrix.postTranslate(mCenterX, mCenterY) + } + +} \ No newline at end of file diff --git a/appcore/src/main/java/org/torproject/android/core/ui/SettingsPreferencesActivity.kt b/appcore/src/main/java/org/torproject/android/core/ui/SettingsPreferencesActivity.kt new file mode 100644 index 00000000..a8eaf644 --- /dev/null +++ b/appcore/src/main/java/org/torproject/android/core/ui/SettingsPreferencesActivity.kt @@ -0,0 +1,65 @@ +/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ /* See LICENSE for licensing information */ +package org.torproject.android.core.ui + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.preference.* +import android.preference.Preference.OnPreferenceChangeListener +import android.view.inputmethod.EditorInfo +import androidx.annotation.XmlRes +import org.torproject.android.core.Languages +import org.torproject.android.core.LocaleHelper + +class SettingsPreferencesActivity : PreferenceActivity() { + private var prefLocale: ListPreference? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(intent.getIntExtra(BUNDLE_KEY_PREFERENCES_XML, 0)) + setNoPersonalizedLearningOnEditTextPreferences() + preferenceManager.sharedPreferencesMode = MODE_MULTI_PROCESS + prefLocale = findPreference("pref_default_locale") as ListPreference + val languages = Languages[this] + prefLocale?.entries = languages!!.allNames + prefLocale?.entryValues = languages.supportedLocales + prefLocale?.onPreferenceChangeListener = OnPreferenceChangeListener { _: Preference?, newValue: Any? -> + val language = newValue as String? + val intentResult = Intent() + intentResult.putExtra("locale", language) + setResult(RESULT_OK, intentResult) + finish() + false + } + } + + override fun attachBaseContext(newBase: Context) = super.attachBaseContext(LocaleHelper.onAttach(newBase)) + + private fun setNoPersonalizedLearningOnEditTextPreferences() { + val preferenceScreen = preferenceScreen + val categoryCount = preferenceScreen.preferenceCount + for (i in 0 until categoryCount) { + var p = preferenceScreen.getPreference(i) + if (p is PreferenceCategory) { + val pc = p + val preferenceCount = pc.preferenceCount + for (j in 0 until preferenceCount) { + p = pc.getPreference(j) + if (p is EditTextPreference) { + val editText = p.editText + editText.imeOptions = editText.imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING + } + } + } + } + } + + companion object { + private const val BUNDLE_KEY_PREFERENCES_XML = "prefxml" + @JvmStatic + fun createIntent(context: Context?, @XmlRes xmlPrefId: Int): Intent { + val intent = Intent(context, SettingsPreferencesActivity::class.java) + intent.putExtra(BUNDLE_KEY_PREFERENCES_XML, xmlPrefId) + return intent + } + } +} \ No newline at end of file diff --git a/appcore/src/test/java/org/torproject/android/core/ExampleUnitTest.kt b/appcore/src/test/java/org/torproject/android/core/ExampleUnitTest.kt new file mode 100644 index 00000000..9b2de166 --- /dev/null +++ b/appcore/src/test/java/org/torproject/android/core/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package org.torproject.android.core + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 031c2bfc..51012a87 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,15 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext { + kotlin_version = '1.3.72' + } repositories { jcenter() google() } dependencies { classpath 'com.android.tools.build:gradle:4.0.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }
diff --git a/intentintegrator/.gitignore b/intentintegrator/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/intentintegrator/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/intentintegrator/build.gradle b/intentintegrator/build.gradle new file mode 100644 index 00000000..81efeb31 --- /dev/null +++ b/intentintegrator/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'androidx.appcompat:appcompat:1.2.0' +} \ No newline at end of file diff --git a/intentintegrator/consumer-rules.pro b/intentintegrator/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/intentintegrator/proguard-rules.pro b/intentintegrator/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/intentintegrator/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/intentintegrator/src/main/AndroidManifest.xml b/intentintegrator/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a0410a4b --- /dev/null +++ b/intentintegrator/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.zxing.integration.android"> + + / +</manifest> \ No newline at end of file diff --git a/app/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java b/intentintegrator/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java similarity index 100% rename from app/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java rename to intentintegrator/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java diff --git a/app-mini/src/main/java/com/google/zxing/integration/android/IntentResult.java b/intentintegrator/src/main/java/com/google/zxing/integration/android/IntentResult.java similarity index 100% rename from app-mini/src/main/java/com/google/zxing/integration/android/IntentResult.java rename to intentintegrator/src/main/java/com/google/zxing/integration/android/IntentResult.java diff --git a/settings.gradle b/settings.gradle index 05e4830c..46cf1758 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,3 @@ +include ':intentintegrator' +include ':appcore' include ':orbotservice',':app',':app-mini'