[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [orbot/master] First stab at modularizing shared code between the app and app mini projects
commit 64692ff14da77e72cf4e34b7e573de1e30fc60da
Author: bim <dsnake@xxxxxxxxxxxxxx>
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'
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits