[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [orbot/master] big refactor
commit d28db417827c601eddaf6be9f01326c68b9c3e03
Author: arrase <arrase@xxxxxxxxx>
Date: Thu Nov 24 02:56:11 2016 +0100
big refactor
---
app/src/main/AndroidManifest.xml | 10 +-
.../org/torproject/android/OrbotMainActivity.java | 6 +-
.../org/torproject/android/backup/BackupUtils.java | 65 ----------
.../java/org/torproject/android/backup/ZipIt.java | 98 ---------------
.../android/storage/AppDataProvider.java | 39 ------
.../android/storage/ExternalStorage.java | 34 ------
.../android/storage/PermissionManager.java | 50 --------
.../ui/hiddenservices/HiddenServicesActivity.java | 129 ++++++++++++++++++++
.../ui/hiddenservices/adapters/BackupAdapter.java | 50 ++++++++
.../hiddenservices/adapters/OnionListAdapter.java | 38 ++++++
.../ui/hiddenservices/backup/BackupUtils.java | 65 ++++++++++
.../android/ui/hiddenservices/backup/ZipIt.java | 98 +++++++++++++++
.../ui/hiddenservices/database/HSDatabase.java | 35 ++++++
.../ui/hiddenservices/dialogs/HSActionsDialog.java | 103 ++++++++++++++++
.../ui/hiddenservices/dialogs/HSDataDialog.java | 89 ++++++++++++++
.../hiddenservices/dialogs/SelectBackupDialog.java | 81 +++++++++++++
.../providers/HSContentProvider.java | 133 +++++++++++++++++++++
.../ui/hiddenservices/storage/AppDataProvider.java | 39 ++++++
.../ui/hiddenservices/storage/ExternalStorage.java | 34 ++++++
.../hiddenservices/storage/PermissionManager.java | 50 ++++++++
.../android/ui/hs/HiddenServicesActivity.java | 129 --------------------
.../android/ui/hs/adapters/BackupAdapter.java | 50 --------
.../android/ui/hs/adapters/OnionListAdapter.java | 38 ------
.../android/ui/hs/database/HSDatabase.java | 35 ------
.../android/ui/hs/dialogs/HSActionsDialog.java | 109 -----------------
.../android/ui/hs/dialogs/HSDataDialog.java | 89 --------------
.../android/ui/hs/dialogs/SelectBackupDialog.java | 81 -------------
.../android/ui/hs/providers/HSContentProvider.java | 133 ---------------------
app/src/main/res/layout/layout_hs_list_view.xml | 2 +-
.../main/res/layout/layout_hs_list_view_main.xml | 2 +-
.../org/torproject/android/service/TorService.java | 2 +-
31 files changed, 955 insertions(+), 961 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c099076..b7a5e87 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -137,7 +137,7 @@
</receiver>
<activity
- android:name=".ui.hs.HiddenServicesActivity"
+ android:name=".ui.hiddenservices.HiddenServicesActivity"
android:label="@string/title_activity_hidden_services"
android:theme="@style/DefaultTheme" >
<meta-data
@@ -146,13 +146,13 @@
</activity>
<provider
- android:name=".ui.hs.providers.HSContentProvider"
+ android:name=".ui.hiddenservices.providers.HSContentProvider"
android:exported="false"
- android:authorities="org.torproject.android.ui.hs.providers" />
+ android:authorities="org.torproject.android.ui.hiddenservices.providers" />
<provider
- android:name="org.torproject.android.storage.AppDataProvider"
- android:authorities="org.torproject.android.storage"
+ android:name=".ui.hiddenservices.storage.AppDataProvider"
+ android:authorities="org.torproject.android.ui.hiddenservices.storage"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
index 1ea9b6e..9a5bfb5 100644
--- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java
+++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
@@ -23,13 +23,13 @@ import org.torproject.android.service.TorServiceConstants;
import org.torproject.android.service.util.TorServiceUtils;
import org.torproject.android.settings.SettingsPreferences;
import org.torproject.android.ui.AppManager;
-import org.torproject.android.ui.hs.HiddenServicesActivity;
+import org.torproject.android.ui.hiddenservices.HiddenServicesActivity;
import org.torproject.android.ui.ImageProgressView;
import org.torproject.android.ui.PromoAppsActivity;
import org.torproject.android.ui.Rotate3dAnimation;
-import org.torproject.android.ui.hs.providers.HSContentProvider;
+import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
import org.torproject.android.vpn.VPNEnableActivity;
-import org.torproject.android.backup.BackupUtils;
+import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
diff --git a/app/src/main/java/org/torproject/android/backup/BackupUtils.java b/app/src/main/java/org/torproject/android/backup/BackupUtils.java
deleted file mode 100644
index 57d8c8d..0000000
--- a/app/src/main/java/org/torproject/android/backup/BackupUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.torproject.android.backup;
-
-import android.app.Application;
-import android.content.Context;
-import android.widget.Toast;
-
-import org.torproject.android.service.R;
-import org.torproject.android.service.TorServiceConstants;
-import org.torproject.android.storage.ExternalStorage;
-
-import java.io.File;
-import java.io.IOException;
-
-public class BackupUtils {
- private File mHSBasePath;
- private Context mContext;
-
- public BackupUtils(Context context) {
- mContext = context;
- mHSBasePath = mContext.getDir(
- TorServiceConstants.DIRECTORY_TOR_DATA,
- Application.MODE_PRIVATE
- );
- }
-
- public String createZipBackup(Integer port) {
-
- File storage_path = ExternalStorage.getOrCreateBackupDir();
-
- if (storage_path == null)
- return null;
-
- String zip_path = storage_path.getAbsolutePath() + "/hs" + port + ".zip";
- String files[] = {
- mHSBasePath + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR + "/hs" + port + "/hostname",
- mHSBasePath + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR + "/hs" + port + "/private_key"
- };
-
- ZipIt zip = new ZipIt(files, zip_path);
-
- if (!zip.zip()) {
- return null;
- }
-
- return zip_path;
- }
-
- public void restoreZipBackup(Integer port, String path) {
- String hsBasePath;
-
- try {
- hsBasePath = mHSBasePath.getCanonicalPath() + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR;
- File hsPath = new File(hsBasePath, "/hs" + port);
- if (hsPath.mkdirs()) {
- ZipIt zip = new ZipIt(null, path);
- zip.unzip(hsPath.getCanonicalPath());
- return;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
- }
-}
diff --git a/app/src/main/java/org/torproject/android/backup/ZipIt.java b/app/src/main/java/org/torproject/android/backup/ZipIt.java
deleted file mode 100644
index bde29f0..0000000
--- a/app/src/main/java/org/torproject/android/backup/ZipIt.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.torproject.android.backup;
-
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-
-public class ZipIt {
- private static final int BUFFER = 2048;
-
- private String[] _files;
- private String _zipFile;
-
- public ZipIt(String[] files, String zipFile) {
- _files = files;
- _zipFile = zipFile;
- }
-
- public boolean zip() {
- try {
- BufferedInputStream origin = null;
- FileOutputStream dest = new FileOutputStream(_zipFile);
-
- ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
-
- byte data[] = new byte[BUFFER];
-
- for (String _file : _files) {
- FileInputStream fi = new FileInputStream(_file);
- origin = new BufferedInputStream(fi, BUFFER);
- ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1));
- out.putNextEntry(entry);
- int count;
- while ((count = origin.read(data, 0, BUFFER)) != -1) {
- out.write(data, 0, count);
- }
- origin.close();
- }
-
- out.close();
- } catch (Exception e) {
- return false;
- }
-
- return true;
- }
-
- public boolean unzip(String output_path) {
- InputStream is;
- ZipInputStream zis;
-
- try {
- String filename;
- is = new FileInputStream(_zipFile);
- zis = new ZipInputStream(new BufferedInputStream(is));
- ZipEntry ze;
- byte[] buffer = new byte[1024];
- int count;
-
- while ((ze = zis.getNextEntry()) != null) {
- // zapis do souboru
- filename = ze.getName();
-
- // Need to create directories if not exists, or
- // it will generate an Exception...
- if (ze.isDirectory()) {
- File fmd = new File(output_path + filename);
- fmd.mkdirs();
- continue;
- }
-
- FileOutputStream fout = new FileOutputStream(output_path + filename);
-
- // cteni zipu a zapis
- while ((count = zis.read(buffer)) != -1) {
- fout.write(buffer, 0, count);
- }
-
- fout.close();
- zis.closeEntry();
- }
-
- zis.close();
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
-
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/torproject/android/storage/AppDataProvider.java b/app/src/main/java/org/torproject/android/storage/AppDataProvider.java
deleted file mode 100644
index c04a293..0000000
--- a/app/src/main/java/org/torproject/android/storage/AppDataProvider.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.torproject.android.storage;
-
-
-import android.app.Application;
-import android.content.Context;
-
-import com.commonsware.cwac.provider.LocalPathStrategy;
-import com.commonsware.cwac.provider.StreamProvider;
-import com.commonsware.cwac.provider.StreamStrategy;
-
-import org.torproject.android.service.TorServiceConstants;
-
-import java.io.IOException;
-import java.util.HashMap;
-
-public class AppDataProvider extends StreamProvider {
- private static final String TAG = "app-data-path";
-
- @Override
- protected StreamStrategy buildStrategy(Context context,
- String tag, String name,
- String path,
- HashMap<String, String> attrs)
- throws IOException {
-
- if (TAG.equals(tag)) {
- return (new LocalPathStrategy(
- name,
- context.getDir(
- TorServiceConstants.DIRECTORY_TOR_DATA,
- Application.MODE_PRIVATE
- )
- )
- );
- }
-
- return (super.buildStrategy(context, tag, name, path, attrs));
- }
-}
diff --git a/app/src/main/java/org/torproject/android/storage/ExternalStorage.java b/app/src/main/java/org/torproject/android/storage/ExternalStorage.java
deleted file mode 100644
index bea196e..0000000
--- a/app/src/main/java/org/torproject/android/storage/ExternalStorage.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.torproject.android.storage;
-
-import android.os.Environment;
-
-import java.io.File;
-
-public class ExternalStorage {
- private static final String BACKUPS_DIR = "Orbot-HiddenServices";
-
- public static File getOrCreateBackupDir() {
- if (!isExternalStorageWritable())
- return null;
-
- File dir = new File(Environment.getExternalStorageDirectory(), BACKUPS_DIR);
-
- if (!dir.isDirectory() && !dir.mkdirs())
- return null;
-
- return dir;
- }
-
- /* Checks if external storage is available for read and write */
- public static boolean isExternalStorageWritable() {
- String state = Environment.getExternalStorageState();
- return Environment.MEDIA_MOUNTED.equals(state);
- }
-
- /* Checks if external storage is available to at least read */
- public static boolean isExternalStorageReadable() {
- String state = Environment.getExternalStorageState();
- return Environment.MEDIA_MOUNTED.equals(state) ||
- Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
- }
-}
diff --git a/app/src/main/java/org/torproject/android/storage/PermissionManager.java b/app/src/main/java/org/torproject/android/storage/PermissionManager.java
deleted file mode 100644
index 128db8e..0000000
--- a/app/src/main/java/org/torproject/android/storage/PermissionManager.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.torproject.android.storage;
-
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.FragmentActivity;
-import android.view.View;
-
-import org.torproject.android.R;
-
-public class PermissionManager {
- private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
-
- public static boolean usesRuntimePermissions() {
- return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
- }
-
- @SuppressLint("NewApi")
- public static boolean hasExternalWritePermission(Context context) {
- return (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
- }
-
- public static void requestPermissions(FragmentActivity activity) {
- final FragmentActivity mActivity = activity;
-
- if (ActivityCompat.shouldShowRequestPermissionRationale
- (mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- Snackbar.make(mActivity.findViewById(android.R.id.content),
- R.string.please_grant_permissions_for_external_storage,
- Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ActivityCompat.requestPermissions(mActivity,
- new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
- }
- }).show();
- } else {
- ActivityCompat.requestPermissions(mActivity,
- new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
- }
- }
-}
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
new file mode 100644
index 0000000..119b13a
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java
@@ -0,0 +1,129 @@
+package org.torproject.android.ui.hiddenservices;
+
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import org.torproject.android.R;
+import org.torproject.android.ui.hiddenservices.storage.PermissionManager;
+import org.torproject.android.ui.hiddenservices.adapters.OnionListAdapter;
+import org.torproject.android.ui.hiddenservices.dialogs.HSActionsDialog;
+import org.torproject.android.ui.hiddenservices.dialogs.HSDataDialog;
+import org.torproject.android.ui.hiddenservices.dialogs.SelectBackupDialog;
+import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
+
+public class HiddenServicesActivity extends AppCompatActivity {
+ private ContentResolver mCR;
+ private OnionListAdapter mAdapter;
+ private Toolbar toolbar;
+
+ private String[] mProjection = new String[]{
+ HSContentProvider.HiddenService._ID,
+ HSContentProvider.HiddenService.NAME,
+ HSContentProvider.HiddenService.PORT,
+ HSContentProvider.HiddenService.DOMAIN,
+ HSContentProvider.HiddenService.CREATED_BY_USER
+ };
+
+ private String mWhere = HSContentProvider.HiddenService.CREATED_BY_USER + "=1";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.layout_hs_list_view);
+
+ toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ mCR = getContentResolver();
+
+ FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ HSDataDialog dialog = new HSDataDialog();
+ dialog.show(getSupportFragmentManager(), "HSDataDialog");
+ }
+ });
+
+ mAdapter = new OnionListAdapter(
+ this,
+ mCR.query(HSContentProvider.CONTENT_URI, mProjection, mWhere, null, null),
+ 0
+ );
+
+ mCR.registerContentObserver(
+ HSContentProvider.CONTENT_URI, true, new HSObserver(new Handler())
+ );
+
+ ListView onion_list = (ListView) findViewById(R.id.onion_list);
+ onion_list.setAdapter(mAdapter);
+
+ onion_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ TextView port = (TextView) view.findViewById(R.id.hs_port);
+ TextView onion = (TextView) view.findViewById(R.id.hs_onion);
+
+ Bundle arguments = new Bundle();
+ arguments.putString("port", port.getText().toString());
+ arguments.putString("onion", onion.getText().toString());
+
+ HSActionsDialog dialog = new HSActionsDialog();
+ dialog.setArguments(arguments);
+ dialog.show(getSupportFragmentManager(), "HSActionsDialog");
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.hs_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ if (id == R.id.menu_restore_backup) {
+ if (PermissionManager.usesRuntimePermissions()
+ && !PermissionManager.hasExternalWritePermission(this)) {
+ PermissionManager.requestPermissions(this);
+ return true;
+ }
+
+ SelectBackupDialog dialog = new SelectBackupDialog();
+ dialog.show(getSupportFragmentManager(), "SelectBackupDialog");
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ class HSObserver extends ContentObserver {
+ HSObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mAdapter.changeCursor(mCR.query(
+ HSContentProvider.CONTENT_URI, mProjection, mWhere, null, null
+ ));
+ }
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/BackupAdapter.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/BackupAdapter.java
new file mode 100644
index 0000000..196023b
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/BackupAdapter.java
@@ -0,0 +1,50 @@
+package org.torproject.android.ui.hiddenservices.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import org.torproject.android.R;
+
+import java.io.File;
+import java.util.List;
+
+public class BackupAdapter extends ArrayAdapter<File> {
+ private int mResource;
+
+ public BackupAdapter(Context context, int resource) {
+ super(context, resource);
+ mResource = resource;
+ }
+
+ public BackupAdapter(Context context, int resource, List<File> zips) {
+ super(context, resource, zips);
+ mResource = resource;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ View v = convertView;
+
+ if (v == null) {
+ LayoutInflater vi;
+ vi = LayoutInflater.from(getContext());
+ v = vi.inflate(mResource, null);
+ }
+
+ File p = getItem(position);
+
+ if (p != null) {
+ TextView name = (TextView) v.findViewById(R.id.backup_name);
+
+ if (name != null)
+ name.setText(p.getName());
+ }
+
+ return v;
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java
new file mode 100644
index 0000000..1edbef2
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java
@@ -0,0 +1,38 @@
+package org.torproject.android.ui.hiddenservices.adapters;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v4.widget.CursorAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.torproject.android.R;
+import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
+
+public class OnionListAdapter extends CursorAdapter {
+ private LayoutInflater cursorInflater;
+
+ public OnionListAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+
+ cursorInflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ TextView port = (TextView) view.findViewById(R.id.hs_port);
+ port.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.PORT)));
+ TextView name = (TextView) view.findViewById(R.id.hs_name);
+ name.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.NAME)));
+ TextView domain = (TextView) view.findViewById(R.id.hs_onion);
+ domain.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.DOMAIN)));
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return cursorInflater.inflate(R.layout.layout_hs_list_item, parent, false);
+ }
+}
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
new file mode 100644
index 0000000..c60beb9
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
@@ -0,0 +1,65 @@
+package org.torproject.android.ui.hiddenservices.backup;
+
+import android.app.Application;
+import android.content.Context;
+import android.widget.Toast;
+
+import org.torproject.android.service.R;
+import org.torproject.android.service.TorServiceConstants;
+import org.torproject.android.ui.hiddenservices.storage.ExternalStorage;
+
+import java.io.File;
+import java.io.IOException;
+
+public class BackupUtils {
+ private File mHSBasePath;
+ private Context mContext;
+
+ public BackupUtils(Context context) {
+ mContext = context;
+ mHSBasePath = mContext.getDir(
+ TorServiceConstants.DIRECTORY_TOR_DATA,
+ Application.MODE_PRIVATE
+ );
+ }
+
+ public String createZipBackup(Integer port) {
+
+ File storage_path = ExternalStorage.getOrCreateBackupDir();
+
+ if (storage_path == null)
+ return null;
+
+ String zip_path = storage_path.getAbsolutePath() + "/hs" + port + ".zip";
+ String files[] = {
+ mHSBasePath + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR + "/hs" + port + "/hostname",
+ mHSBasePath + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR + "/hs" + port + "/private_key"
+ };
+
+ ZipIt zip = new ZipIt(files, zip_path);
+
+ if (!zip.zip()) {
+ return null;
+ }
+
+ return zip_path;
+ }
+
+ public void restoreZipBackup(Integer port, String path) {
+ String hsBasePath;
+
+ try {
+ hsBasePath = mHSBasePath.getCanonicalPath() + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR;
+ File hsPath = new File(hsBasePath, "/hs" + port);
+ if (hsPath.mkdirs()) {
+ ZipIt zip = new ZipIt(null, path);
+ zip.unzip(hsPath.getCanonicalPath());
+ return;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java
new file mode 100644
index 0000000..42e0bf9
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java
@@ -0,0 +1,98 @@
+package org.torproject.android.ui.hiddenservices.backup;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+public class ZipIt {
+ private static final int BUFFER = 2048;
+
+ private String[] _files;
+ private String _zipFile;
+
+ public ZipIt(String[] files, String zipFile) {
+ _files = files;
+ _zipFile = zipFile;
+ }
+
+ public boolean zip() {
+ try {
+ BufferedInputStream origin = null;
+ FileOutputStream dest = new FileOutputStream(_zipFile);
+
+ ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
+
+ byte data[] = new byte[BUFFER];
+
+ for (String _file : _files) {
+ FileInputStream fi = new FileInputStream(_file);
+ origin = new BufferedInputStream(fi, BUFFER);
+ ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1));
+ out.putNextEntry(entry);
+ int count;
+ while ((count = origin.read(data, 0, BUFFER)) != -1) {
+ out.write(data, 0, count);
+ }
+ origin.close();
+ }
+
+ out.close();
+ } catch (Exception e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean unzip(String output_path) {
+ InputStream is;
+ ZipInputStream zis;
+
+ try {
+ String filename;
+ is = new FileInputStream(_zipFile);
+ zis = new ZipInputStream(new BufferedInputStream(is));
+ ZipEntry ze;
+ byte[] buffer = new byte[1024];
+ int count;
+
+ while ((ze = zis.getNextEntry()) != null) {
+ // zapis do souboru
+ filename = ze.getName();
+
+ // Need to create directories if not exists, or
+ // it will generate an Exception...
+ if (ze.isDirectory()) {
+ File fmd = new File(output_path + filename);
+ fmd.mkdirs();
+ continue;
+ }
+
+ FileOutputStream fout = new FileOutputStream(output_path + filename);
+
+ // cteni zipu a zapis
+ while ((count = zis.read(buffer)) != -1) {
+ fout.write(buffer, 0, count);
+ }
+
+ fout.close();
+ zis.closeEntry();
+ }
+
+ zis.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java
new file mode 100644
index 0000000..8f1123f
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java
@@ -0,0 +1,35 @@
+package org.torproject.android.ui.hiddenservices.database;
+
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class HSDatabase extends SQLiteOpenHelper {
+
+ public static final String HS_DATA_TABLE_NAME = "hs_data";
+ private static final int DATABASE_VERSION = 2;
+ private static final String DATABASE_NAME = "hidden_services";
+ private static final String HS_DATA_TABLE_CREATE =
+ "CREATE TABLE " + HS_DATA_TABLE_NAME + " (" +
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "name TEXT, " +
+ "domain TEXT, " +
+ "onion_port INTEGER, " +
+ "created_by_user INTEGER DEFAULT 0, " +
+ "port INTEGER);";
+
+ public HSDatabase(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(HS_DATA_TABLE_CREATE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ }
+}
+
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java
new file mode 100644
index 0000000..103f87b
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java
@@ -0,0 +1,103 @@
+package org.torproject.android.ui.hiddenservices.dialogs;
+
+
+import android.app.Dialog;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import org.torproject.android.R;
+import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
+import org.torproject.android.ui.hiddenservices.storage.PermissionManager;
+import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
+
+public class HSActionsDialog extends DialogFragment {
+ public final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Bundle arguments = getArguments();
+
+ final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_actions, null);
+ final AlertDialog actionDialog = new AlertDialog.Builder(getActivity())
+ .setView(dialog_view)
+ .setTitle(R.string.hidden_services)
+ .create();
+
+ Button backup = (Button) dialog_view.findViewById(R.id.btn_hs_backup);
+ backup.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Context mContext = v.getContext();
+
+ if (PermissionManager.usesRuntimePermissions()
+ && !PermissionManager.hasExternalWritePermission(mContext)) {
+ PermissionManager.requestPermissions(getActivity());
+ return;
+ }
+
+ BackupUtils hsutils = new BackupUtils(mContext);
+ String backupPath = hsutils.createZipBackup(Integer.parseInt(arguments.getString("port")));
+
+ if (backupPath == null || backupPath.length() < 1) {
+ Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
+ actionDialog.dismiss();
+ return;
+ }
+
+ Toast.makeText(mContext, R.string.backup_saved_at_external_storage, Toast.LENGTH_LONG).show();
+
+ Uri selectedUri = Uri.parse(backupPath.substring(0, backupPath.lastIndexOf("/")));
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(selectedUri, "resource/folder");
+
+ if (intent.resolveActivityInfo(mContext.getPackageManager(), 0) != null) {
+ startActivity(intent);
+ } else {
+ Toast.makeText(mContext, R.string.filemanager_not_available, Toast.LENGTH_LONG).show();
+ }
+ actionDialog.dismiss();
+ }
+ });
+
+ Button copy = (Button) dialog_view.findViewById(R.id.btn_hs_clipboard);
+ copy.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Context mContext = v.getContext();
+ ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("onion", arguments.getString("onion"));
+ clipboard.setPrimaryClip(clip);
+ Toast.makeText(mContext, R.string.done, Toast.LENGTH_LONG).show();
+ actionDialog.dismiss();
+ }
+ });
+
+ Button delete = (Button) dialog_view.findViewById(R.id.btn_hs_delete);
+ delete.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ v.getContext().getContentResolver().delete(
+ HSContentProvider.CONTENT_URI, "port=" + arguments.getString("port"), null
+ );
+ actionDialog.dismiss();
+ }
+ });
+
+ Button cancel = (Button) dialog_view.findViewById(R.id.btn_hs_cancel);
+ cancel.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ actionDialog.dismiss();
+ }
+ });
+
+ return actionDialog;
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDataDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDataDialog.java
new file mode 100644
index 0000000..0b04135
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDataDialog.java
@@ -0,0 +1,89 @@
+package org.torproject.android.ui.hiddenservices.dialogs;
+
+
+import android.app.Dialog;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import org.torproject.android.R;
+import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
+
+public class HSDataDialog extends DialogFragment {
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Get the layout
+ final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_data_dialog, null);
+
+ // Use the Builder class for convenient dialog construction
+ final AlertDialog serviceDataDialog = new AlertDialog.Builder(getActivity())
+ .setView(dialog_view)
+ .setTitle(R.string.hidden_services)
+ .create();
+
+ // Buttons action
+ Button save = (Button) dialog_view.findViewById(R.id.HSDialogSave);
+ save.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ String serverName = ((EditText) dialog_view.findViewById(R.id.hsName)).getText().toString();
+ Integer localPort = Integer.parseInt(
+ ((EditText) dialog_view.findViewById(R.id.hsLocalPort)).getText().toString()
+ );
+ Integer onionPort = Integer.parseInt(
+ ((EditText) dialog_view.findViewById(R.id.hsOnionPort)).getText().toString()
+ );
+
+ if (checkInput(localPort, onionPort)) {
+ saveData(serverName, localPort, onionPort);
+ serviceDataDialog.dismiss();
+ }
+ }
+ });
+
+ Button cancel = (Button) dialog_view.findViewById(R.id.HSDialogCancel);
+ cancel.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ serviceDataDialog.cancel();
+ }
+ });
+
+ return serviceDataDialog;
+ }
+
+ private boolean checkInput(Integer local, Integer remote) {
+ boolean is_ok = true;
+ Integer error_msg = 0;
+
+ if ((local < 1 || local > 65535) || (remote < 1 || remote > 65535)) {
+ error_msg = R.string.invalid_port;
+ is_ok = false;
+ }
+
+ if (!is_ok) {
+ Toast.makeText(getContext(), error_msg, Toast.LENGTH_SHORT).show();
+ }
+
+ return is_ok;
+ }
+
+ private void saveData(String name, Integer local, Integer remote) {
+ ContentValues fields = new ContentValues();
+ fields.put("name", name);
+ fields.put("port", local);
+ fields.put("onion_port", remote);
+ fields.put("created_by_user", 1);
+
+ ContentResolver cr = getContext().getContentResolver();
+
+ cr.insert(HSContentProvider.CONTENT_URI, fields);
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectBackupDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectBackupDialog.java
new file mode 100644
index 0000000..ce2c717
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/SelectBackupDialog.java
@@ -0,0 +1,81 @@
+package org.torproject.android.ui.hiddenservices.dialogs;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+
+import org.torproject.android.R;
+import org.torproject.android.ui.hiddenservices.storage.ExternalStorage;
+import org.torproject.android.ui.hiddenservices.adapters.BackupAdapter;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class SelectBackupDialog extends DialogFragment {
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder backupsDialog = new AlertDialog.Builder(getActivity());
+
+ backupsDialog.setTitle(R.string.restore_backup);
+
+ File backupDir = ExternalStorage.getOrCreateBackupDir();
+ File[] files = null;
+
+ try {
+ files = backupDir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.toLowerCase().endsWith(".zip");
+ }
+ });
+ } catch (NullPointerException e) {
+ // Silent block
+ }
+
+ if (files == null || files.length < 1) {
+ backupsDialog.setMessage(R.string.create_a_backup_first);
+ backupsDialog.setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
+
+ return backupsDialog.create();
+ }
+
+ final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_backups_list, null);
+
+ backupsDialog.setView(dialog_view);
+ backupsDialog.setPositiveButton(R.string.btn_okay, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
+
+ ListView backups = (ListView) dialog_view.findViewById(R.id.listview_hs_backups);
+
+ List<File> zips = new ArrayList<>();
+ Collections.addAll(zips, files);
+
+ backups.setAdapter(new BackupAdapter(getContext(), R.layout.layout_hs_backups_list_item, zips));
+ backups.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // TODO
+ }
+ });
+
+ return backupsDialog.create();
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java
new file mode 100644
index 0000000..856c685
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java
@@ -0,0 +1,133 @@
+package org.torproject.android.ui.hiddenservices.providers;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.torproject.android.ui.hiddenservices.database.HSDatabase;
+
+
+public class HSContentProvider extends ContentProvider {
+ private static final String AUTH = "org.torproject.android.ui.hiddenservices.providers";
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTH + "/hs");
+ //UriMatcher
+ private static final int ONIONS = 1;
+ private static final int ONION_ID = 2;
+
+ private static final UriMatcher uriMatcher;
+
+ //Inicializamos el UriMatcher
+ static {
+ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ uriMatcher.addURI(AUTH, "hs", ONIONS);
+ uriMatcher.addURI(AUTH, "hs/#", ONION_ID);
+ }
+
+ private HSDatabase mServerDB;
+ private Context mContext;
+
+ @Override
+ public boolean onCreate() {
+ mContext = getContext();
+ mServerDB = new HSDatabase(mContext);
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ //Si es una consulta a un ID concreto construimos el WHERE
+ String where = selection;
+ if (uriMatcher.match(uri) == ONION_ID) {
+ where = "_id=" + uri.getLastPathSegment();
+ }
+
+ SQLiteDatabase db = mServerDB.getReadableDatabase();
+
+ return db.query(HSDatabase.HS_DATA_TABLE_NAME, projection, where,
+ selectionArgs, null, null, sortOrder);
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ int match = uriMatcher.match(uri);
+
+ switch (match) {
+ case ONIONS:
+ return "vnd.android.cursor.dir/vnd.torproject.onions";
+ case ONION_ID:
+ return "vnd.android.cursor.item/vnd.torproject.onion";
+ default:
+ return null;
+ }
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
+ long regId;
+
+ SQLiteDatabase db = mServerDB.getWritableDatabase();
+
+ regId = db.insert(HSDatabase.HS_DATA_TABLE_NAME, null, values);
+
+ mContext.getContentResolver().notifyChange(CONTENT_URI, null);
+
+ return ContentUris.withAppendedId(CONTENT_URI, regId);
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
+
+ //Si es una consulta a un ID concreto construimos el WHERE
+ String where = selection;
+ if (uriMatcher.match(uri) == ONION_ID) {
+ where = "_id=" + uri.getLastPathSegment();
+ }
+
+ SQLiteDatabase db = mServerDB.getWritableDatabase();
+
+ Integer rows = db.delete(HSDatabase.HS_DATA_TABLE_NAME, where, selectionArgs);
+
+ mContext.getContentResolver().notifyChange(CONTENT_URI, null);
+
+ return rows;
+
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ SQLiteDatabase db = mServerDB.getWritableDatabase();
+
+ String where = selection;
+ if (uriMatcher.match(uri) == ONION_ID) {
+ where = "_id=" + uri.getLastPathSegment();
+ }
+
+ Integer rows = db.update(HSDatabase.HS_DATA_TABLE_NAME, values, where, null);
+ mContext.getContentResolver().notifyChange(CONTENT_URI, null);
+
+ return rows;
+ }
+
+ public static final class HiddenService implements BaseColumns {
+ public static final String NAME = "name";
+ public static final String PORT = "port";
+ public static final String ONION_PORT = "onion_port";
+ public static final String DOMAIN = "domain";
+ public static final String CREATED_BY_USER = "created_by_user";
+
+ private HiddenService() {
+ }
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/AppDataProvider.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/AppDataProvider.java
new file mode 100644
index 0000000..6e55569
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/AppDataProvider.java
@@ -0,0 +1,39 @@
+package org.torproject.android.ui.hiddenservices.storage;
+
+
+import android.app.Application;
+import android.content.Context;
+
+import com.commonsware.cwac.provider.LocalPathStrategy;
+import com.commonsware.cwac.provider.StreamProvider;
+import com.commonsware.cwac.provider.StreamStrategy;
+
+import org.torproject.android.service.TorServiceConstants;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+public class AppDataProvider extends StreamProvider {
+ private static final String TAG = "app-data-path";
+
+ @Override
+ protected StreamStrategy buildStrategy(Context context,
+ String tag, String name,
+ String path,
+ HashMap<String, String> attrs)
+ throws IOException {
+
+ if (TAG.equals(tag)) {
+ return (new LocalPathStrategy(
+ name,
+ context.getDir(
+ TorServiceConstants.DIRECTORY_TOR_DATA,
+ Application.MODE_PRIVATE
+ )
+ )
+ );
+ }
+
+ return (super.buildStrategy(context, tag, name, path, attrs));
+ }
+}
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
new file mode 100644
index 0000000..cda3f8c
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/ExternalStorage.java
@@ -0,0 +1,34 @@
+package org.torproject.android.ui.hiddenservices.storage;
+
+import android.os.Environment;
+
+import java.io.File;
+
+public class ExternalStorage {
+ private static final String BACKUPS_DIR = "Orbot-HiddenServices";
+
+ public static File getOrCreateBackupDir() {
+ if (!isExternalStorageWritable())
+ return null;
+
+ File dir = new File(Environment.getExternalStorageDirectory(), BACKUPS_DIR);
+
+ if (!dir.isDirectory() && !dir.mkdirs())
+ return null;
+
+ return dir;
+ }
+
+ /* Checks if external storage is available for read and write */
+ public static boolean isExternalStorageWritable() {
+ String state = Environment.getExternalStorageState();
+ return Environment.MEDIA_MOUNTED.equals(state);
+ }
+
+ /* Checks if external storage is available to at least read */
+ public static boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ return Environment.MEDIA_MOUNTED.equals(state) ||
+ Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/PermissionManager.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/PermissionManager.java
new file mode 100644
index 0000000..80706c5
--- /dev/null
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/storage/PermissionManager.java
@@ -0,0 +1,50 @@
+package org.torproject.android.ui.hiddenservices.storage;
+
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.FragmentActivity;
+import android.view.View;
+
+import org.torproject.android.R;
+
+public class PermissionManager {
+ private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
+
+ public static boolean usesRuntimePermissions() {
+ return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
+ }
+
+ @SuppressLint("NewApi")
+ public static boolean hasExternalWritePermission(Context context) {
+ return (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
+ }
+
+ public static void requestPermissions(FragmentActivity activity) {
+ final FragmentActivity mActivity = activity;
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale
+ (mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ Snackbar.make(mActivity.findViewById(android.R.id.content),
+ R.string.please_grant_permissions_for_external_storage,
+ Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ActivityCompat.requestPermissions(mActivity,
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
+ }
+ }).show();
+ } else {
+ ActivityCompat.requestPermissions(mActivity,
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
+ }
+ }
+}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/HiddenServicesActivity.java b/app/src/main/java/org/torproject/android/ui/hs/HiddenServicesActivity.java
deleted file mode 100644
index 4474668..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/HiddenServicesActivity.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.torproject.android.ui.hs;
-
-
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.design.widget.FloatingActionButton;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import org.torproject.android.R;
-import org.torproject.android.storage.PermissionManager;
-import org.torproject.android.ui.hs.adapters.OnionListAdapter;
-import org.torproject.android.ui.hs.dialogs.HSActionsDialog;
-import org.torproject.android.ui.hs.dialogs.HSDataDialog;
-import org.torproject.android.ui.hs.dialogs.SelectBackupDialog;
-import org.torproject.android.ui.hs.providers.HSContentProvider;
-
-public class HiddenServicesActivity extends AppCompatActivity {
- private ContentResolver mCR;
- private OnionListAdapter mAdapter;
- private Toolbar toolbar;
-
- private String[] mProjection = new String[]{
- HSContentProvider.HiddenService._ID,
- HSContentProvider.HiddenService.NAME,
- HSContentProvider.HiddenService.PORT,
- HSContentProvider.HiddenService.DOMAIN,
- HSContentProvider.HiddenService.CREATED_BY_USER
- };
-
- private String mWhere = HSContentProvider.HiddenService.CREATED_BY_USER + "=1";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.layout_hs_list_view);
-
- toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- mCR = getContentResolver();
-
- FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- HSDataDialog dialog = new HSDataDialog();
- dialog.show(getSupportFragmentManager(), "HSDataDialog");
- }
- });
-
- mAdapter = new OnionListAdapter(
- this,
- mCR.query(HSContentProvider.CONTENT_URI, mProjection, mWhere, null, null),
- 0
- );
-
- mCR.registerContentObserver(
- HSContentProvider.CONTENT_URI, true, new HSObserver(new Handler())
- );
-
- ListView onion_list = (ListView) findViewById(R.id.onion_list);
- onion_list.setAdapter(mAdapter);
-
- onion_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- TextView port = (TextView) view.findViewById(R.id.hs_port);
- TextView onion = (TextView) view.findViewById(R.id.hs_onion);
-
- Bundle arguments = new Bundle();
- arguments.putString("port", port.getText().toString());
- arguments.putString("onion", onion.getText().toString());
-
- HSActionsDialog dialog = new HSActionsDialog();
- dialog.setArguments(arguments);
- dialog.show(getSupportFragmentManager(), "HSActionsDialog");
- }
- });
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.hs_menu, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
-
- if (id == R.id.menu_restore_backup) {
- if (PermissionManager.usesRuntimePermissions()
- && !PermissionManager.hasExternalWritePermission(this)) {
- PermissionManager.requestPermissions(this);
- return true;
- }
-
- SelectBackupDialog dialog = new SelectBackupDialog();
- dialog.show(getSupportFragmentManager(), "SelectBackupDialog");
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- class HSObserver extends ContentObserver {
- HSObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mAdapter.changeCursor(mCR.query(
- HSContentProvider.CONTENT_URI, mProjection, mWhere, null, null
- ));
- }
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/adapters/BackupAdapter.java b/app/src/main/java/org/torproject/android/ui/hs/adapters/BackupAdapter.java
deleted file mode 100644
index bcc7a5a..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/adapters/BackupAdapter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.torproject.android.ui.hs.adapters;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
-
-import org.torproject.android.R;
-
-import java.io.File;
-import java.util.List;
-
-public class BackupAdapter extends ArrayAdapter<File> {
- private int mResource;
-
- public BackupAdapter(Context context, int resource) {
- super(context, resource);
- mResource = resource;
- }
-
- public BackupAdapter(Context context, int resource, List<File> zips) {
- super(context, resource, zips);
- mResource = resource;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- View v = convertView;
-
- if (v == null) {
- LayoutInflater vi;
- vi = LayoutInflater.from(getContext());
- v = vi.inflate(mResource, null);
- }
-
- File p = getItem(position);
-
- if (p != null) {
- TextView name = (TextView) v.findViewById(R.id.backup_name);
-
- if (name != null)
- name.setText(p.getName());
- }
-
- return v;
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/adapters/OnionListAdapter.java b/app/src/main/java/org/torproject/android/ui/hs/adapters/OnionListAdapter.java
deleted file mode 100644
index 0ae10cb..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/adapters/OnionListAdapter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.torproject.android.ui.hs.adapters;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.support.v4.widget.CursorAdapter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.torproject.android.R;
-import org.torproject.android.ui.hs.providers.HSContentProvider;
-
-public class OnionListAdapter extends CursorAdapter {
- private LayoutInflater cursorInflater;
-
- public OnionListAdapter(Context context, Cursor c, int flags) {
- super(context, c, flags);
-
- cursorInflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- TextView port = (TextView) view.findViewById(R.id.hs_port);
- port.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.PORT)));
- TextView name = (TextView) view.findViewById(R.id.hs_name);
- name.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.NAME)));
- TextView domain = (TextView) view.findViewById(R.id.hs_onion);
- domain.setText(cursor.getString(cursor.getColumnIndex(HSContentProvider.HiddenService.DOMAIN)));
- }
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return cursorInflater.inflate(R.layout.layout_hs_list_item, parent, false);
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/database/HSDatabase.java b/app/src/main/java/org/torproject/android/ui/hs/database/HSDatabase.java
deleted file mode 100644
index 07e2ca2..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/database/HSDatabase.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.torproject.android.ui.hs.database;
-
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-public class HSDatabase extends SQLiteOpenHelper {
-
- public static final String HS_DATA_TABLE_NAME = "hs_data";
- private static final int DATABASE_VERSION = 2;
- private static final String DATABASE_NAME = "hidden_services";
- private static final String HS_DATA_TABLE_CREATE =
- "CREATE TABLE " + HS_DATA_TABLE_NAME + " (" +
- "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "name TEXT, " +
- "domain TEXT, " +
- "onion_port INTEGER, " +
- "created_by_user INTEGER DEFAULT 0, " +
- "port INTEGER);";
-
- public HSDatabase(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(HS_DATA_TABLE_CREATE);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- }
-}
-
diff --git a/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSActionsDialog.java b/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSActionsDialog.java
deleted file mode 100644
index d5603b7..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSActionsDialog.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.torproject.android.ui.hs.dialogs;
-
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.Button;
-import android.widget.Toast;
-
-import org.torproject.android.R;
-import org.torproject.android.backup.BackupUtils;
-import org.torproject.android.storage.PermissionManager;
-import org.torproject.android.ui.hs.providers.HSContentProvider;
-
-public class HSActionsDialog extends DialogFragment {
- public final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Bundle arguments = getArguments();
-
- final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_actions, null);
- final AlertDialog actionDialog = new AlertDialog.Builder(getActivity())
- .setView(dialog_view)
- .setTitle(R.string.hidden_services)
- .create();
-
- Button backup = (Button) dialog_view.findViewById(R.id.btn_hs_backup);
- backup.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Context mContext = v.getContext();
-
- if (PermissionManager.usesRuntimePermissions()
- && !PermissionManager.hasExternalWritePermission(mContext)) {
- PermissionManager.requestPermissions(getActivity());
- return;
- }
-
- BackupUtils hsutils = new BackupUtils(mContext);
- String backupPath = hsutils.createZipBackup(Integer.parseInt(arguments.getString("port")));
-
- if (backupPath == null || backupPath.length() < 1) {
- Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
- actionDialog.dismiss();
- return;
- }
-
- Toast.makeText(mContext, R.string.backup_saved_at_external_storage, Toast.LENGTH_LONG).show();
-
- Uri selectedUri = Uri.parse(backupPath.substring(0, backupPath.lastIndexOf("/")));
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(selectedUri, "resource/folder");
-
- if (intent.resolveActivityInfo(mContext.getPackageManager(), 0) != null) {
- startActivity(intent);
- } else {
- Toast.makeText(mContext, R.string.filemanager_not_available, Toast.LENGTH_LONG).show();
- }
- actionDialog.dismiss();
- }
- });
-
- Button copy = (Button) dialog_view.findViewById(R.id.btn_hs_clipboard);
- copy.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Context mContext = v.getContext();
- ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("onion", arguments.getString("onion"));
- clipboard.setPrimaryClip(clip);
- Toast.makeText(mContext, R.string.done, Toast.LENGTH_LONG).show();
- actionDialog.dismiss();
- }
- });
-
- Button delete = (Button) dialog_view.findViewById(R.id.btn_hs_delete);
- delete.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- v.getContext().getContentResolver().delete(
- HSContentProvider.CONTENT_URI, "port=" + arguments.getString("port"), null
- );
- actionDialog.dismiss();
- }
- });
-
- Button cancel = (Button) dialog_view.findViewById(R.id.btn_hs_cancel);
- cancel.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- actionDialog.dismiss();
- }
- });
-
- return actionDialog;
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSDataDialog.java b/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSDataDialog.java
deleted file mode 100644
index 922b7f0..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/dialogs/HSDataDialog.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.torproject.android.ui.hs.dialogs;
-
-
-import android.app.Dialog;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import org.torproject.android.R;
-import org.torproject.android.ui.hs.providers.HSContentProvider;
-
-public class HSDataDialog extends DialogFragment {
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get the layout
- final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_data_dialog, null);
-
- // Use the Builder class for convenient dialog construction
- final AlertDialog serviceDataDialog = new AlertDialog.Builder(getActivity())
- .setView(dialog_view)
- .setTitle(R.string.hidden_services)
- .create();
-
- // Buttons action
- Button save = (Button) dialog_view.findViewById(R.id.HSDialogSave);
- save.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- String serverName = ((EditText) dialog_view.findViewById(R.id.hsName)).getText().toString();
- Integer localPort = Integer.parseInt(
- ((EditText) dialog_view.findViewById(R.id.hsLocalPort)).getText().toString()
- );
- Integer onionPort = Integer.parseInt(
- ((EditText) dialog_view.findViewById(R.id.hsOnionPort)).getText().toString()
- );
-
- if (checkInput(localPort, onionPort)) {
- saveData(serverName, localPort, onionPort);
- serviceDataDialog.dismiss();
- }
- }
- });
-
- Button cancel = (Button) dialog_view.findViewById(R.id.HSDialogCancel);
- cancel.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- serviceDataDialog.cancel();
- }
- });
-
- return serviceDataDialog;
- }
-
- private boolean checkInput(Integer local, Integer remote) {
- boolean is_ok = true;
- Integer error_msg = 0;
-
- if ((local < 1 || local > 65535) || (remote < 1 || remote > 65535)) {
- error_msg = R.string.invalid_port;
- is_ok = false;
- }
-
- if (!is_ok) {
- Toast.makeText(getContext(), error_msg, Toast.LENGTH_SHORT).show();
- }
-
- return is_ok;
- }
-
- private void saveData(String name, Integer local, Integer remote) {
- ContentValues fields = new ContentValues();
- fields.put("name", name);
- fields.put("port", local);
- fields.put("onion_port", remote);
- fields.put("created_by_user", 1);
-
- ContentResolver cr = getContext().getContentResolver();
-
- cr.insert(HSContentProvider.CONTENT_URI, fields);
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/dialogs/SelectBackupDialog.java b/app/src/main/java/org/torproject/android/ui/hs/dialogs/SelectBackupDialog.java
deleted file mode 100644
index 37c722b..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/dialogs/SelectBackupDialog.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.torproject.android.ui.hs.dialogs;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-
-import org.torproject.android.R;
-import org.torproject.android.storage.ExternalStorage;
-import org.torproject.android.ui.hs.adapters.BackupAdapter;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class SelectBackupDialog extends DialogFragment {
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder backupsDialog = new AlertDialog.Builder(getActivity());
-
- backupsDialog.setTitle(R.string.restore_backup);
-
- File backupDir = ExternalStorage.getOrCreateBackupDir();
- File[] files = null;
-
- try {
- files = backupDir.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.toLowerCase().endsWith(".zip");
- }
- });
- } catch (NullPointerException e) {
- // Silent block
- }
-
- if (files == null || files.length < 1) {
- backupsDialog.setMessage(R.string.create_a_backup_first);
- backupsDialog.setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- });
-
- return backupsDialog.create();
- }
-
- final View dialog_view = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_backups_list, null);
-
- backupsDialog.setView(dialog_view);
- backupsDialog.setPositiveButton(R.string.btn_okay, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- });
-
- ListView backups = (ListView) dialog_view.findViewById(R.id.listview_hs_backups);
-
- List<File> zips = new ArrayList<>();
- Collections.addAll(zips, files);
-
- backups.setAdapter(new BackupAdapter(getContext(), R.layout.layout_hs_backups_list_item, zips));
- backups.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- // TODO
- }
- });
-
- return backupsDialog.create();
- }
-}
diff --git a/app/src/main/java/org/torproject/android/ui/hs/providers/HSContentProvider.java b/app/src/main/java/org/torproject/android/ui/hs/providers/HSContentProvider.java
deleted file mode 100644
index f222b85..0000000
--- a/app/src/main/java/org/torproject/android/ui/hs/providers/HSContentProvider.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.torproject.android.ui.hs.providers;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.provider.BaseColumns;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import org.torproject.android.ui.hs.database.HSDatabase;
-
-
-public class HSContentProvider extends ContentProvider {
- private static final String AUTH = "org.torproject.android.ui.hs.providers";
- public static final Uri CONTENT_URI =
- Uri.parse("content://" + AUTH + "/hs");
- //UriMatcher
- private static final int ONIONS = 1;
- private static final int ONION_ID = 2;
-
- private static final UriMatcher uriMatcher;
-
- //Inicializamos el UriMatcher
- static {
- uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- uriMatcher.addURI(AUTH, "hs", ONIONS);
- uriMatcher.addURI(AUTH, "hs/#", ONION_ID);
- }
-
- private HSDatabase mServerDB;
- private Context mContext;
-
- @Override
- public boolean onCreate() {
- mContext = getContext();
- mServerDB = new HSDatabase(mContext);
- return true;
- }
-
- @Nullable
- @Override
- public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
- //Si es una consulta a un ID concreto construimos el WHERE
- String where = selection;
- if (uriMatcher.match(uri) == ONION_ID) {
- where = "_id=" + uri.getLastPathSegment();
- }
-
- SQLiteDatabase db = mServerDB.getReadableDatabase();
-
- return db.query(HSDatabase.HS_DATA_TABLE_NAME, projection, where,
- selectionArgs, null, null, sortOrder);
- }
-
- @Nullable
- @Override
- public String getType(@NonNull Uri uri) {
- int match = uriMatcher.match(uri);
-
- switch (match) {
- case ONIONS:
- return "vnd.android.cursor.dir/vnd.torproject.onions";
- case ONION_ID:
- return "vnd.android.cursor.item/vnd.torproject.onion";
- default:
- return null;
- }
- }
-
- @Nullable
- @Override
- public Uri insert(@NonNull Uri uri, ContentValues values) {
- long regId;
-
- SQLiteDatabase db = mServerDB.getWritableDatabase();
-
- regId = db.insert(HSDatabase.HS_DATA_TABLE_NAME, null, values);
-
- mContext.getContentResolver().notifyChange(CONTENT_URI, null);
-
- return ContentUris.withAppendedId(CONTENT_URI, regId);
- }
-
- @Override
- public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
-
- //Si es una consulta a un ID concreto construimos el WHERE
- String where = selection;
- if (uriMatcher.match(uri) == ONION_ID) {
- where = "_id=" + uri.getLastPathSegment();
- }
-
- SQLiteDatabase db = mServerDB.getWritableDatabase();
-
- Integer rows = db.delete(HSDatabase.HS_DATA_TABLE_NAME, where, selectionArgs);
-
- mContext.getContentResolver().notifyChange(CONTENT_URI, null);
-
- return rows;
-
- }
-
- @Override
- public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- SQLiteDatabase db = mServerDB.getWritableDatabase();
-
- String where = selection;
- if (uriMatcher.match(uri) == ONION_ID) {
- where = "_id=" + uri.getLastPathSegment();
- }
-
- Integer rows = db.update(HSDatabase.HS_DATA_TABLE_NAME, values, where, null);
- mContext.getContentResolver().notifyChange(CONTENT_URI, null);
-
- return rows;
- }
-
- public static final class HiddenService implements BaseColumns {
- public static final String NAME = "name";
- public static final String PORT = "port";
- public static final String ONION_PORT = "onion_port";
- public static final String DOMAIN = "domain";
- public static final String CREATED_BY_USER = "created_by_user";
-
- private HiddenService() {
- }
- }
-}
diff --git a/app/src/main/res/layout/layout_hs_list_view.xml b/app/src/main/res/layout/layout_hs_list_view.xml
index c47a392..3e7b32f 100644
--- a/app/src/main/res/layout/layout_hs_list_view.xml
+++ b/app/src/main/res/layout/layout_hs_list_view.xml
@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
- tools:context="org.torproject.android.ui.hs.HiddenServicesActivity">
+ tools:context="org.torproject.android.ui.hiddenservices.HiddenServicesActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/layout_hs_list_view_main.xml b/app/src/main/res/layout/layout_hs_list_view_main.xml
index bb1c94c..284a01c 100644
--- a/app/src/main/res/layout/layout_hs_list_view_main.xml
+++ b/app/src/main/res/layout/layout_hs_list_view_main.xml
@@ -10,7 +10,7 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
- tools:context="org.torproject.android.ui.hs.HiddenServicesActivity"
+ tools:context="org.torproject.android.ui.hiddenservices.HiddenServicesActivity"
tools:showIn="@layout/layout_hs_list_view">
<ListView
diff --git a/orbotservice/src/main/java/org/torproject/android/service/TorService.java b/orbotservice/src/main/java/org/torproject/android/service/TorService.java
index f8ed3b3..6d12424 100644
--- a/orbotservice/src/main/java/org/torproject/android/service/TorService.java
+++ b/orbotservice/src/main/java/org/torproject/android/service/TorService.java
@@ -132,7 +132,7 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
private Shell mShellPolipo;
- private static final Uri CONTENT_URI = Uri.parse("content://org.torproject.android.ui.hs.providers/hs");
+ private static final Uri CONTENT_URI = Uri.parse("content://org.torproject.android.ui.hiddenservices.providers/hs");
public static final class HiddenService implements BaseColumns {
public static final String NAME = "name";
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits