├── LICENSE.txt
├── README.md
├── org.hive2hive.android.deployment
├── .gitignore
├── assembly.xml
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── hive2hive
│ │ └── android
│ │ └── deployment
│ │ ├── MultiStableH2HPeers.java
│ │ └── StableH2HPeer.java
│ └── resources
│ ├── deployment-single.conf
│ ├── deployment.conf
│ └── logback.xml
└── org.hive2hive.mobile
├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── nrutishauser.xml
├── encodings.xml
├── gradle.xml
├── libraries
│ ├── apktool_lib_1_4_4_3.xml
│ ├── appcompat_v7_20_0_0.xml
│ ├── commons_io_2_4.xml
│ ├── core_1_51_0_0.xml
│ ├── el_api_2_2.xml
│ ├── fst_2_23.xml
│ ├── gcm_server_1_0_2.xml
│ ├── javassist_3_18_1_GA.xml
│ ├── json_simple_1_1.xml
│ ├── logback_android_classic_1_1_1_3.xml
│ ├── logback_android_core_1_1_1_3.xml
│ ├── mbassador_1_2_0.xml
│ ├── netty_buffer_4_0_25_Final.xml
│ ├── netty_common_4_0_25_Final.xml
│ ├── netty_transport_4_0_25_Final.xml
│ ├── objenesis_2_1.xml
│ ├── org_hive2hive_core_1_2_2.xml
│ ├── org_hive2hive_processframework_1_1.xml
│ ├── play_services_4_2_42.xml
│ ├── prov_1_51_0_0.xml
│ ├── slf4j_api_1_7_6.xml
│ ├── support_annotations_20_0_0.xml
│ ├── support_v4_20_0_0.xml
│ ├── tomp2p_android_5_0_Beta5.xml
│ ├── tomp2p_core_5_0_Beta5.xml
│ ├── tomp2p_dht_5_0_Beta5.xml
│ ├── tomp2p_nat_5_0_Beta5.xml
│ └── tomp2p_replication_5_0_Beta5.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── vcs.xml
└── workspace.xml
├── app
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── org
│ │ └── hive2hive
│ │ └── mobile
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── logback.xml
│ ├── java
│ └── org
│ │ └── hive2hive
│ │ └── mobile
│ │ ├── H2HApplication.java
│ │ ├── common
│ │ ├── AndroidFileAgent.java
│ │ ├── ApplicationHelper.java
│ │ ├── BaseProgressTask.java
│ │ ├── ConnectionMode.java
│ │ ├── ISuccessFailListener.java
│ │ ├── RelayMode.java
│ │ └── UserPermissionComparator.java
│ │ ├── connection
│ │ ├── ConnectActivity.java
│ │ ├── ConnectionChangeListener.java
│ │ ├── ConnectionSetupTask.java
│ │ └── DisconnectTask.java
│ │ ├── files
│ │ ├── AndroidFile.java
│ │ ├── AndroidFileComparator.java
│ │ ├── AndroidFileEventListener.java
│ │ ├── FileArrayAdapter.java
│ │ ├── FileState.java
│ │ ├── FilesActivity.java
│ │ ├── FilesFragment.java
│ │ └── tasks
│ │ │ ├── BaseFileTask.java
│ │ │ ├── FileDeleteTask.java
│ │ │ ├── FileDownloadTask.java
│ │ │ ├── FileListTask.java
│ │ │ ├── FileShareTask.java
│ │ │ ├── FileUpdateTask.java
│ │ │ └── FileUploadTask.java
│ │ ├── gcm
│ │ ├── GCMBroadcastReceiver.java
│ │ ├── GCMIntentService.java
│ │ └── GCMRegistrationUtil.java
│ │ ├── login
│ │ ├── LoginActivity.java
│ │ ├── UserLoginTask.java
│ │ └── UserLogoutTask.java
│ │ ├── preference
│ │ ├── PortPickerPreference.java
│ │ ├── SettingsActivity.java
│ │ └── SettingsFragment.java
│ │ └── security
│ │ ├── SCSecurityClassProvider.java
│ │ ├── SCStrongAESEncryption.java
│ │ └── SpongyCastleEncryption.java
│ └── res
│ ├── animator
│ ├── slide_in_left.xml
│ ├── slide_in_right.xml
│ ├── slide_out_left.xml
│ └── slide_out_right.xml
│ ├── drawable-hdpi
│ ├── ic_action_refresh.png
│ ├── ic_action_upload.png
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ ├── ic_action_refresh.png
│ ├── ic_action_upload.png
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ ├── ic_action_refresh.png
│ ├── ic_action_upload.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── ic_action_refresh.png
│ ├── ic_action_upload.png
│ └── ic_launcher.png
│ ├── drawable-xxxhdpi
│ └── ic_launcher.png
│ ├── drawable
│ ├── h2h_logo_large.png
│ ├── ic_archive_ex.png
│ ├── ic_archive_inex.png
│ ├── ic_audio_ex.png
│ ├── ic_audio_inex.png
│ ├── ic_blank_ex.png
│ ├── ic_blank_inex.png
│ ├── ic_calendar_ex.png
│ ├── ic_calendar_inex.png
│ ├── ic_cloud_inex.png
│ ├── ic_code_ex.png
│ ├── ic_code_inex.png
│ ├── ic_download_inex.png
│ ├── ic_folder.png
│ ├── ic_folder_loading.png
│ ├── ic_folder_shared.png
│ ├── ic_folder_upload.png
│ ├── ic_image_ex.png
│ ├── ic_image_inex.png
│ ├── ic_loading_inex.png
│ ├── ic_powerpoint_ex.png
│ ├── ic_powerpoint_inex.png
│ ├── ic_spreadsheet_ex.png
│ ├── ic_spreadsheet_inex.png
│ ├── ic_text_ex.png
│ ├── ic_text_inex.png
│ ├── ic_upload_ex.png
│ ├── ic_video_ex.png
│ ├── ic_video_inex.png
│ └── login_lock.png
│ ├── layout
│ ├── activity_connect.xml
│ ├── activity_files.xml
│ ├── activity_login.xml
│ ├── dialog_share.xml
│ └── fragment_files.xml
│ ├── menu
│ ├── menu_files.xml
│ └── menu_settings.xml
│ ├── values-w820dp
│ └── dimens.xml
│ ├── values
│ ├── dimens.xml
│ ├── strings.xml
│ ├── strings_activity_connect.xml
│ ├── strings_activity_files.xml
│ ├── strings_activity_login.xml
│ ├── strings_activity_power.xml
│ ├── strings_activity_preferences.xml
│ └── styles.xml
│ └── xml
│ └── preferences.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── org.hive2hive.mobile.iml
└── settings.gradle
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Nico Rutishauser
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Hive2Hive Android App
2 | =====================
3 |
4 | In this repository, you can find the sources of the **Hive2Hive Android App** ([Play Store](https://play.google.com/store/apps/details?id=org.hive2hive.mobile)) and simple runnable to create a network with 5 initial peers on a computer or server.
5 |
6 | Also visit the [Wiki](https://github.com/Hive2Hive/Android/wiki) to get more information.
7 |
8 | We appreciate every contribution to the application or the [Hive2Hive core project](https://github.com/Hive2Hive/Hive2Hive) itself. You could for example add translations for your language, improve the usability or stability. Feel free to ask questions or write an issue if something is unclear.
9 |
10 | ## Screenshots
11 | 
12 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/.gitignore:
--------------------------------------------------------------------------------
1 | # Eclipse #
2 |
3 | /bin
4 | /target
5 | /logs
6 | .project
7 | .classpath
8 | .settings
9 |
10 | # IntelliJ IDEA #
11 | .idea
12 | *.iml
13 |
14 | # Mac #
15 |
16 | .DS_Store
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/assembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | client
4 |
5 | zip
6 |
7 |
8 |
9 |
10 |
11 |
13 | true
14 | lib
15 | false
16 |
17 |
18 |
19 |
20 |
21 |
22 | ${project.build.directory}
23 |
24 |
25 | *.jar
26 |
27 |
28 |
29 |
30 | src/main/resources
31 |
32 |
33 | deployment.conf
34 | logback.xml
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | org.hive2hive
5 | org.hive2hive.android.deployment
6 | 1.0.2
7 |
8 |
9 |
10 | org.hive2hive
11 | org.hive2hive.core
12 | 1.2.2
13 |
14 |
15 | net.tomp2p
16 | tomp2p-android
17 | 5.0-Beta5
18 | compile
19 |
20 |
21 | ch.qos.logback
22 | logback-classic
23 | 1.1.1
24 | compile
25 |
26 |
27 | com.typesafe
28 | config
29 | 1.2.1
30 | compile
31 |
32 |
33 |
34 |
35 |
36 | hive2hive.org
37 | http://repo.hive2hive.org
38 |
39 |
40 |
41 | tomp2p.net
42 | TomP2P Repository
43 | http://tomp2p.net/dev/mvn/
44 |
45 |
46 |
47 |
48 |
49 |
50 |
52 | org.apache.maven.plugins
53 | maven-jar-plugin
54 | 2.5
55 |
56 |
57 |
58 | org.hive2hive.android.deployment.MultiStableH2HPeers
59 | true
60 | lib/
61 |
62 |
63 | ./
64 |
65 |
66 |
67 | deployment-single.conf
68 | deployment.conf
69 | logback.xml
70 |
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-assembly-plugin
78 | 2.5.1
79 |
80 |
81 | jar-with-dependencies
82 | package
83 |
84 | single
85 |
86 |
87 |
88 |
89 |
90 | assembly.xml
91 |
92 | false
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/src/main/java/org/hive2hive/android/deployment/MultiStableH2HPeers.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.android.deployment;
2 |
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | import net.tomp2p.relay.android.AndroidRelayServerConfig;
8 | import net.tomp2p.relay.buffer.MessageBufferConfiguration;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import com.typesafe.config.Config;
14 | import com.typesafe.config.ConfigFactory;
15 |
16 | /**
17 | * Creates multiple peers. The first one is the 'initial' peer, all others bootstrap to it.
18 | * This can be used to increase the number of seed nodes in the P2P network.
19 | *
20 | * @author Nico
21 | *
22 | */
23 | public class MultiStableH2HPeers {
24 |
25 | private static final Logger logger = LoggerFactory.getLogger(StableH2HPeer.class);
26 |
27 | public static void main(String[] args) throws UnknownHostException {
28 |
29 | Config config = ConfigFactory.load("deployment.conf");
30 | int numPeers = config.getInt("NumPeers");
31 | int startPort = config.getInt("StartPort");
32 | String externalAddressString = config.getString("ExternalAddress");
33 | InetAddress externalAddress = null;
34 | if (!"auto".equalsIgnoreCase(externalAddressString)) {
35 | externalAddress = InetAddress.getByName(externalAddressString);
36 | }
37 |
38 | boolean acceptData = config.getBoolean("AcceptData");
39 | boolean enableRelaying = config.getBoolean("Relay.enabled");
40 | AndroidRelayServerConfig androidServer = null;
41 | if (enableRelaying) {
42 | String gcmKey = config.getString("Relay.GCM.api-key");
43 | long bufferTimeout = config.getDuration("Relay.GCM.buffer-age-limit", TimeUnit.MILLISECONDS);
44 | MessageBufferConfiguration buffer = new MessageBufferConfiguration().bufferAgeLimit(bufferTimeout);
45 | androidServer = new AndroidRelayServerConfig(gcmKey, 5, buffer);
46 | }
47 |
48 | for (int i = 0; i < numPeers; i++) {
49 | InetAddress bootstrapAddress = null;
50 | if (i > 0) {
51 | if (externalAddress == null) {
52 | // bootstrap by default to 127.0.0.1
53 | bootstrapAddress = InetAddress.getLocalHost();
54 | } else {
55 | // bootstrap to external address if existing
56 | bootstrapAddress = externalAddress;
57 | }
58 | }
59 |
60 | // iterate port to not reuse the same twice
61 | new StableH2HPeer(startPort + i, i != 0, bootstrapAddress, startPort, externalAddress, acceptData,
62 | enableRelaying, androidServer);
63 | }
64 |
65 | logger.debug("{} peers started!", numPeers);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/src/main/java/org/hive2hive/android/deployment/StableH2HPeer.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.android.deployment;
2 |
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | import net.tomp2p.connection.ConnectionBean;
8 | import net.tomp2p.nat.PeerBuilderNAT;
9 | import net.tomp2p.peers.PeerAddress;
10 | import net.tomp2p.relay.RelayType;
11 | import net.tomp2p.relay.android.AndroidRelayServerConfig;
12 | import net.tomp2p.relay.buffer.MessageBufferConfiguration;
13 |
14 | import org.hive2hive.core.api.H2HNode;
15 | import org.hive2hive.core.api.configs.FileConfiguration;
16 | import org.hive2hive.core.api.configs.NetworkConfiguration;
17 | import org.hive2hive.core.api.interfaces.IFileConfiguration;
18 | import org.hive2hive.core.api.interfaces.IH2HNode;
19 | import org.hive2hive.core.network.H2HStorageMemory;
20 | import org.hive2hive.core.network.H2HStorageMemory.StorageMemoryPutMode;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import com.typesafe.config.Config;
25 | import com.typesafe.config.ConfigFactory;
26 |
27 | /**
28 | * Creates a single stable peer with the configuration in the separate file
29 | * This can be used to either create a new P2P network or add a node to an existing network.
30 | *
31 | * @author Nico
32 | *
33 | */
34 | public class StableH2HPeer {
35 |
36 | // File Configuration
37 | private static final IFileConfiguration fileConfig = FileConfiguration.createDefault();
38 |
39 | private static final Logger logger = LoggerFactory.getLogger(StableH2HPeer.class);
40 |
41 | static {
42 | // increase timeouts
43 | ConnectionBean.DEFAULT_CONNECTION_TIMEOUT_TCP = 20000;
44 | ConnectionBean.DEFAULT_TCP_IDLE_SECONDS = 12;
45 | ConnectionBean.DEFAULT_UDP_IDLE_SECONDS = 12;
46 | }
47 |
48 | public static void main(String[] args) throws UnknownHostException {
49 | Config config = ConfigFactory.load("deployment-single.conf");
50 | int port = config.getInt("Port");
51 | boolean bootstrapEnabled = config.getBoolean("Bootstrap.enabled");
52 | String inetString = config.getString("Bootstrap.address");
53 | InetAddress bootstrapAddress = InetAddress.getByName(inetString);
54 | int bootstrapPort = config.getInt("Bootstrap.port");
55 |
56 | InetAddress externalAddress = null;
57 | String externalAddressString = config.getString("ExternalAddress");
58 | if (!"auto".equalsIgnoreCase(externalAddressString)) {
59 | externalAddress = InetAddress.getByName(externalAddressString);
60 | }
61 |
62 | boolean acceptData = config.getBoolean("AcceptData");
63 |
64 | boolean enableRelaying = config.getBoolean("Relay.enabled");
65 | AndroidRelayServerConfig androidServer = null;
66 | if (enableRelaying) {
67 | String gcmKey = config.getString("Relay.GCM.api-key");
68 | long bufferTimeout = config.getDuration("Relay.GCM.buffer-age-limit", TimeUnit.MILLISECONDS);
69 | MessageBufferConfiguration buffer = new MessageBufferConfiguration().bufferAgeLimit(bufferTimeout);
70 | androidServer = new AndroidRelayServerConfig(gcmKey, 5, buffer);
71 | }
72 |
73 | new StableH2HPeer(port, bootstrapEnabled, bootstrapAddress, bootstrapPort, externalAddress, acceptData,
74 | enableRelaying, androidServer);
75 | }
76 |
77 | public StableH2HPeer(int port, boolean bootstrapEnabled, InetAddress bootstrapAddress, int bootstrapPort,
78 | InetAddress externalAddress, boolean acceptData, boolean enableRelaying, AndroidRelayServerConfig androidConfig) {
79 |
80 | IH2HNode node = H2HNode.createNode(fileConfig);
81 | NetworkConfiguration netConf = NetworkConfiguration.createInitial();
82 | netConf.setPort(port);
83 | if (bootstrapEnabled) {
84 | netConf.setBootstrap(bootstrapAddress);
85 | netConf.setBootstrapPort(bootstrapPort);
86 | }
87 |
88 | if (!node.connect(netConf)) {
89 | logger.error("Peer cannot connect!");
90 | return;
91 | }
92 |
93 | if (externalAddress != null) {
94 | logger.debug("Binding to address {}", externalAddress);
95 | PeerAddress peerAddress = node.getPeer().peerBean().serverPeerAddress().changeAddress(externalAddress);
96 | node.getPeer().peerBean().serverPeerAddress(peerAddress);
97 | }
98 |
99 | if (!acceptData) {
100 | logger.debug("Denying all data requests on this peer");
101 | H2HStorageMemory storageLayer = (H2HStorageMemory) node.getPeer().storageLayer();
102 | storageLayer.setPutMode(StorageMemoryPutMode.DENY_ALL);
103 | }
104 |
105 | // start relaying if required
106 | if (enableRelaying) {
107 | logger.debug("Starting relay functionality...");
108 |
109 | PeerBuilderNAT nat = new PeerBuilderNAT(node.getPeer().peer());
110 | if (androidConfig != null) {
111 | nat.addRelayServerConfiguration(RelayType.ANDROID, androidConfig);
112 | }
113 | nat.start();
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/src/main/resources/deployment-single.conf:
--------------------------------------------------------------------------------
1 | #######################################################
2 | # Configuration for the Hive2Hive Android Stable Peer #
3 | #######################################################
4 |
5 | # Set the port to bind. On one machine, it is not possible to run multiple instances on the same port
6 | Port=4622
7 |
8 | # Either set the IP address, a host name or use "auto" in case the address should be determined automatically.
9 | # Note that the external IP address will not be detected automatically if this node is the initial. In this case,
10 | # you need to set it here manually.
11 | ExternalAddress = auto
12 |
13 | Bootstrap {
14 | # Enable bootstrapping if this peer is not the initial one.
15 | enabled = false
16 | # The address to connect to
17 | address = 127.0.0.1
18 | # The port to connect to
19 | port = 4622
20 | }
21 |
22 | # You can configure this peer to decline any put request or replication data
23 | AcceptData = true
24 |
25 | # Allows unreachable peers to connect to this node. This peer then forwards messages
26 | Relay {
27 | enabled = true
28 |
29 | # Enable GCM at some peers to serve as battery-saving relay peers
30 | GCM {
31 | api-key = "your-api-key"
32 | buffer-age-limit = 20s
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/src/main/resources/deployment.conf:
--------------------------------------------------------------------------------
1 | #######################################################
2 | # Configuration for the Hive2Hive Android Stable Peer #
3 | #######################################################
4 |
5 | # The number of peers to start (usually ~5-10)
6 | NumPeers = 5
7 |
8 | # The start port for the first peer
9 | StartPort=4622
10 |
11 | # Either set the IP address, a host name or use "auto" in case the address should be determined automatically.
12 | # Note that the external IP address will not be detected automatically if this node is the initial. In this case,
13 | # you need to set it here manually.
14 | ExternalAddress = auto
15 |
16 | # You can configure this peer to decline any put request or replication data
17 | AcceptData = true
18 |
19 | # Allows unreachable peers to connect to this node. This peer then forwards messages
20 | Relay {
21 | enabled = true
22 |
23 | # Enable GCM at some peers to serve as battery-saving relay peers
24 | GCM {
25 | api-key = "your-api-key"
26 | buffer-age-limit = 20s
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/org.hive2hive.android.deployment/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %d{HH:mm:ss} %-12.-12([%thread])[%-5level] %logger{0} - %msg%n
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .gitignore support plugin (hsz.mobi)
2 | ### Android template
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio files (IntelliJ)
31 | .idea/
32 |
33 | # Apple files
34 | .DS_Store
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/.name:
--------------------------------------------------------------------------------
1 | org.hive2hive.mobile
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/dictionaries/nrutishauser.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | rutishauser
5 |
6 |
7 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/apktool_lib_1_4_4_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/appcompat_v7_20_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/commons_io_2_4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/core_1_51_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/el_api_2_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/fst_2_23.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/gcm_server_1_0_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/javassist_3_18_1_GA.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/json_simple_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/logback_android_classic_1_1_1_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/logback_android_core_1_1_1_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/mbassador_1_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/netty_buffer_4_0_25_Final.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/netty_common_4_0_25_Final.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/netty_transport_4_0_25_Final.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/objenesis_2_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/org_hive2hive_core_1_2_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/org_hive2hive_processframework_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/play_services_4_2_42.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/prov_1_51_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/slf4j_api_1_7_6.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/support_annotations_20_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/support_v4_20_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/tomp2p_android_5_0_Beta5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/tomp2p_core_5_0_Beta5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/tomp2p_dht_5_0_Beta5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/tomp2p_nat_5_0_Beta5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/libraries/tomp2p_replication_5_0_Beta5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'idea'
3 |
4 | android {
5 | compileSdkVersion 19
6 | buildToolsVersion '21.1.2'
7 | defaultConfig {
8 | applicationId 'org.hive2hive.mobile'
9 | minSdkVersion 14
10 | targetSdkVersion 19
11 | versionCode 3
12 | versionName '1.0.2'
13 | }
14 |
15 | dexOptions {
16 | // incremental true
17 | javaMaxHeapSize "4g"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled true
23 | zipAlignEnabled true
24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25 | buildConfigField "String", "DEFAULT_BOOTSTRAP_ADDRESS", "\"bootstrap.example.com\""
26 | buildConfigField "String", "H2H_VERSION", "\"1.2.2\""
27 | buildConfigField "int", "DEFAULT_BOOTSTRAP_PORT", "4622"
28 | buildConfigField "int", "PEER_MAP_UPDATE_INTERVAL", "120"
29 | }
30 | debug {
31 | // minifyEnabled true
32 | // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | buildConfigField "String", "DEFAULT_BOOTSTRAP_ADDRESS", "\"192.168.1.30\""
34 | buildConfigField "String", "H2H_VERSION", "\"1.2.2\""
35 | buildConfigField "int", "DEFAULT_BOOTSTRAP_PORT", "4622"
36 | buildConfigField "int", "PEER_MAP_UPDATE_INTERVAL", "120"
37 | }
38 | }
39 |
40 | productFlavors {
41 | // Define separate dev and prod product flavors.
42 | dev {
43 | // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
44 | // to pre-dex each module and produce an APK that can be tested on
45 | // Android Lollipop without time consuming dex merging processes.
46 | minSdkVersion 19
47 | }
48 | prod {
49 | // The actual minSdkVersion for the application.
50 | minSdkVersion 14
51 | }
52 | }
53 |
54 | packagingOptions {
55 | exclude 'META-INF/io.netty.versions.properties'
56 | exclude 'META-INF/INDEX.LIST'
57 | exclude 'logback.xml'
58 | }
59 | compileOptions {
60 | sourceCompatibility JavaVersion.VERSION_1_7
61 | targetCompatibility JavaVersion.VERSION_1_7
62 | }
63 | }
64 |
65 | repositories {
66 | maven { url 'http://tomp2p.net/dev/mvn/' }
67 | maven { url '// maven { url \'http://repo.hive2hive.org\' }' }
68 | mavenLocal()
69 | }
70 |
71 | dependencies {
72 | compile fileTree(dir: 'libs', include: ['*.jar'])
73 | compile ('net.tomp2p:tomp2p-android:5.0-Beta5') {
74 | exclude group: 'org.bitlet'
75 | }
76 |
77 | compile ('org.hive2hive:org.hive2hive.core:1.2.2') {
78 | exclude group: 'org.bouncycastle'
79 | }
80 |
81 | compile 'com.madgag.spongycastle:prov:1.51.0.0'
82 | compile 'com.github.tony19:logback-android-classic:1.1.1-3'
83 | compile 'com.google.android.gms:play-services:4.2.42'
84 | compile 'com.android.support:appcompat-v7:20.0.0'
85 | }
86 |
87 | idea {
88 | module {
89 | //if you love browsing Javadoc and sources
90 | downloadJavadoc = true
91 | downloadSources = true
92 | }
93 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | -dontwarn javax.mail.**
20 | -dontwarn javax.swing.**
21 | -dontwarn javax.naming.**
22 | -dontwarn sun.misc.Unsafe
23 | -dontwarn sun.misc.Cleaner
24 | -dontwarn sun.nio.ch.FileChannelImpl
25 | -dontwarn sun.reflect.ReflectionFactory
26 | -dontwarn java.nio.channels.**
27 | -dontwarn org.apache.log4j.**
28 | -dontwarn ch.qos.logback.core.net.**
29 | -dontwarn org.apache.commons.logging.LogFactory
30 | -dontwarn com.sun.jdi.**
31 | -dontwarn java.beans.**
32 | -dontwarn java.awt.**
33 | -dontwarn java.applet.Applet
34 | -dontwarn java.net.ProtocolFamily
35 | -dontwarn java.net.StandardProtocolFamily
36 | -dontwarn net.tomp2p.holep.testapp.**
37 | -dontwarn org.bitlet.weupnp.**
38 | -dontwarn org.bouncycastle.**
39 |
40 | # Fix for netty
41 | -keepattributes Signature,InnerClasses
42 | -keepclasseswithmembers class io.netty.** { *; }
43 | -keepnames class sun.misc.Unsafe { *; }
44 |
45 | # For MBassador event bus
46 | -keepattributes *Annotation*
47 | -keep class javax.el.**,net.engio.**,android.support.annotation.** { *; }
48 | -keep class org.hive2hive.mobile.files.AndroidFileEventListener { *; }
49 | -keep class org.hive2hive.core.events.** { *; }
50 |
51 | # For FST serializer and encryption
52 | -keep class org.nustaq.**,javassist.**,org.objenesis.** { *; }
53 | -keep class org.spongycastle.** { *; }
54 | -keepclasseswithmembers class org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey { *; }
55 | -keepclasseswithmembers class org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey { *; }
56 | -keepclasseswithmembers class org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey { *; }
57 |
58 | #-keepclasseswithmembernames class org.hive2hive.core.**,net.tomp2p.** { *; }
59 |
60 | # Keep compatibility for serialized classes
61 | -keepnames class * implements java.io.Serializable
62 | -keepclassmembers class * implements java.io.Serializable {
63 | static final long serialVersionUID;
64 | private static final java.io.ObjectStreamField[] serialPersistentFields;
65 | !static !transient ;
66 | private void writeObject(java.io.ObjectOutputStream);
67 | private void readObject(java.io.ObjectInputStream);
68 | java.lang.Object writeReplace();
69 | java.lang.Object readResolve();
70 | }
71 |
72 | # For debug
73 | #-keep class ch.qos.** { *; }
74 | #-keep class org.slf4j.** { *; }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/androidTest/java/org/hive2hive/mobile/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
46 |
49 |
50 |
55 |
56 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/assets/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/H2HApplication.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import net.tomp2p.connection.ConnectionBean;
7 | import net.tomp2p.dht.PeerDHT;
8 | import net.tomp2p.relay.buffer.BufferRequestListener;
9 |
10 | import org.hive2hive.core.H2HConstants;
11 | import org.hive2hive.core.api.interfaces.IH2HNode;
12 | import org.hive2hive.core.api.interfaces.INetworkConfiguration;
13 | import org.hive2hive.core.network.IPeerHolder;
14 | import org.hive2hive.mobile.common.ApplicationHelper;
15 | import org.hive2hive.mobile.common.ConnectionMode;
16 | import org.hive2hive.mobile.common.RelayMode;
17 | import org.hive2hive.mobile.files.AndroidFile;
18 |
19 | /**
20 | * To be able to configure some things when the application starts / ends / ...
21 | */
22 | public class H2HApplication extends Application implements IPeerHolder {
23 |
24 | private BufferRequestListener bufferListener;
25 | private IH2HNode h2hNode;
26 | private RelayMode relayMode;
27 | private INetworkConfiguration networkConfig;
28 | private AndroidFile treeRoot;
29 | private ConnectionMode lastMode;
30 | private String userId;
31 |
32 | @Override
33 | public void onCreate() {
34 | super.onCreate();
35 |
36 | // Prevent using IPv6, prefer IPv4
37 | System.setProperty("java.net.preferIPv4Stack", "true");
38 |
39 | lastMode = ApplicationHelper.getConnectionMode(this);
40 |
41 | // ConnectionChangeListener connectionChangeListener = new ConnectionChangeListener(this);
42 | // IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
43 | // registerReceiver(connectionChangeListener, filter);
44 |
45 | // increase timeouts
46 | ConnectionBean.DEFAULT_CONNECTION_TIMEOUT_TCP = 20000;
47 | ConnectionBean.DEFAULT_TCP_IDLE_SECONDS = 12;
48 | ConnectionBean.DEFAULT_UDP_IDLE_SECONDS = 12;
49 | }
50 |
51 | @Override
52 | protected void attachBaseContext(Context base) {
53 | super.attachBaseContext(base);
54 | // enable multidex
55 | // MultiDex.install(this);
56 | }
57 |
58 | /**
59 | * Singleton-like application data that needs to be present in the whole application.
60 | * Note that the content of this data is removed once the process is killed.
61 | */
62 |
63 | public void relayMode(RelayMode relayMode) {
64 | this.relayMode = relayMode;
65 | }
66 |
67 | public RelayMode relayMode() {
68 | return relayMode;
69 | }
70 |
71 | public void bufferListener(BufferRequestListener bufferListener) {
72 | this.bufferListener = bufferListener;
73 | }
74 |
75 | public BufferRequestListener bufferListener() {
76 | return bufferListener;
77 | }
78 |
79 | public void h2hNode(IH2HNode h2hNode) {
80 | this.h2hNode = h2hNode;
81 | }
82 |
83 | public IH2HNode h2hNode() {
84 | return h2hNode;
85 | }
86 |
87 | public void networkConfig(INetworkConfiguration networkConfig) {
88 | this.networkConfig = networkConfig;
89 | }
90 |
91 | public INetworkConfiguration networkConfig() {
92 | return networkConfig;
93 | }
94 |
95 |
96 | public void logout() {
97 | treeRoot = null;
98 | userId = null;
99 | }
100 |
101 | /**
102 | * Holds the latest file list of the currently logged in user
103 | *
104 | * @param treeRoot
105 | */
106 | public void currentTree(AndroidFile treeRoot) {
107 | this.treeRoot = treeRoot;
108 | }
109 |
110 | /**
111 | * @return the last file taste list or null
if not fetched yet
112 | */
113 | public AndroidFile currentTree() {
114 | return treeRoot;
115 | }
116 |
117 | public void currentUser(String userId) {
118 | this.userId = userId;
119 | }
120 |
121 | public String currentUser() {
122 | return userId;
123 | }
124 |
125 | @Override
126 | public PeerDHT getPeer() {
127 | if (h2hNode == null) {
128 | return null;
129 | }
130 | return h2hNode.getPeer();
131 | }
132 |
133 | /**
134 | * @return the last connection mode
135 | */
136 | public ConnectionMode lastMode() {
137 | return lastMode;
138 | }
139 |
140 | /**
141 | * Set the last mode in order to detect changes when the {@link org.hive2hive.mobile.connection.ConnectionChangeListener} is triggered
142 | */
143 | public void lastMode(ConnectionMode lastMode) {
144 | this.lastMode = lastMode;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/AndroidFileAgent.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import org.apache.commons.io.FileUtils;
7 | import org.hive2hive.core.file.IFileAgent;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 |
14 | /**
15 | * Files are located at a public location, whereas cache is stored internally
16 | * Created by Nico Rutishauser on 24.11.14.
17 | */
18 | public class AndroidFileAgent implements IFileAgent {
19 |
20 | private static final Logger LOG = LoggerFactory.getLogger(AndroidFileAgent.class);
21 |
22 | private final File rootDir;
23 | private final File cacheDir;
24 |
25 | public AndroidFileAgent(Context context, String username) {
26 | cacheDir = new File(context.getCacheDir(), username);
27 | rootDir = getStorageLocation(context, username);
28 | if (!rootDir.exists() && !rootDir.mkdirs()) {
29 | LOG.error("Root directory not created");
30 | }
31 | }
32 |
33 | public static File getStorageLocation(Context context, String username) {
34 | File folder;
35 | if (ApplicationHelper.isExternalStorageWritable()) {
36 | // Get the directory for the user's public pictures directory.
37 | folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Hive2Hive");
38 | } else {
39 | LOG.info("Need to save logs to internal storage because external is not available");
40 | folder = new File(context.getFilesDir(), "Hive2Hive");
41 | }
42 |
43 | if (username == null) {
44 | return folder;
45 | } else {
46 | return new File(folder, username);
47 | }
48 | }
49 |
50 | @Override
51 | public File getRoot() {
52 | return rootDir;
53 | }
54 |
55 | @Override
56 | public void writeCache(String key, byte[] data) throws IOException {
57 | File file = new File(cacheDir, key);
58 | FileUtils.writeByteArrayToFile(file, data);
59 | }
60 |
61 | @Override
62 | public byte[] readCache(String key) throws IOException {
63 | File file = new File(cacheDir, key);
64 | return FileUtils.readFileToByteArray(file);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/ApplicationHelper.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.net.ConnectivityManager;
7 | import android.net.NetworkInfo;
8 | import android.net.Uri;
9 | import android.os.Environment;
10 | import android.os.Process;
11 | import android.provider.OpenableColumns;
12 |
13 | import com.google.android.gms.common.ConnectionResult;
14 | import com.google.android.gms.common.GooglePlayServicesUtil;
15 |
16 | import org.apache.http.HttpEntity;
17 | import org.apache.http.HttpResponse;
18 | import org.apache.http.client.HttpClient;
19 | import org.apache.http.client.methods.HttpGet;
20 | import org.apache.http.impl.client.DefaultHttpClient;
21 | import org.apache.http.util.EntityUtils;
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 |
25 | import java.net.Inet4Address;
26 | import java.net.InetAddress;
27 | import java.net.NetworkInterface;
28 | import java.net.SocketException;
29 | import java.util.Enumeration;
30 |
31 | /**
32 | * Created by Nico Rutishauser on 08.09.14.
33 | */
34 | public class ApplicationHelper {
35 |
36 | private static final Logger LOG = LoggerFactory.getLogger(ApplicationHelper.class);
37 | private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
38 | private static final String EXTERNAL_IP_LOOKUP_URL = "http://wtfismyip.com/text";
39 |
40 | /**
41 | * Kills the application immediately. Only use in emergency!
42 | */
43 | public static void killApplication() {
44 | android.os.Process.killProcess(Process.myPid());
45 | }
46 |
47 | /**
48 | * Check the device to make sure it has the Google Play Services APK. If
49 | * it doesn't, display a dialog that allows users to download the APK from
50 | * the Google Play Store or enable it in the device's system settings.
51 | */
52 | public static boolean checkPlayServices(Activity activity) {
53 | int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
54 | if (resultCode != ConnectionResult.SUCCESS) {
55 | if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
56 | GooglePlayServicesUtil.getErrorDialog(resultCode, activity,
57 | PLAY_SERVICES_RESOLUTION_REQUEST).show();
58 | } else {
59 | LOG.info("This device is not supported.");
60 | }
61 | return false;
62 | }
63 | return true;
64 | }
65 |
66 | /* Checks if external storage is available for read and write */
67 | public static boolean isExternalStorageWritable() {
68 | String state = Environment.getExternalStorageState();
69 | if (Environment.MEDIA_MOUNTED.equals(state)) {
70 | return true;
71 | }
72 | return false;
73 | }
74 |
75 | /**
76 | * Maps a URI starting with 'content:' to a real file name
77 | */
78 | public static String getFileNameContentURI(Context context, Uri contentUri) {
79 | Cursor returnCursor =
80 | context.getContentResolver().query(contentUri, null, null, null, null);
81 | int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
82 | returnCursor.moveToFirst();
83 | return returnCursor.getString(nameIndex);
84 | }
85 |
86 | /**
87 | * @return the current connection mode
88 | */
89 | public static ConnectionMode getConnectionMode(Context context) {
90 | ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
91 | NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
92 | if (wifiInfo.isConnected()) {
93 | return ConnectionMode.WIFI;
94 | }
95 | NetworkInfo mobileInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
96 | if (mobileInfo.isConnected()) {
97 | return ConnectionMode.CELLULAR;
98 | }
99 |
100 | return ConnectionMode.OFFLINE;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/BaseProgressTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | import android.app.ProgressDialog;
4 | import android.os.AsyncTask;
5 |
6 | import org.hive2hive.mobile.H2HApplication;
7 |
8 | /**
9 | * @author Nico
10 | */
11 | public abstract class BaseProgressTask extends AsyncTask {
12 |
13 | protected final H2HApplication context;
14 | private final ISuccessFailListener listener;
15 | private final ProgressDialog progressDialog;
16 |
17 | private String[] progressMessages;
18 |
19 | public BaseProgressTask(H2HApplication context, ISuccessFailListener listener, ProgressDialog progressDialog) {
20 | this.context = context;
21 | this.listener = listener;
22 | this.progressDialog = progressDialog;
23 | }
24 |
25 | @Override
26 | protected void onPreExecute() {
27 | progressMessages = getProgressMessages();
28 |
29 | progressDialog.setProgress(0);
30 | progressDialog.setMax(progressMessages.length);
31 | progressDialog.setIndeterminate(false);
32 |
33 | progressDialog.setMessage(progressMessages[0]);
34 | progressDialog.show();
35 | }
36 |
37 | protected abstract String[] getProgressMessages();
38 |
39 | @Override
40 | protected final void onProgressUpdate(Integer... values) {
41 | super.onProgressUpdate(values);
42 | if (values != null && values.length > 0) {
43 | if (values[0] < progressMessages.length) {
44 | progressDialog.setMessage(progressMessages[values[0]]);
45 | }
46 | progressDialog.setProgress(values[0]);
47 | }
48 | }
49 |
50 | @Override
51 | protected void onPostExecute(Boolean success) {
52 | if (success) {
53 | listener.onSuccess();
54 | } else {
55 | listener.onFail();
56 | }
57 |
58 | // close the progress dialog in any case
59 | progressDialog.dismiss();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/ConnectionMode.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | /**
4 | * @author Nico
5 | */
6 | public enum ConnectionMode {
7 | WIFI("Wifi"),
8 | CELLULAR("3G"),
9 | OFFLINE("Offline");
10 |
11 | private final String name;
12 |
13 | private ConnectionMode(String name) {
14 | this.name = name;
15 | }
16 |
17 | public String getName() {
18 | return name;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/ISuccessFailListener.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | /**
4 | * Created by Nico Rutishauser on 24.08.14.
5 | */
6 | public interface ISuccessFailListener {
7 |
8 | void onSuccess();
9 |
10 | void onFail();
11 | }
12 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/RelayMode.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | /**
4 | * Created by Nico Rutishauser
5 | */
6 | public enum RelayMode {
7 | GCM(0),
8 | TCP(1),
9 | FULL(2);
10 |
11 | private final int spinnerPosition;
12 |
13 | private RelayMode(int spinnerPosition) {
14 | this.spinnerPosition = spinnerPosition;
15 | }
16 |
17 | public int spinnerPosition() {
18 | return spinnerPosition;
19 | }
20 |
21 | public static RelayMode getByPosition(int pos) {
22 | for (RelayMode mode : RelayMode.values()) {
23 | if (mode.spinnerPosition() == pos) {
24 | return mode;
25 | }
26 | }
27 |
28 | // by default
29 | return GCM;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/common/UserPermissionComparator.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.common;
2 |
3 | import org.hive2hive.core.model.PermissionType;
4 | import org.hive2hive.core.model.UserPermission;
5 |
6 | import java.util.Comparator;
7 |
8 | /**
9 | * @author Nico
10 | */
11 | public class UserPermissionComparator implements Comparator {
12 |
13 | @Override
14 | public int compare(UserPermission perm1, UserPermission perm2) {
15 | if (perm1.getPermission() == perm2.getPermission()) {
16 | return perm1.getUserId().toLowerCase().compareTo(perm2.getUserId().toLowerCase());
17 | } else {
18 | return perm1.getPermission() == PermissionType.WRITE ? -1 : 1;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/connection/ConnectionChangeListener.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.connection;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import org.hive2hive.mobile.H2HApplication;
8 | import org.hive2hive.mobile.common.ApplicationHelper;
9 | import org.hive2hive.mobile.common.ConnectionMode;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | /**
14 | * @author Nico
15 | */
16 | public class ConnectionChangeListener extends BroadcastReceiver {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(ConnectionChangeListener.class);
19 | private final H2HApplication application;
20 |
21 | public ConnectionChangeListener(H2HApplication application) {
22 | this.application = application;
23 | }
24 |
25 | @Override
26 | public void onReceive(Context context, Intent intent) {
27 | ConnectionMode mode = ApplicationHelper.getConnectionMode(context);
28 | if (application.lastMode() == mode) {
29 | LOG.trace("Mode did not change, is still {}", mode);
30 | return;
31 | } else if (application.h2hNode() == null || !application.h2hNode().isConnected()) {
32 | LOG.trace("Connectivity mode did change to {} but node is not connected", mode);
33 | return;
34 | }
35 |
36 | LOG.debug("Network connection changed to {}", mode);
37 |
38 | // TODO take actions (reconnect node)
39 |
40 | application.lastMode(mode);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/connection/ConnectionSetupTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.connection;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.provider.Settings;
7 |
8 | import net.tomp2p.futures.FutureBootstrap;
9 | import net.tomp2p.nat.FutureRelayNAT;
10 | import net.tomp2p.nat.PeerBuilderNAT;
11 | import net.tomp2p.nat.PeerNAT;
12 | import net.tomp2p.peers.PeerAddress;
13 | import net.tomp2p.relay.RelayClientConfig;
14 | import net.tomp2p.relay.android.AndroidRelayClientConfig;
15 | import net.tomp2p.relay.buffer.BufferRequestListener;
16 | import net.tomp2p.relay.tcp.TCPRelayClientConfig;
17 |
18 | import org.hive2hive.core.H2HConstants;
19 | import org.hive2hive.core.api.H2HNode;
20 | import org.hive2hive.core.api.configs.FileConfiguration;
21 | import org.hive2hive.core.api.configs.NetworkConfiguration;
22 | import org.hive2hive.core.api.interfaces.IH2HNode;
23 | import org.hive2hive.core.serializer.FSTSerializer;
24 | import org.hive2hive.core.serializer.IH2HSerialize;
25 | import org.hive2hive.mobile.BuildConfig;
26 | import org.hive2hive.mobile.H2HApplication;
27 | import org.hive2hive.mobile.R;
28 | import org.hive2hive.mobile.common.ApplicationHelper;
29 | import org.hive2hive.mobile.common.BaseProgressTask;
30 | import org.hive2hive.mobile.common.ISuccessFailListener;
31 | import org.hive2hive.mobile.common.RelayMode;
32 | import org.hive2hive.mobile.gcm.GCMRegistrationUtil;
33 | import org.hive2hive.mobile.security.SCSecurityClassProvider;
34 | import org.hive2hive.mobile.security.SpongyCastleEncryption;
35 | import org.slf4j.Logger;
36 | import org.slf4j.LoggerFactory;
37 |
38 | import java.net.InetAddress;
39 | import java.net.UnknownHostException;
40 | import java.util.Collection;
41 | import java.util.UUID;
42 |
43 | /**
44 | * @author Nico
45 | */
46 | public class ConnectionSetupTask extends BaseProgressTask {
47 |
48 | private static final Logger LOG = LoggerFactory.getLogger(ConnectionSetupTask.class);
49 |
50 | private final String bootstrapAddressString;
51 | private final int bootstrapPort;
52 | private final long gcmSenderId;
53 |
54 | private final SharedPreferences prefs;
55 |
56 | private String registrationId;
57 | /**
58 | * variables that will be stored in the context
59 | */
60 | private final RelayMode relayMode;
61 | private NetworkConfiguration networkConfig;
62 | private BufferRequestListener bufferListener;
63 | private IH2HNode h2hNode;
64 | private Collection boostrapAddresses;
65 |
66 | public ConnectionSetupTask(String bootstrapAddress, int bootstrapPort, RelayMode relayMode, long gcmSenderId, H2HApplication context, ISuccessFailListener listener, ProgressDialog progressDialog) {
67 | super(context, listener, progressDialog);
68 | this.bootstrapAddressString = bootstrapAddress;
69 | this.bootstrapPort = bootstrapPort;
70 | this.relayMode = relayMode;
71 | this.gcmSenderId = gcmSenderId;
72 | this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
73 | }
74 |
75 | @Override
76 | protected String[] getProgressMessages() {
77 | String[] progressMessages = new String[4];
78 | progressMessages[0] = context.getString(R.string.progress_connect_resolve_address);
79 | progressMessages[1] = context.getString(R.string.progress_connect_bootstrapping);
80 | progressMessages[2] = context.getString(R.string.progress_connect_register_gcm);
81 | progressMessages[3] = context.getString(R.string.progress_connect_relay);
82 | return progressMessages;
83 | }
84 |
85 | @Override
86 | protected Boolean doInBackground(Void... voids) {
87 | publishProgress(0);
88 | try {
89 | InetAddress bootstrapAddress = InetAddress.getByName(bootstrapAddressString);
90 | String deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
91 | if (deviceId == null || deviceId.isEmpty()) {
92 | deviceId = UUID.randomUUID().toString();
93 | }
94 | LOG.debug("Using node ID: {}", deviceId);
95 |
96 | int bindPort = prefs.getInt(context.getString(R.string.pref_port_key), H2HConstants.H2H_PORT);
97 | LOG.debug("Binding port {}", bindPort);
98 |
99 | networkConfig = NetworkConfiguration.create(deviceId, bootstrapAddress, bootstrapPort).setPort(bindPort);
100 | } catch (UnknownHostException e) {
101 | LOG.error("Cannot resolve host {}", bootstrapAddressString, e);
102 | return false;
103 | }
104 |
105 | publishProgress(1);
106 | if (!createPeer()) {
107 | return false;
108 | }
109 |
110 | publishProgress(2);
111 | if (!registerGCM()) {
112 | return false;
113 | }
114 |
115 | publishProgress(3);
116 | if (!connectNAT()) {
117 | return false;
118 | }
119 |
120 | // store the peerNAT in the application context
121 | context.h2hNode(h2hNode);
122 | context.networkConfig(networkConfig);
123 | context.bufferListener(bufferListener);
124 | context.relayMode(relayMode);
125 |
126 | LOG.debug("Peer setup finished successfully");
127 | publishProgress(4);
128 | return true;
129 | }
130 |
131 | /**
132 | * Creates a peer and returns true if successful
133 | */
134 | private boolean createPeer() {
135 | IH2HSerialize serializer = new FSTSerializer(false, new SCSecurityClassProvider());
136 | h2hNode = H2HNode.createNode(FileConfiguration.createDefault(), new SpongyCastleEncryption(serializer), serializer);
137 | if (h2hNode.connect(networkConfig)) {
138 | LOG.debug("H2HNode successfully created.");
139 |
140 | FutureBootstrap bootstrap = h2hNode.getPeer().peer().bootstrap().inetAddress(networkConfig.getBootstrapAddress()).ports(networkConfig.getBootstrapPort()).start();
141 | bootstrap.awaitUninterruptibly();
142 | boostrapAddresses = bootstrap.bootstrapTo();
143 | return true;
144 | } else {
145 | LOG.error("H2HNode cannot connect.");
146 | return false;
147 | }
148 |
149 |
150 | }
151 |
152 | /**
153 | * Register Google Cloud Messaging. Returns true if successful
154 | */
155 | private boolean registerGCM() {
156 | if (relayMode == RelayMode.GCM) {
157 | registrationId = GCMRegistrationUtil.getRegistrationId(context, gcmSenderId);
158 | return registrationId != null;
159 | } else {
160 | // don't require a GCM registration id because not necessary
161 | return true;
162 | }
163 | }
164 |
165 | /**
166 | * Connects to the relay node and returns true if successful
167 | */
168 | private boolean connectNAT() {
169 | int mapUpdateInterval = BuildConfig.PEER_MAP_UPDATE_INTERVAL;
170 | String mapUpdateIntervalString = prefs.getString(context.getString(R.string.pref_map_update_interval_key), String.valueOf(mapUpdateInterval));
171 | try {
172 | mapUpdateInterval = Integer.valueOf(mapUpdateIntervalString);
173 | LOG.debug("Use configured map update interval of {}s", mapUpdateInterval);
174 | } catch (NumberFormatException e) {
175 | LOG.warn("Cannot parse the invalid map update interval string '{}'. Use default value {}s", mapUpdateIntervalString, mapUpdateInterval);
176 | }
177 |
178 | RelayClientConfig config;
179 | switch (relayMode) {
180 | case FULL:
181 | // don't set up any NAT
182 | LOG.warn("Don't use relay functionality. Make sure to not be behind a firewall!");
183 | return true;
184 | case GCM:
185 | config = new AndroidRelayClientConfig(registrationId, mapUpdateInterval).manualRelays(boostrapAddresses);
186 | break;
187 | case TCP:
188 | config = new TCPRelayClientConfig().manualRelays(boostrapAddresses).peerMapUpdateInterval(mapUpdateInterval);
189 | break;
190 | default:
191 | LOG.debug("Invalid relay mode {}", relayMode);
192 | return false;
193 | }
194 | LOG.debug("Use {} as relay type. Map updateView interval is {}s", relayMode, mapUpdateInterval);
195 |
196 | PeerNAT peerNat = new PeerBuilderNAT(h2hNode.getPeer().peer()).start();
197 | FutureRelayNAT futureRelayNAT = peerNat.startRelay(config, boostrapAddresses.iterator().next()).awaitUninterruptibly();
198 | if (futureRelayNAT.isSuccess()) {
199 | LOG.debug("Successfully connected to Relay.");
200 | bufferListener = futureRelayNAT.bufferRequestListener();
201 | return true;
202 | } else {
203 | LOG.error("Cannot connect to Relay. Reason: {}", futureRelayNAT.failedReason());
204 | return false;
205 | }
206 | }
207 |
208 | @Override
209 | protected void onPostExecute(Boolean success) {
210 | if (!success && h2hNode != null) {
211 | h2hNode.disconnect();
212 | }
213 | super.onPostExecute(success);
214 | }
215 |
216 | @Override
217 | protected void onCancelled(Boolean aBoolean) {
218 | if (h2hNode != null) {
219 | h2hNode.disconnect();
220 | }
221 |
222 | super.onCancelled(aBoolean);
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/connection/DisconnectTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.connection;
2 |
3 | import android.app.ProgressDialog;
4 |
5 | import org.hive2hive.core.api.interfaces.IH2HNode;
6 | import org.hive2hive.mobile.H2HApplication;
7 | import org.hive2hive.mobile.R;
8 | import org.hive2hive.mobile.common.BaseProgressTask;
9 | import org.hive2hive.mobile.common.ISuccessFailListener;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | /**
14 | * @author Nico
15 | */
16 | public class DisconnectTask extends BaseProgressTask {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(DisconnectTask.class);
19 |
20 | public DisconnectTask(H2HApplication context, ISuccessFailListener listener, ProgressDialog progressDialog) {
21 | super(context, listener, progressDialog);
22 | }
23 |
24 | @Override
25 | protected String[] getProgressMessages() {
26 | return new String[]{context.getString(R.string.progress_disconnect_shutdown)};
27 | }
28 |
29 | @Override
30 | protected Boolean doInBackground(Void... voids) {
31 | IH2HNode node = context.h2hNode();
32 | if (node != null && node.isConnected()) {
33 | LOG.debug("Start disconnecting the peer...");
34 | boolean shutdown = context.h2hNode().disconnect();
35 |
36 | if (shutdown) {
37 | LOG.debug("Successfully shut down the peer.");
38 | context.logout();
39 | context.h2hNode(null);
40 | } else {
41 | LOG.warn("Could not disconnect properly");
42 | }
43 |
44 | return shutdown;
45 | } else {
46 | // no need to disconnect
47 | return true;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/AndroidFile.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import android.widget.ImageView;
4 | import android.widget.ProgressBar;
5 | import android.widget.TextView;
6 |
7 | import org.hive2hive.core.model.PermissionType;
8 | import org.hive2hive.core.model.UserPermission;
9 | import org.hive2hive.core.processes.files.list.FileNode;
10 | import org.hive2hive.core.security.HashUtil;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.io.File;
15 | import java.io.IOException;
16 | import java.util.Set;
17 | import java.util.TreeSet;
18 |
19 | /**
20 | * @author Nico
21 | */
22 | public class AndroidFile implements Comparable {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(AndroidFile.class);
25 |
26 | private final boolean isFile;
27 | private final File file;
28 | private final String path;
29 | private final Set children = new TreeSet<>();
30 | private final Set permissions;
31 | private AndroidFile parent;
32 | private FileState state;
33 |
34 | private TextView detailsView;
35 | private ImageView imageView;
36 | private ProgressBar progressBar;
37 |
38 | /**
39 | * Recursively copy the tree from the @link FileNode}
40 | */
41 | public AndroidFile(FileNode node, AndroidFile parent) {
42 | this.file = node.getFile();
43 | this.isFile = node.isFile();
44 | this.path = node.getPath();
45 | this.parent = parent;
46 | this.permissions = node.getUserPermissions();
47 |
48 | if (node.isFolder()) {
49 | if (node.isShared() && parent != null) {
50 | if (parent.isShared()) {
51 | this.state = FileState.SHARED;
52 | } else {
53 | this.state = FileState.TOP_SHARED;
54 | }
55 | } else {
56 | this.state = FileState.IN_SYNC;
57 | }
58 | for (FileNode child : node.getChildren()) {
59 | children.add(new AndroidFile(child, this));
60 | }
61 | } else if (node.getFile().exists()) {
62 | try {
63 | // check if hash of file same as the hash of the item
64 | if (HashUtil.compare(node.getFile(), node.getMd5())) {
65 | this.state = FileState.IN_SYNC;
66 | } else {
67 | this.state = FileState.OUTDATED;
68 | }
69 | } catch (IOException e) {
70 | LOG.warn("Cannot compare the hash of the item {} with the hash in the user profile", node, e);
71 | this.state = FileState.OUTDATED;
72 | }
73 | } else {
74 | this.state = FileState.ON_AIR;
75 | }
76 | }
77 |
78 | /**
79 | * Default constructor. Add children separately
80 | */
81 | public AndroidFile(File file, boolean isFile, AndroidFile parent, FileState state, Set permissions) {
82 | this.file = file;
83 | this.isFile = isFile;
84 | this.parent = parent;
85 | this.permissions = permissions;
86 |
87 | if (isFile) {
88 | this.path = parent.getPath() + file.getName();
89 | } else {
90 | this.path = parent.getPath() + file.getName() + File.separator;
91 | }
92 | this.state = state;
93 | }
94 |
95 | public boolean isRoot() {
96 | return parent == null;
97 | }
98 |
99 | public boolean isFile() {
100 | return isFile;
101 | }
102 |
103 | public boolean isFolder() {
104 | return !isFile();
105 | }
106 |
107 | public File getFile() {
108 | return file;
109 | }
110 |
111 | public Set getPermissions() {
112 | return permissions;
113 | }
114 |
115 | public boolean canWrite(String userId) {
116 | for (UserPermission permission : permissions) {
117 | if (permission.getPermission() == PermissionType.WRITE && permission.getUserId().equalsIgnoreCase(userId)) {
118 | return true;
119 | }
120 | }
121 | return false;
122 | }
123 |
124 | public boolean isShared() {
125 | return permissions.size() > 1;
126 | }
127 |
128 | public String getPath() {
129 | return path;
130 | }
131 |
132 | public FileState getState() {
133 | return state;
134 | }
135 |
136 | public void setState(FileState state) {
137 | this.state = state;
138 | }
139 |
140 | public void setState(FileState state, FileArrayAdapter adapter) {
141 | this.state = state;
142 | if (imageView != null) {
143 | imageView.setImageDrawable(adapter.getContext().getResources().getDrawable(state.getIconId(isFile())));
144 | }
145 | if (detailsView != null) {
146 | detailsView.setText(state.getMessageId());
147 | }
148 |
149 | adapter.updateView(false);
150 | }
151 |
152 | public Set getChildren() {
153 | return children;
154 | }
155 |
156 | public AndroidFile getParent() {
157 | return parent;
158 | }
159 |
160 | public void setParent(AndroidFile parent) {
161 | this.parent = parent;
162 | }
163 |
164 | public void setDetailsView(TextView detailsView) {
165 | this.detailsView = detailsView;
166 | }
167 |
168 | public void setImageView(ImageView imageView) {
169 | this.imageView = imageView;
170 | }
171 |
172 | public void setProgressBar(ProgressBar progressBar) {
173 | this.progressBar = progressBar;
174 | }
175 |
176 | public ProgressBar getProgressBar() {
177 | return progressBar;
178 | }
179 |
180 | public AndroidFile findByFile(File file) {
181 | if (this.file.equals(file)) {
182 | // can stop the search, we found it here
183 | return this;
184 | }
185 |
186 | for (AndroidFile child : children) {
187 | AndroidFile found = child.findByFile(file);
188 | if (found != null) {
189 | return found;
190 | }
191 | }
192 |
193 | // no child matches
194 | return null;
195 | }
196 |
197 | @Override
198 | public int hashCode() {
199 | return getPath().hashCode();
200 | }
201 |
202 | @Override
203 | public boolean equals(Object o) {
204 | if (o == null) {
205 | return false;
206 | } else if (o instanceof AndroidFile) {
207 | AndroidFile other = ((AndroidFile) o);
208 | return other.isFile == isFile() && other.getPath().equalsIgnoreCase(getPath());
209 | } else {
210 | return false;
211 | }
212 | }
213 |
214 | @Override
215 | public int compareTo(AndroidFile other) {
216 | if (other == null) {
217 | return 1;
218 | } else if (other.isFile() != isFile()) {
219 | // folders first
220 | return isFolder() ? -1 : 1;
221 | } else {
222 | // same type than other, order by default file
223 | return file.getName().toLowerCase().compareTo(other.getFile().getName().toLowerCase());
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/AndroidFileComparator.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import java.util.Comparator;
4 |
5 | /**
6 | * @author Nico
7 | */
8 | public class AndroidFileComparator implements Comparator {
9 |
10 | @Override
11 | public int compare(AndroidFile file1, AndroidFile file2) {
12 | return file1.compareTo(file2);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/AndroidFileEventListener.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import net.engio.mbassy.listener.Handler;
4 | import net.engio.mbassy.listener.Listener;
5 | import net.engio.mbassy.listener.References;
6 |
7 | import org.hive2hive.core.events.framework.interfaces.IFileEventListener;
8 | import org.hive2hive.core.events.framework.interfaces.file.IFileAddEvent;
9 | import org.hive2hive.core.events.framework.interfaces.file.IFileDeleteEvent;
10 | import org.hive2hive.core.events.framework.interfaces.file.IFileMoveEvent;
11 | import org.hive2hive.core.events.framework.interfaces.file.IFileShareEvent;
12 | import org.hive2hive.core.events.framework.interfaces.file.IFileUpdateEvent;
13 | import org.hive2hive.core.model.UserPermission;
14 | import org.hive2hive.mobile.H2HApplication;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import java.io.File;
19 | import java.util.HashMap;
20 | import java.util.HashSet;
21 | import java.util.Map;
22 | import java.util.Set;
23 |
24 | /**
25 | * @author Nico
26 | */
27 | @Listener(references = References.Strong)
28 | public class AndroidFileEventListener implements IFileEventListener {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(AndroidFileEventListener.class);
31 | private final FilesActivity activity;
32 | private final H2HApplication context;
33 |
34 | // used to temporarily mark shared folders correctly
35 | private final Map> currentShareInvitations = new HashMap<>(1);
36 |
37 | public AndroidFileEventListener(FilesActivity activity, H2HApplication context) {
38 | this.activity = activity;
39 | this.context = context;
40 | }
41 |
42 | private FilesFragment getFragment() {
43 | return activity.getCurrentFragment();
44 | }
45 |
46 | private AndroidFile createAndroidFile(File file, boolean isFile, AndroidFile parent) {
47 | FileState state;
48 | Set permissions;
49 | if (isFile) {
50 | state = FileState.ON_AIR;
51 | permissions = new HashSet<>(parent.getPermissions());
52 | } else if (currentShareInvitations.containsKey(file)) {
53 | permissions = currentShareInvitations.remove(file);
54 | state = FileState.SHARED;
55 | } else {
56 | state = FileState.IN_SYNC;
57 | permissions = new HashSet<>(parent.getPermissions());
58 | }
59 |
60 | return new AndroidFile(file, isFile, parent, state, permissions);
61 | }
62 |
63 | @Override
64 | @Handler
65 | public void onFileAdd(IFileAddEvent fileEvent) {
66 | LOG.debug("Remotely added file {}", fileEvent.getFile());
67 | final FilesFragment fragment = getFragment();
68 | final AndroidFile parent = context.currentTree().findByFile(fileEvent.getFile().getParentFile());
69 | if (fragment != null && parent != null) {
70 | final AndroidFile file = createAndroidFile(fileEvent.getFile(), fileEvent.isFile(), parent);
71 | parent.getChildren().add(file);
72 |
73 | // updateView the UI because it's currently watched folder
74 | activity.runOnUiThread(new Runnable() {
75 | @Override
76 | public void run() {
77 | if (parent.equals(activity.getCurrentFolder())) {
78 | fragment.getFileAdapter().add(file);
79 | }
80 |
81 | fragment.getFileAdapter().updateView(true);
82 | }
83 | });
84 | }
85 | }
86 |
87 | @Override
88 | @Handler
89 | public void onFileUpdate(IFileUpdateEvent fileEvent) {
90 | LOG.debug("Remotely updated file {}", fileEvent.getFile());
91 | final AndroidFile file = context.currentTree().findByFile(fileEvent.getFile());
92 | if (file == null) {
93 | return;
94 | }
95 |
96 | file.setState(FileState.OUTDATED);
97 |
98 | // updateView the UI when it's the currently watched folder
99 | final FilesFragment fragment = getFragment();
100 | if (fragment != null && file.getParent().equals(activity.getCurrentFolder())) {
101 | activity.runOnUiThread(new Runnable() {
102 | @Override
103 | public void run() {
104 | file.setState(FileState.OUTDATED, fragment.getFileAdapter());
105 | }
106 | });
107 | }
108 | }
109 |
110 | @Override
111 | @Handler
112 | public void onFileDelete(IFileDeleteEvent fileEvent) {
113 | LOG.debug("Remotely deleted file {}", fileEvent.getFile());
114 | final AndroidFile file = context.currentTree().findByFile(fileEvent.getFile());
115 | if (file == null) {
116 | return;
117 | }
118 |
119 | // remove from model
120 | boolean removed = file.getParent().getChildren().remove(file);
121 | final FilesFragment fragment = getFragment();
122 | if (removed && fragment != null) {
123 | // need to updateView the current view
124 | activity.runOnUiThread(new Runnable() {
125 | @Override
126 | public void run() {
127 | if (file.getParent().equals(activity.getCurrentFolder())) {
128 | fragment.getFileAdapter().remove(file);
129 | }
130 | fragment.getFileAdapter().updateView(false);
131 | }
132 | });
133 | }
134 | }
135 |
136 | @Override
137 | @Handler
138 | public void onFileMove(final IFileMoveEvent fileEvent) {
139 | LOG.debug("Remotely moved file from {} to {}", fileEvent.getSrcFile(), fileEvent.getDstFile());
140 | final AndroidFile srcFile = context.currentTree().findByFile(fileEvent.getSrcFile());
141 | if (srcFile != null) {
142 | // for UI notification
143 | final String oldPath = srcFile.getParent().getPath();
144 | // remove it from the old parent
145 | srcFile.getParent().getChildren().remove(srcFile);
146 |
147 | final AndroidFile dstParent = context.currentTree().findByFile(fileEvent.getDstFile().getParentFile());
148 | if (dstParent != null) {
149 | // add the file to the new parent
150 | srcFile.setParent(dstParent);
151 | srcFile.getPermissions().clear();
152 | srcFile.getPermissions().addAll(dstParent.getPermissions());
153 | dstParent.getChildren().add(srcFile);
154 |
155 | final FilesFragment fragment = getFragment();
156 | if (fragment != null) {
157 | // need to updateView the current view
158 | activity.runOnUiThread(new Runnable() {
159 | @Override
160 | public void run() {
161 | if (oldPath.equals(activity.getCurrentFolder().getPath())) {
162 | fragment.getFileAdapter().remove(srcFile);
163 | } else if (dstParent.equals(activity.getCurrentFolder())) {
164 | fragment.getFileAdapter().add(srcFile);
165 | }
166 | fragment.getFileAdapter().updateView(true);
167 | }
168 | });
169 | }
170 | } else {
171 | LOG.warn("New parent for moved file {} not found", fileEvent.getDstFile());
172 | }
173 | } else {
174 | LOG.warn("Original moved file {} not found. Already moved?", fileEvent.getSrcFile());
175 | }
176 | }
177 |
178 | @Override
179 | @Handler
180 | public void onFileShare(IFileShareEvent fileEvent) {
181 | LOG.debug("Got notified that file {} has been shared by {}.", fileEvent.getFile(), fileEvent.getInvitedBy());
182 | currentShareInvitations.put(fileEvent.getFile(), fileEvent.getUserPermissions());
183 | // can ignore because 'addFile' will be triggered as well
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/FileArrayAdapter.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ArrayAdapter;
9 | import android.widget.ImageView;
10 | import android.widget.ProgressBar;
11 | import android.widget.TextView;
12 |
13 | import org.hive2hive.mobile.H2HApplication;
14 | import org.hive2hive.mobile.R;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * @author Nico
20 | * inspired by http://custom-android-dn.blogspot.in/2013/01/create-simple-file-explore-in-android.html
21 | */
22 | public class FileArrayAdapter extends ArrayAdapter {
23 |
24 | private static final int LAYOUT_ID = R.layout.fragment_files;
25 |
26 | private final H2HApplication context;
27 | private final AndroidFileComparator comparator;
28 |
29 | public FileArrayAdapter(H2HApplication context, List items) {
30 | super(context, LAYOUT_ID, items);
31 | this.context = context;
32 | this.comparator = new AndroidFileComparator();
33 | }
34 |
35 | @Override
36 | public View getView(int position, View convertView, ViewGroup parent) {
37 | View view = convertView;
38 | if (view == null) {
39 | LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
40 | view = vi.inflate(LAYOUT_ID, null);
41 | }
42 |
43 | final AndroidFile node = getItem(position);
44 | if (node != null) {
45 | TextView nameText = (TextView) view.findViewById(R.id.file_list_name);
46 | nameText.setText(node.getFile().getName());
47 |
48 | TextView detailsText = (TextView) view.findViewById(R.id.file_list_details);
49 | detailsText.setText(getDetailsText(node));
50 | node.setDetailsView(detailsText);
51 |
52 | // TextView dateText = (TextView) v.findViewById(R.id.file_list_date);
53 | // dateText.setText(fileTaste.getDate());
54 |
55 | // register the image view at the file state holder in order to automatically get updates
56 | ImageView fileImage = (ImageView) view.findViewById(R.id.file_list_icon);
57 | node.setImageView(fileImage);
58 |
59 | Drawable icon = context.getResources().getDrawable(node.getState().getIconId(node.isFile()));
60 | fileImage.setImageDrawable(icon);
61 |
62 | // set the progress bar
63 | ProgressBar progress = (ProgressBar) view.findViewById(R.id.file_list_progress);
64 | node.setProgressBar(progress);
65 | }
66 |
67 | return view;
68 | }
69 |
70 | @Override
71 | public void add(AndroidFile file) {
72 | if(getPosition(file) > 0) {
73 | // don't add it because it is already in the list
74 | } else {
75 | super.add(file);
76 | }
77 | }
78 |
79 | private String getDetailsText(AndroidFile node) {
80 | if (node.isFolder()) {
81 | // show item count
82 | int items = node.getChildren().size();
83 | if (items == 0) {
84 | return context.getString(R.string.folder_empty);
85 | } else if (items == 1) {
86 | return context.getString(R.string.folder_single_item);
87 | } else {
88 | return context.getString(R.string.folder_items, items);
89 | }
90 | } else {
91 | return context.getString(node.getState().getMessageId());
92 | }
93 | }
94 |
95 | public void updateView(boolean sort) {
96 | if (sort) {
97 | super.sort(comparator);
98 | } else {
99 | notifyDataSetChanged();
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/FileState.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import org.hive2hive.mobile.R;
4 |
5 | /**
6 | * @author Nico
7 | */
8 | public enum FileState {
9 |
10 | /**
11 | * The file exists in the latest version on the disk The next state will be {@link org.hive2hive.mobile.files.FileState#OUTDATED} or {@link org.hive2hive.mobile.files.FileState#ON_AIR} if it's deleted locally
12 | */
13 | IN_SYNC(R.drawable.ic_blank_ex, R.drawable.ic_folder, R.string.file_state_in_sync),
14 |
15 | /**
16 | * The file is currently downloading. The next state will be {@link org.hive2hive.mobile.files.FileState#IN_SYNC}
17 | */
18 | DOWNLOADING(R.drawable.ic_download_inex, R.drawable.ic_folder_loading, R.string.file_state_downloading),
19 |
20 | /**
21 | * The file does only exist in the user profile ({@link org.hive2hive.core.processes.files.list.FileNode}, but not on the phone itself. The next state will be {@link org.hive2hive.mobile.files.FileState#DOWNLOADING}
22 | */
23 | ON_AIR(R.drawable.ic_cloud_inex, R.drawable.ic_folder, R.string.file_state_on_air),
24 |
25 | /**
26 | * The file exists in an older version on the phone. A new version could be downloaded. Thus, the next state is {@link org.hive2hive.mobile.files.FileState#DOWNLOADING}.
27 | */
28 | OUTDATED(R.drawable.ic_loading_inex, R.drawable.ic_folder_loading, R.string.file_state_outdated),
29 |
30 | /**
31 | * The file is currently uploading (new file or new version). Next state is {@link org.hive2hive.mobile.files.FileState#IN_SYNC}.
32 | */
33 | UPLOADING(R.drawable.ic_upload_ex, R.drawable.ic_folder_upload, R.string.file_state_uploading),
34 |
35 | /**
36 | * The user selected the file to be deleted. There's no next state because the file is completely removed from the network.
37 | */
38 | DELETING(R.drawable.ic_loading_inex, R.drawable.ic_folder_loading, R.string.file_state_deleting),
39 |
40 | /**
41 | * The user is currently sharing the folder with another user. The next state is again {@link org.hive2hive.mobile.files.FileState#SHARED}.
42 | */
43 | SHARING(R.drawable.ic_loading_inex, R.drawable.ic_folder_loading, R.string.file_state_sharing),
44 |
45 | /**
46 | * This folder is shared with another user
47 | */
48 | TOP_SHARED(R.drawable.ic_loading_inex, R.drawable.ic_folder_shared, R.string.file_state_shared),
49 |
50 | /**
51 | * The folder is currently shared with another user, but not the root share folder.
52 | */
53 | SHARED(R.drawable.ic_loading_inex, R.drawable.ic_folder, R.string.file_state_in_sync);
54 |
55 |
56 | private final int fileIconId;
57 | private final int folderIconId;
58 | private final int messageId;
59 |
60 | private FileState(int fileIconId, int folderIconId, int messageId) {
61 | this.fileIconId = fileIconId;
62 | this.folderIconId = folderIconId;
63 | this.messageId = messageId;
64 | }
65 |
66 | public int getIconId(boolean isFile) {
67 | if (isFile) {
68 | return fileIconId;
69 | } else {
70 | return folderIconId;
71 | }
72 | }
73 |
74 | public int getMessageId() {
75 | return messageId;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/FilesFragment.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.ListFragment;
5 | import android.content.ActivityNotFoundException;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.net.Uri;
10 | import android.os.Bundle;
11 | import android.view.ContextMenu;
12 | import android.view.ContextThemeWrapper;
13 | import android.view.LayoutInflater;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.webkit.MimeTypeMap;
18 | import android.widget.AdapterView;
19 | import android.widget.CheckBox;
20 | import android.widget.EditText;
21 | import android.widget.ListView;
22 | import android.widget.Toast;
23 |
24 | import org.apache.commons.io.FilenameUtils;
25 | import org.hive2hive.core.model.PermissionType;
26 | import org.hive2hive.core.model.UserPermission;
27 | import org.hive2hive.mobile.H2HApplication;
28 | import org.hive2hive.mobile.R;
29 | import org.hive2hive.mobile.common.UserPermissionComparator;
30 | import org.hive2hive.mobile.files.tasks.FileDeleteTask;
31 | import org.hive2hive.mobile.files.tasks.FileDownloadTask;
32 | import org.hive2hive.mobile.files.tasks.FileShareTask;
33 | import org.hive2hive.mobile.files.tasks.FileUpdateTask;
34 | import org.slf4j.Logger;
35 | import org.slf4j.LoggerFactory;
36 |
37 | import java.io.File;
38 | import java.util.ArrayList;
39 | import java.util.Collections;
40 | import java.util.List;
41 |
42 |
43 | public class FilesFragment extends ListFragment {
44 |
45 | private static final Logger LOG = LoggerFactory.getLogger(FilesFragment.class);
46 |
47 | private H2HApplication context;
48 | private FileArrayAdapter fileAdapter;
49 |
50 | @Override
51 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
52 | // create ContextThemeWrapper from the original Activity Context with the custom theme
53 | final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_DARK);
54 | // clone the inflater using the ContextThemeWrapper
55 | LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
56 |
57 | // Inflate the layout for this fragment
58 | View view = super.onCreateView(localInflater, container, savedInstanceState);
59 | localInflater.inflate(R.layout.fragment_files, container, false);
60 | return view;
61 | }
62 |
63 | @Override
64 | public void onActivityCreated(Bundle savedInstanceState) {
65 | super.onActivityCreated(savedInstanceState);
66 | registerForContextMenu(getListView());
67 | }
68 |
69 | public String getPath() {
70 | return getArguments().getString("path");
71 | }
72 |
73 | public FileArrayAdapter getFileAdapter() {
74 | return fileAdapter;
75 | }
76 |
77 | private FilesActivity getFilesActivity() {
78 | return (FilesActivity) getActivity();
79 | }
80 |
81 | public void fillFileList(AndroidFile folder, H2HApplication context) {
82 | this.context = context;
83 | if (folder == null) {
84 | return;
85 | }
86 |
87 | // Put the data into the list
88 | List children = new ArrayList<>(folder.getChildren());
89 | fileAdapter = new FileArrayAdapter(context, children);
90 | setListAdapter(fileAdapter);
91 | }
92 |
93 | private void openFile(final File file) {
94 | Intent intent = new Intent();
95 | intent.setAction(android.content.Intent.ACTION_VIEW);
96 |
97 | MimeTypeMap mime = MimeTypeMap.getSingleton();
98 | String ext = FilenameUtils.getExtension(file.getName());
99 | String type = mime.getMimeTypeFromExtension(ext);
100 | intent.setDataAndType(Uri.fromFile(file), type);
101 |
102 | try {
103 | startActivity(intent);
104 | } catch (ActivityNotFoundException ex) {
105 | // happens when the file has an unknown suffix / type
106 | Toast.makeText(getActivity(), R.string.files_error_open, Toast.LENGTH_LONG).show();
107 | }
108 |
109 | getFilesActivity().resetLogoutHint();
110 | }
111 |
112 | @Override
113 | public void onListItemClick(ListView l, View v, int position, long id) {
114 | AndroidFile node = (AndroidFile) getListAdapter().getItem(position);
115 | if (node.isFolder() && (node.getState() == FileState.IN_SYNC || node.getState() == FileState.SHARED || node.getState() == FileState.TOP_SHARED)) {
116 | getFilesActivity().showFolder(node);
117 | } else {
118 | FileState state = node.getState();
119 | switch (state) {
120 | case IN_SYNC: // fall-through
121 | case SHARING:
122 | openFile(node.getFile());
123 | break;
124 | case DOWNLOADING:
125 | // TODO show dialog to cancel download
126 | break;
127 | case ON_AIR: // fall-through
128 | case OUTDATED:
129 | new FileDownloadTask(context.h2hNode().getFileManager(), fileAdapter, node).execute();
130 | break;
131 | }
132 | LOG.debug("Selected file '{}' for action...", node.getFile());
133 | }
134 | }
135 |
136 | @Override
137 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
138 | super.onCreateContextMenu(menu, v, menuInfo);
139 | AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
140 | AndroidFile item = fileAdapter.getItem(info.position);
141 |
142 | switch (item.getState()) {
143 | case ON_AIR:
144 | case OUTDATED:
145 | menu.add(0, R.string.context_files_download, 0, R.string.context_files_download);
146 | if (item.canWrite(context.currentUser())) {
147 | menu.add(0, R.string.context_files_update, 0, R.string.context_files_update);
148 | }
149 | case SHARED:
150 | menu.add(0, R.string.context_files_open, 0, R.string.context_files_open);
151 | if (item.isFile()) {
152 | menu.add(0, R.string.context_files_delete_locally, 0, R.string.context_files_delete_locally);
153 | } else {
154 | menu.add(0, R.string.context_folder_share_info, 0, R.string.context_folder_share_info);
155 | }
156 | if (item.canWrite(context.currentUser())) {
157 | menu.add(0, R.string.context_delete_globally, 0, R.string.context_delete_globally);
158 | }
159 | break;
160 | case TOP_SHARED:
161 | menu.add(0, R.string.context_files_open, 0, R.string.context_files_open);
162 | menu.add(0, R.string.context_folder_share, 0, R.string.context_folder_share);
163 | menu.add(0, R.string.context_folder_share_info, 0, R.string.context_folder_share_info);
164 | menu.add(0, R.string.context_delete_globally, 0, R.string.context_delete_globally);
165 | break;
166 | case IN_SYNC:
167 | menu.add(0, R.string.context_files_open, 0, R.string.context_files_open);
168 | if (item.isFile()) {
169 | menu.add(0, R.string.context_files_delete_locally, 0, R.string.context_files_delete_locally);
170 | } else {
171 | menu.add(0, R.string.context_folder_share, 0, R.string.context_folder_share);
172 | }
173 | if (item.canWrite(context.currentUser())) {
174 | menu.add(0, R.string.context_delete_globally, 0, R.string.context_delete_globally);
175 | }
176 | break;
177 | case SHARING:
178 | case UPLOADING:
179 | case DOWNLOADING:
180 | default:
181 | if (item.canWrite(context.currentUser())) {
182 | menu.add(0, R.string.context_delete_globally, 0, R.string.context_delete_globally);
183 | }
184 | }
185 | }
186 |
187 | @Override
188 | public boolean onContextItemSelected(MenuItem item) {
189 | getFilesActivity().resetLogoutHint();
190 |
191 | AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
192 | AndroidFile node = fileAdapter.getItem(info.position);
193 |
194 | switch (item.getItemId()) {
195 | case R.string.context_files_download:
196 | new FileDownloadTask(context.h2hNode().getFileManager(), fileAdapter, node).execute();
197 | break;
198 | case R.string.context_files_update:
199 | new FileUpdateTask(context.h2hNode().getFileManager(), fileAdapter, node).execute();
200 | break;
201 | case R.string.context_files_delete_locally:
202 | if (node.getFile().delete()) {
203 | node.setState(FileState.ON_AIR, fileAdapter);
204 | } else {
205 | Toast.makeText(getActivity(), R.string.files_error_delete_failed, Toast.LENGTH_SHORT).show();
206 | }
207 | break;
208 | case R.string.context_delete_globally:
209 | if (node.isFolder() && !node.getChildren().isEmpty()) {
210 | // show warning that non-empty folders cannot be deleted
211 | Toast.makeText(getActivity(), R.string.files_error_delete_nonempty, Toast.LENGTH_SHORT).show();
212 | } else {
213 | new FileDeleteTask(context.h2hNode().getFileManager(), fileAdapter, node).execute();
214 | }
215 | break;
216 | case R.string.context_files_open:
217 | if (node.isFile()) {
218 | openFile(node.getFile());
219 | } else {
220 | getFilesActivity().showFolder(node);
221 | }
222 | break;
223 | case R.string.context_folder_share:
224 | shareFolder(node);
225 | break;
226 | case R.string.context_folder_share_info:
227 | showShareInfo(node);
228 | break;
229 | default:
230 | super.onContextItemSelected(item);
231 | }
232 |
233 | return true;
234 | }
235 |
236 | public void shareFolder(final AndroidFile file) {
237 | ContextThemeWrapper wrapper = new ContextThemeWrapper(getActivity(), R.style.AppTheme);
238 | LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
239 | final View view = vi.inflate(R.layout.dialog_share, null);
240 |
241 | new AlertDialog.Builder(wrapper, AlertDialog.THEME_DEVICE_DEFAULT_DARK)
242 | .setTitle(R.string.share_folder_title)
243 | .setMessage(R.string.share_folder_message)
244 | .setView(view)
245 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
246 | public void onClick(DialogInterface dialog, int whichButton) {
247 | EditText usernameField = (EditText) view.findViewById(R.id.share_username);
248 | CheckBox writeCheckbox = (CheckBox) view.findViewById(R.id.share_write_permissions);
249 |
250 | PermissionType perm = writeCheckbox.isChecked() ? PermissionType.WRITE : PermissionType.READ;
251 | new FileShareTask(context.h2hNode().getFileManager(), fileAdapter, file, usernameField.getText().toString(), perm).execute();
252 | }
253 | }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
254 | public void onClick(DialogInterface dialog, int whichButton) {
255 | // Do nothing.
256 | }
257 | }).show();
258 | }
259 |
260 | private void showShareInfo(AndroidFile node) {
261 | // Concatenate user list
262 | List permissions = new ArrayList<>(node.getPermissions());
263 | Collections.sort(permissions, new UserPermissionComparator());
264 | StringBuilder sb = new StringBuilder(getString(R.string.share_info_message, node.getFile().getName())).append("\n");
265 | for (UserPermission permission : permissions) {
266 | sb.append("\u2022 ").append(permission.getUserId());
267 | if (permission.getPermission() == PermissionType.READ) {
268 | sb.append(" ").append(getString(R.string.share_info_readonly));
269 | }
270 | sb.append("\n");
271 | }
272 |
273 | new AlertDialog.Builder(getActivity())
274 | .setTitle(R.string.share_info_title)
275 | .setMessage(sb.toString()).setNeutralButton(android.R.string.ok, null).show();
276 | }
277 |
278 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/BaseFileTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.os.AsyncTask;
4 | import android.view.View;
5 |
6 | import org.hive2hive.core.api.interfaces.IFileManager;
7 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
8 | import org.hive2hive.core.exceptions.NoSessionException;
9 | import org.hive2hive.mobile.files.AndroidFile;
10 | import org.hive2hive.mobile.files.FileArrayAdapter;
11 | import org.hive2hive.processframework.interfaces.IProcessComponent;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | /**
16 | * @author Nico
17 | */
18 | public abstract class BaseFileTask extends AsyncTask {
19 |
20 | private static final Logger LOG = LoggerFactory.getLogger(BaseFileTask.class);
21 |
22 | protected final FileArrayAdapter adapter;
23 | protected final AndroidFile file;
24 | private final IFileManager fileManager;
25 |
26 | public BaseFileTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file) {
27 | this.adapter = adapter;
28 | this.file = file;
29 | this.fileManager = fileManager;
30 | }
31 |
32 | @Override
33 | protected final void onPreExecute() {
34 | beforeExecution();
35 | if (file.getProgressBar() != null) {
36 | file.getProgressBar().setVisibility(View.VISIBLE);
37 | adapter.updateView(false);
38 | }
39 | }
40 |
41 | protected abstract void beforeExecution();
42 |
43 | @Override
44 | protected final Boolean doInBackground(Void... voids) {
45 | try {
46 | getProcess(fileManager).execute();
47 | return true;
48 | } catch (Exception e) {
49 | LOG.error("Cannot run the file process", e);
50 | return false;
51 | }
52 | }
53 |
54 | protected abstract IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException;
55 |
56 | @Override
57 | protected final void onPostExecute(Boolean success) {
58 | super.onPostExecute(success);
59 | if (file.getProgressBar() != null) {
60 | file.getProgressBar().setVisibility(View.INVISIBLE);
61 | adapter.updateView(false);
62 | }
63 |
64 | afterExecution(success);
65 | }
66 |
67 | protected abstract void afterExecution(boolean success);
68 | }
69 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileDeleteTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.widget.Toast;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.mobile.R;
9 | import org.hive2hive.mobile.files.AndroidFile;
10 | import org.hive2hive.mobile.files.FileArrayAdapter;
11 | import org.hive2hive.mobile.files.FileState;
12 | import org.hive2hive.processframework.interfaces.IProcessComponent;
13 |
14 | /**
15 | * @author Nico
16 | */
17 | public class FileDeleteTask extends BaseFileTask {
18 |
19 | private FileState stateBefore;
20 |
21 | public FileDeleteTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file) {
22 | super(fileManager, adapter, file);
23 | }
24 |
25 | @Override
26 | protected void beforeExecution() {
27 | stateBefore = file.getState();
28 | file.setState(FileState.DELETING, adapter);
29 | }
30 |
31 | @Override
32 | protected IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException {
33 | return fileManager.createDeleteProcess(file.getFile());
34 | }
35 |
36 | @Override
37 | protected void afterExecution(boolean success) {
38 | if (success) {
39 | file.getFile().delete();
40 | adapter.remove(file);
41 | file.getParent().getChildren().remove(file);
42 | } else {
43 | file.setState(stateBefore, adapter);
44 | Toast.makeText(adapter.getContext(), adapter.getContext().getString(R.string.files_error_delete_failed), Toast.LENGTH_LONG).show();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileDownloadTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.widget.Toast;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.mobile.R;
9 | import org.hive2hive.mobile.files.AndroidFile;
10 | import org.hive2hive.mobile.files.FileArrayAdapter;
11 | import org.hive2hive.mobile.files.FileState;
12 | import org.hive2hive.processframework.interfaces.IProcessComponent;
13 |
14 | /**
15 | * @author Nico
16 | */
17 | public class FileDownloadTask extends BaseFileTask {
18 |
19 | public FileDownloadTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file) {
20 | super(fileManager, adapter, file);
21 | }
22 |
23 | @Override
24 | protected void beforeExecution() {
25 | file.setState(FileState.DOWNLOADING, adapter);
26 | }
27 |
28 | @Override
29 | protected IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException {
30 | return fileManager.createDownloadProcess(file.getFile());
31 | }
32 |
33 | @Override
34 | protected void afterExecution(boolean success) {
35 | if (success) {
36 | file.setState(FileState.IN_SYNC, adapter);
37 | } else {
38 | file.setState(FileState.ON_AIR, adapter);
39 | Toast.makeText(adapter.getContext(), adapter.getContext().getString(R.string.files_error_download, file.getPath()), Toast.LENGTH_LONG).show();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileListTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.app.ProgressDialog;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.core.processes.files.list.FileNode;
9 | import org.hive2hive.mobile.H2HApplication;
10 | import org.hive2hive.mobile.R;
11 | import org.hive2hive.mobile.common.BaseProgressTask;
12 | import org.hive2hive.mobile.common.ISuccessFailListener;
13 | import org.hive2hive.mobile.files.AndroidFile;
14 | import org.hive2hive.processframework.exceptions.InvalidProcessStateException;
15 | import org.hive2hive.processframework.exceptions.ProcessExecutionException;
16 | import org.hive2hive.processframework.interfaces.IProcessComponent;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | /**
21 | * @author Nico
22 | */
23 | public class FileListTask extends BaseProgressTask {
24 |
25 | private static final Logger LOG = LoggerFactory.getLogger(FileListTask.class);
26 |
27 | public FileListTask(H2HApplication context, ISuccessFailListener listener, ProgressDialog progressDialog) {
28 | super(context, listener, progressDialog);
29 | }
30 |
31 | @Override
32 | protected String[] getProgressMessages() {
33 | return new String[]{context.getString(R.string.progress_files_title)};
34 | }
35 |
36 | @Override
37 | protected Boolean doInBackground(Void... voids) {
38 | if (context.h2hNode() != null && context.h2hNode().isConnected()) {
39 | IFileManager fileManager = context.h2hNode().getFileManager();
40 | try {
41 | IProcessComponent process = fileManager.createFileListProcess();
42 | FileNode root = process.execute();
43 | AndroidFile androidRoot = new AndroidFile(root, null);
44 | context.currentTree(androidRoot);
45 | LOG.debug("Successfully obtained the file list");
46 | } catch (NoPeerConnectionException | NoSessionException | InvalidProcessStateException | ProcessExecutionException e) {
47 | LOG.error("Cannot obtain the latest file list");
48 | return false;
49 | }
50 |
51 | return true;
52 | }
53 |
54 | return false;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileShareTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.widget.Toast;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.core.model.PermissionType;
9 | import org.hive2hive.core.model.UserPermission;
10 | import org.hive2hive.mobile.R;
11 | import org.hive2hive.mobile.files.AndroidFile;
12 | import org.hive2hive.mobile.files.FileArrayAdapter;
13 | import org.hive2hive.mobile.files.FileState;
14 | import org.hive2hive.processframework.interfaces.IProcessComponent;
15 |
16 | /**
17 | * @author Nico
18 | */
19 | public class FileShareTask extends BaseFileTask {
20 |
21 | private final String username;
22 | private final PermissionType permission;
23 | private final FileState stateBefore;
24 |
25 | public FileShareTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file, String username, PermissionType permission) {
26 | super(fileManager, adapter, file);
27 | this.username = username;
28 | this.permission = permission;
29 | this.stateBefore = file.getState();
30 | }
31 |
32 | @Override
33 | protected void beforeExecution() {
34 | file.setState(FileState.SHARING, adapter);
35 | }
36 |
37 | @Override
38 | protected IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException {
39 | return fileManager.createShareProcess(file.getFile(), username, permission);
40 | }
41 |
42 | @Override
43 | protected void afterExecution(boolean success) {
44 | if (success) {
45 | file.setState(FileState.TOP_SHARED, adapter);
46 | file.getPermissions().add(new UserPermission(username, permission));
47 | } else {
48 | file.setState(stateBefore, adapter);
49 | Toast.makeText(adapter.getContext(), adapter.getContext().getString(R.string.files_error_share, username), Toast.LENGTH_LONG).show();
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileUpdateTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.widget.Toast;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.mobile.R;
9 | import org.hive2hive.mobile.files.AndroidFile;
10 | import org.hive2hive.mobile.files.FileArrayAdapter;
11 | import org.hive2hive.mobile.files.FileState;
12 | import org.hive2hive.processframework.interfaces.IProcessComponent;
13 |
14 | /**
15 | * @author Nico
16 | */
17 | public class FileUpdateTask extends BaseFileTask {
18 |
19 | public FileUpdateTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file) {
20 | super(fileManager, adapter, file);
21 | }
22 |
23 | @Override
24 | protected void beforeExecution() {
25 | file.setState(FileState.UPLOADING, adapter);
26 | }
27 |
28 | @Override
29 | protected IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException {
30 | return fileManager.createUpdateProcess(file.getFile());
31 | }
32 |
33 | @Override
34 | protected void afterExecution(boolean success) {
35 | if (success) {
36 | file.setState(FileState.IN_SYNC, adapter);
37 | } else {
38 | file.setState(FileState.OUTDATED, adapter);
39 | Toast.makeText(adapter.getContext(), adapter.getContext().getString(R.string.files_error_upload, file.getPath()), Toast.LENGTH_LONG).show();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/files/tasks/FileUploadTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.files.tasks;
2 |
3 | import android.widget.Toast;
4 |
5 | import org.hive2hive.core.api.interfaces.IFileManager;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.mobile.R;
9 | import org.hive2hive.mobile.files.AndroidFile;
10 | import org.hive2hive.mobile.files.FileArrayAdapter;
11 | import org.hive2hive.mobile.files.FileState;
12 | import org.hive2hive.processframework.interfaces.IProcessComponent;
13 |
14 | /**
15 | * @author Nico
16 | */
17 | public class FileUploadTask extends BaseFileTask {
18 |
19 | public FileUploadTask(IFileManager fileManager, FileArrayAdapter adapter, AndroidFile file) {
20 | super(fileManager, adapter, file);
21 | }
22 |
23 | @Override
24 | protected void beforeExecution() {
25 | // add the file to the list
26 | file.setState(FileState.UPLOADING, adapter);
27 |
28 | file.getParent().getChildren().add(file);
29 | adapter.add(file);
30 | adapter.updateView(true);
31 | }
32 |
33 | @Override
34 | protected IProcessComponent getProcess(IFileManager fileManager) throws NoSessionException, NoPeerConnectionException {
35 | return fileManager.createAddProcess(file.getFile());
36 | }
37 |
38 | @Override
39 | protected void afterExecution(boolean success) {
40 | if (success) {
41 | file.setState(FileState.IN_SYNC, adapter);
42 | } else {
43 | file.getParent().getChildren().remove(file);
44 | adapter.remove(file);
45 | adapter.updateView(false);
46 | Toast.makeText(adapter.getContext(), adapter.getContext().getString(R.string.files_error_upload, file.getPath()), Toast.LENGTH_LONG).show();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/gcm/GCMBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.gcm;
2 |
3 | import android.app.Activity;
4 | import android.content.ComponentName;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.support.v4.content.WakefulBroadcastReceiver;
8 |
9 | /**
10 | * Created by Nico Rutishauser on 08.09.14.
11 | * Handles incoming messages and passes them to the intent service. This class ensures that the application stays awake while the message is processed.
12 | */
13 | public class GCMBroadcastReceiver extends WakefulBroadcastReceiver {
14 |
15 | @Override
16 | public void onReceive(Context context, Intent intent) {
17 | // Explicitly specify that GcmIntentService will handle the intent.
18 | ComponentName comp = new ComponentName(context.getPackageName(),
19 | GCMIntentService.class.getName());
20 |
21 | // Start the service, keeping the device awake while it is launching.
22 | startWakefulService(context, (intent.setComponent(comp)));
23 | setResultCode(Activity.RESULT_OK);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/gcm/GCMIntentService.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.gcm;
2 |
3 | import android.app.IntentService;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import com.google.android.gms.gcm.GoogleCloudMessaging;
8 |
9 | import net.tomp2p.relay.buffer.BufferRequestListener;
10 |
11 | import org.hive2hive.mobile.H2HApplication;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | /**
16 | * Created by Nico Rutishauser on 08.09.14.
17 | * Handles incoming GCM messages
18 | */
19 | public class GCMIntentService extends IntentService {
20 |
21 | private static final Logger LOG = LoggerFactory.getLogger(GCMIntentService.class);
22 |
23 | public GCMIntentService() {
24 | super("GCMIntentService");
25 | }
26 |
27 | @Override
28 | protected void onHandleIntent(Intent intent) {
29 | GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
30 | // the message type is in the intent
31 | String messageType = gcm.getMessageType(intent);
32 |
33 | Bundle extras = intent.getExtras();
34 | if (extras.isEmpty()) {
35 | LOG.warn("Received empty GCM message of type {}", messageType);
36 | return;
37 | }
38 |
39 | LOG.debug("Received message of type {} with extras {}", messageType, extras.toString());
40 |
41 | H2HApplication application = (H2HApplication) getApplicationContext();
42 | BufferRequestListener handler = application.bufferListener();
43 | if (handler == null) {
44 | LOG.warn("Ignoring message because peer is not connected yet / anymore");
45 | } else {
46 | LOG.debug("Passing GCM message to handler");
47 | handler.sendBufferRequest(extras.getString("collapse_key"));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/gcm/GCMRegistrationUtil.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.gcm;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 |
8 | import com.google.android.gms.gcm.GoogleCloudMessaging;
9 |
10 | import org.hive2hive.mobile.connection.ConnectActivity;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.io.IOException;
15 |
16 | /**
17 | * Created by Nico Rutishauser on 08.09.14.
18 | *
19 | * If the application is running for the first time on this device, a new registration ID will be created by GCM.
20 | * Else, the existing ID will be used. Then, this id is forwarded to all relay peers.
21 | */
22 | public class GCMRegistrationUtil {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(GCMRegistrationUtil.class);
25 | private static final String PROPERTY_REG_ID = "registration_id";
26 | private static final String PROPERTY_APP_VERSION = "app_version";
27 | private static final String PROPERTY_GCM_SENDER = "gcm_sender";
28 |
29 | private GCMRegistrationUtil() {
30 | // only static method
31 | }
32 |
33 | /**
34 | * Obtain the registration ID from the application store or create a new one.
35 | */
36 | public static String getRegistrationId(Context context, long gcmSenderId) {
37 | int currentAppVersion = getAppVersion(context);
38 | String registrationID = getStoredRegistrationId(context, currentAppVersion, gcmSenderId);
39 | if (registrationID == null || registrationID.isEmpty()) {
40 | registrationID = obtainRegistrationId(context, gcmSenderId);
41 | LOG.debug("Successfully obtained a new registration ID {} for version {} and sender id {}", registrationID, currentAppVersion, gcmSenderId);
42 | storeRegistrationId(context, registrationID, currentAppVersion, gcmSenderId);
43 | } else {
44 | LOG.debug("Reusing existing registration ID: {}", registrationID);
45 | }
46 |
47 | return registrationID;
48 | }
49 |
50 | /**
51 | * @return Application's version code from the {@code PackageManager}.
52 | */
53 | private static int getAppVersion(Context context) {
54 | try {
55 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
56 | return packageInfo.versionCode;
57 | } catch (PackageManager.NameNotFoundException e) {
58 | // should never happen
59 | throw new RuntimeException("Could not get package name: " + e);
60 | }
61 | }
62 |
63 | private static String getStoredRegistrationId(Context context, int currentAppVersion, long gcmSenderId) {
64 | SharedPreferences prefs = context.getSharedPreferences(ConnectActivity.class.getSimpleName(), Context.MODE_PRIVATE);
65 | String registrationId = prefs.getString(PROPERTY_REG_ID, null);
66 | if (registrationId == null) {
67 | LOG.info("No registration id stored. Obtain new one");
68 | return null;
69 | }
70 |
71 | // Check if the app version and the gcm sender id of the registered prefs match
72 | int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
73 | if (registeredVersion != currentAppVersion) {
74 | LOG.info("App version changed from {} to {}! Obtain new registration id.", registeredVersion, currentAppVersion);
75 | return null;
76 | }
77 |
78 | long registeredGcmSenderId = prefs.getLong(PROPERTY_GCM_SENDER, Long.MIN_VALUE);
79 | if (registeredGcmSenderId != gcmSenderId) {
80 | LOG.info("GCM sender id {} does not match with stored one ({}). Obtain new registration id.", gcmSenderId, registeredGcmSenderId);
81 | return null;
82 | }
83 |
84 | return registrationId;
85 | }
86 |
87 | private static void storeRegistrationId(Context context, String registrationId, int currentAppVersion, long gcmSenderId) {
88 | SharedPreferences prefs = context.getSharedPreferences(ConnectActivity.class.getSimpleName(), Context.MODE_PRIVATE);
89 | prefs.edit().putString(PROPERTY_REG_ID, registrationId).putInt(PROPERTY_APP_VERSION, currentAppVersion).putLong(PROPERTY_GCM_SENDER, gcmSenderId).commit();
90 | }
91 |
92 | private static String obtainRegistrationId(Context context, long gcmSenderId) {
93 | GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
94 |
95 | try {
96 | return gcm.register(String.valueOf(gcmSenderId));
97 | } catch (IOException e) {
98 | LOG.error("Cannot obtain a registration ID for sender id {}", gcmSenderId, e);
99 | return null;
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/login/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.login;
2 |
3 | import android.app.Activity;
4 | import android.app.ProgressDialog;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.preference.PreferenceManager;
10 | import android.text.TextUtils;
11 | import android.view.Menu;
12 | import android.view.MenuItem;
13 | import android.view.View;
14 | import android.view.Window;
15 | import android.widget.CheckBox;
16 | import android.widget.EditText;
17 | import android.widget.TextView;
18 |
19 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
20 | import org.hive2hive.mobile.H2HApplication;
21 | import org.hive2hive.mobile.R;
22 | import org.hive2hive.mobile.common.ISuccessFailListener;
23 | import org.hive2hive.mobile.connection.ConnectActivity;
24 | import org.hive2hive.mobile.files.FilesActivity;
25 | import org.hive2hive.mobile.preference.SettingsActivity;
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 |
29 |
30 | /**
31 | * A login screen that offers login via username/password.
32 | *
33 | * @author Nico
34 | */
35 | public class LoginActivity extends Activity {
36 |
37 | private static final Logger LOG = LoggerFactory.getLogger(LoginActivity.class);
38 | private static final String STORE_CREDENTIALS = "store";
39 | private static final String STORED_USER_ID = "userid";
40 | private static final String STORED_PASSWORD = "pin";
41 | private static final String STORED_PIN = "password";
42 |
43 | private H2HApplication context;
44 |
45 | // UI references.
46 | private EditText usernameView;
47 | private EditText passwordView;
48 | private EditText pinView;
49 | private CheckBox storeCredentials;
50 |
51 | @Override
52 | protected void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | requestWindowFeature(Window.FEATURE_ACTION_BAR);
55 | setContentView(R.layout.activity_login);
56 |
57 | context = (H2HApplication) getApplicationContext();
58 | if (context.h2hNode() == null || !context.h2hNode().isConnected()) {
59 | // head back to the connection page
60 | Intent intent = new Intent(context, ConnectActivity.class);
61 | startActivity(intent);
62 | return;
63 | }
64 |
65 | // Set up the login form.
66 | usernameView = (EditText) findViewById(R.id.username);
67 | passwordView = (EditText) findViewById(R.id.password);
68 | pinView = (EditText) findViewById(R.id.pin);
69 | storeCredentials = (CheckBox) findViewById(R.id.store_credentials);
70 |
71 | // set stored credentials
72 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
73 | usernameView.setText(prefs.getString(STORED_USER_ID, ""), TextView.BufferType.EDITABLE);
74 | passwordView.setText(prefs.getString(STORED_PASSWORD, ""), TextView.BufferType.EDITABLE);
75 | pinView.setText(prefs.getString(STORED_PIN, ""), TextView.BufferType.EDITABLE);
76 | storeCredentials.setChecked(prefs.getBoolean(STORE_CREDENTIALS, false));
77 | }
78 |
79 | /**
80 | * Attempts to sign in or register the account specified by the login form.
81 | * If there are form errors (invalid username, missing fields, etc.), the
82 | * errors are presented and no actual login attempt is made.
83 | */
84 | public void login(View view) {
85 | if (context.h2hNode() == null) {
86 | return;
87 | }
88 |
89 | try {
90 | if (context.h2hNode().getUserManager().isLoggedIn()) {
91 | // already logged in
92 | startFileView();
93 | return;
94 | }
95 | } catch (NoPeerConnectionException e) {
96 | LOG.warn("Cannot determine the login state", e);
97 | }
98 |
99 | // Reset errors.
100 | usernameView.setError(null);
101 | passwordView.setError(null);
102 |
103 | // Store values at the time of the login attempt.
104 | String username = usernameView.getText().toString();
105 | String password = passwordView.getText().toString();
106 | String pin = pinView.getText().toString();
107 |
108 | boolean cancel = false;
109 | View focusView = null;
110 |
111 |
112 | // Check for a valid password, if the user entered one.
113 | if (TextUtils.isEmpty(password)) {
114 | passwordView.setError(getString(R.string.error_field_required));
115 | focusView = passwordView;
116 | cancel = true;
117 | }
118 |
119 | // Check for a valid pin, if the user entered one.
120 | if (TextUtils.isEmpty(pin)) {
121 | pinView.setError(getString(R.string.error_field_required));
122 | focusView = pinView;
123 | cancel = true;
124 | }
125 |
126 | // Check for a valid username address.
127 | if (TextUtils.isEmpty(username)) {
128 | usernameView.setError(getString(R.string.error_field_required));
129 | focusView = usernameView;
130 | cancel = true;
131 | }
132 |
133 | if (cancel) {
134 | // There was an error; don't attempt login and focus the first
135 | // form field with an error.
136 | focusView.requestFocus();
137 | } else {
138 | // create the progress dialog
139 | ProgressDialog dialog = new ProgressDialog(this);
140 | dialog.setTitle(getString(R.string.progress_login_title));
141 | dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
142 | dialog.setCancelable(false);
143 | dialog.setCanceledOnTouchOutside(false);
144 |
145 | // Show a progress spinner, and kick off a background task to
146 | // perform the user login attempt.
147 | UserLoginTask loginTask = new UserLoginTask(context, username, password, pin, new LoginListener(username, password, pin), dialog);
148 | loginTask.execute((Void) null);
149 | }
150 | }
151 |
152 | private void startFileView() {
153 | Intent intent = new Intent(getApplicationContext(), FilesActivity.class);
154 | intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
155 | startActivity(intent);
156 | }
157 |
158 | private void storeCredentials(String username, String password, String pin) {
159 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
160 | if (storeCredentials.isChecked()) {
161 | // store the credentials
162 | prefs.edit().putBoolean(STORE_CREDENTIALS, true).putString(STORED_USER_ID, username).putString(STORED_PASSWORD, password).putString(STORED_PIN, pin).commit();
163 | } else {
164 | // erase existing credentials
165 | prefs.edit().putBoolean(STORE_CREDENTIALS, false).remove(STORED_USER_ID).remove(STORED_PASSWORD).remove(STORED_PIN).commit();
166 | }
167 | }
168 |
169 | @Override
170 | public boolean onCreateOptionsMenu(Menu menu) {
171 | getMenuInflater().inflate(R.menu.menu_settings, menu);
172 | return true;
173 | }
174 |
175 | @Override
176 | public boolean onOptionsItemSelected(MenuItem item) {
177 | // Handle action bar item clicks here. The action bar will
178 | // automatically handle clicks on the Home/Up button, so long
179 | // as you specify a parent activity in AndroidManifest.xml.
180 | int id = item.getItemId();
181 | if (id == R.id.action_settings) {
182 | Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);
183 | startActivity(intent);
184 | return true;
185 | } else if (id == R.id.action_help) {
186 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help_login_url)));
187 | startActivity(browserIntent);
188 | return true;
189 | }
190 |
191 | return super.onOptionsItemSelected(item);
192 | }
193 |
194 | private class LoginListener implements ISuccessFailListener {
195 |
196 | private final String username;
197 | private final String password;
198 | private final String pin;
199 |
200 | public LoginListener(String username, String password, String pin) {
201 | this.username = username;
202 | this.password = password;
203 | this.pin = pin;
204 | }
205 |
206 | @Override
207 | public void onSuccess() {
208 | storeCredentials(username, password, pin);
209 | startFileView();
210 | }
211 |
212 | @Override
213 | public void onFail() {
214 | passwordView.setError(getString(R.string.error_incorrect_credentials));
215 | passwordView.requestFocus();
216 | }
217 | }
218 | }
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/login/UserLoginTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.login;
2 |
3 | import android.app.ProgressDialog;
4 |
5 | import org.hive2hive.core.api.interfaces.IH2HNode;
6 | import org.hive2hive.core.api.interfaces.IUserManager;
7 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
8 | import org.hive2hive.core.security.UserCredentials;
9 | import org.hive2hive.mobile.H2HApplication;
10 | import org.hive2hive.mobile.R;
11 | import org.hive2hive.mobile.common.AndroidFileAgent;
12 | import org.hive2hive.mobile.common.BaseProgressTask;
13 | import org.hive2hive.mobile.common.ISuccessFailListener;
14 | import org.hive2hive.processframework.exceptions.InvalidProcessStateException;
15 | import org.hive2hive.processframework.exceptions.ProcessExecutionException;
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | /**
20 | * Represents an asynchronous login/registration task used to authenticate
21 | * the user.
22 | */
23 | public class UserLoginTask extends BaseProgressTask {
24 | private static final Logger LOG = LoggerFactory.getLogger(UserLoginTask.class);
25 |
26 | private final String username;
27 | private final String password;
28 | private final String pin;
29 |
30 | public UserLoginTask(H2HApplication context, String username, String password, String pin, ISuccessFailListener listener, ProgressDialog progressDialog) {
31 | super(context, listener, progressDialog);
32 | this.username = username;
33 | this.password = password;
34 | this.pin = pin;
35 | }
36 |
37 | @Override
38 | protected String[] getProgressMessages() {
39 | String[] progressMessages = new String[4];
40 | progressMessages[0] = context.getString(R.string.progress_login_encrypt);
41 | progressMessages[1] = context.getString(R.string.progress_login_register_check);
42 | progressMessages[2] = context.getString(R.string.progress_login_register);
43 | progressMessages[3] = context.getString(R.string.progress_login_login);
44 | return progressMessages;
45 | }
46 |
47 | @Override
48 | protected Boolean doInBackground(Void... params) {
49 | IH2HNode node = context.h2hNode();
50 | if (node == null || !node.isConnected()) {
51 | LOG.error("H2HNode is null or not connected (anymore)");
52 | // TODO head back to the connection activity
53 | return false;
54 | }
55 |
56 | IUserManager userManager = node.getUserManager();
57 |
58 | // create credentials here (takes some time)
59 | publishProgress(0);
60 | UserCredentials credentials = new UserCredentials(username, password, pin);
61 |
62 | try {
63 | LOG.debug("Check if user {} is already registered.", username);
64 | publishProgress(1);
65 | if (!userManager.isRegistered(username)) {
66 | LOG.debug("Start registering user {}.", username);
67 | publishProgress(2);
68 | userManager.createRegisterProcess(credentials).execute();
69 | LOG.debug("User {} successfully registered.", username);
70 | }
71 | } catch (NoPeerConnectionException | ProcessExecutionException | InvalidProcessStateException e) {
72 | LOG.error("Cannot check if user registered or cannot register user {}", username, e);
73 | return false;
74 | }
75 |
76 | try {
77 | LOG.debug("Start logging in user {}", username);
78 | publishProgress(3);
79 | AndroidFileAgent fileAgent = new AndroidFileAgent(context, username);
80 | userManager.createLoginProcess(credentials, fileAgent).execute();
81 | LOG.info("User {} successfully logged in", username);
82 | context.currentUser(username);
83 | return true;
84 | } catch (NoPeerConnectionException | ProcessExecutionException | InvalidProcessStateException e) {
85 | LOG.error("Cannot login user {}", credentials.getUserId(), e);
86 | return false;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/login/UserLogoutTask.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.login;
2 |
3 | import android.app.ProgressDialog;
4 |
5 | import org.hive2hive.core.api.interfaces.IH2HNode;
6 | import org.hive2hive.core.exceptions.NoPeerConnectionException;
7 | import org.hive2hive.core.exceptions.NoSessionException;
8 | import org.hive2hive.mobile.H2HApplication;
9 | import org.hive2hive.mobile.R;
10 | import org.hive2hive.mobile.common.BaseProgressTask;
11 | import org.hive2hive.mobile.common.ISuccessFailListener;
12 | import org.hive2hive.processframework.exceptions.InvalidProcessStateException;
13 | import org.hive2hive.processframework.exceptions.ProcessExecutionException;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | /**
18 | * Represents an asynchronous logout task
19 | */
20 | public class UserLogoutTask extends BaseProgressTask {
21 | private static final Logger LOG = LoggerFactory.getLogger(UserLogoutTask.class);
22 |
23 | public UserLogoutTask(H2HApplication context, ISuccessFailListener listener, ProgressDialog progressDialog) {
24 | super(context, listener, progressDialog);
25 | }
26 |
27 | @Override
28 | protected String[] getProgressMessages() {
29 | String[] progressMessages = new String[1];
30 | progressMessages[0] = context.getString(R.string.progress_logout_msg);
31 | return progressMessages;
32 | }
33 |
34 | @Override
35 | protected Boolean doInBackground(Void... params) {
36 | IH2HNode node = context.h2hNode();
37 | if (node == null || !node.isConnected()) {
38 | LOG.error("H2HNode is null or not connected (anymore)");
39 | // TODO head back to the connection activity
40 | return false;
41 | }
42 |
43 | try {
44 | if (!node.getUserManager().isLoggedIn()) {
45 | LOG.info("Not logged in");
46 | return true;
47 | }
48 | LOG.debug("Start logging out...");
49 | node.getUserManager().createLogoutProcess().execute();
50 | LOG.debug("Successfully logged out");
51 | return true;
52 | } catch (InvalidProcessStateException | ProcessExecutionException | NoPeerConnectionException | NoSessionException e) {
53 | LOG.error("Cannot logout properly", e);
54 | return false;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/preference/PortPickerPreference.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.preference;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.preference.DialogPreference;
6 | import android.util.AttributeSet;
7 | import android.view.Gravity;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.FrameLayout;
11 | import android.widget.NumberPicker;
12 |
13 | import org.hive2hive.core.H2HConstants;
14 |
15 | /**
16 | * A {@link android.preference.Preference} that displays a number picker as a dialog.
17 | */
18 | public class PortPickerPreference extends DialogPreference {
19 |
20 | public static final int MAX_VALUE = 65535;
21 | public static final int MIN_VALUE = 1;
22 | public static final int DEFAULT_PORT = H2HConstants.H2H_PORT;
23 |
24 | private NumberPicker picker;
25 | private int value;
26 |
27 | public PortPickerPreference(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | }
30 |
31 | public PortPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | }
34 |
35 | @Override
36 | protected View onCreateDialogView() {
37 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
38 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
39 | layoutParams.gravity = Gravity.CENTER;
40 |
41 | picker = new NumberPicker(getContext());
42 | picker.setLayoutParams(layoutParams);
43 |
44 | FrameLayout dialogView = new FrameLayout(getContext());
45 | dialogView.addView(picker);
46 |
47 | return dialogView;
48 | }
49 |
50 | @Override
51 | protected void onBindDialogView(View view) {
52 | super.onBindDialogView(view);
53 | picker.setMinValue(MIN_VALUE);
54 | picker.setMaxValue(MAX_VALUE);
55 | picker.setValue(getValue());
56 | }
57 |
58 | @Override
59 | protected void onDialogClosed(boolean positiveResult) {
60 | if (positiveResult) {
61 | setValue(picker.getValue());
62 | }
63 | }
64 |
65 | @Override
66 | protected Object onGetDefaultValue(TypedArray a, int index) {
67 | return a.getInt(index, DEFAULT_PORT);
68 | }
69 |
70 | @Override
71 | protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
72 | setValue(restorePersistedValue ? getPersistedInt(DEFAULT_PORT) : (Integer) defaultValue);
73 | }
74 |
75 | public void setValue(int value) {
76 | this.value = value;
77 | persistInt(this.value);
78 | }
79 |
80 | public int getValue() {
81 | return this.value;
82 | }
83 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/preference/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.preference;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | import org.hive2hive.mobile.R;
7 |
8 | /**
9 | * @author Nico
10 | */
11 | public class SettingsActivity extends Activity {
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setTitle(R.string.action_settings);
16 |
17 | // Display the fragment as the main content.
18 | getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
19 | }
20 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/preference/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.preference;
2 |
3 | import android.content.SharedPreferences;
4 | import android.content.pm.PackageManager;
5 | import android.os.Bundle;
6 | import android.preference.EditTextPreference;
7 | import android.preference.ListPreference;
8 | import android.preference.Preference;
9 | import android.preference.PreferenceCategory;
10 | import android.preference.PreferenceFragment;
11 |
12 | import org.hive2hive.mobile.BuildConfig;
13 | import org.hive2hive.mobile.H2HApplication;
14 | import org.hive2hive.mobile.R;
15 | import org.hive2hive.mobile.common.AndroidFileAgent;
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | import java.io.File;
20 |
21 | /**
22 | * @author Nico
23 | * Inspired by http://www.vogella.com/tutorials/AndroidFileBasedPersistence/article.html
24 | */
25 | public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
26 |
27 | private static final Logger LOG = LoggerFactory.getLogger(SettingsFragment.class);
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | addPreferencesFromResource(R.xml.preferences);
33 |
34 | // show the current value in the settings screen
35 | for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
36 | initSummary(getPreferenceScreen().getPreference(i));
37 | }
38 |
39 | try {
40 | String appVersion = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName;
41 | findPreference(getString(R.string.pref_app_version_key)).setSummary(appVersion);
42 | } catch (PackageManager.NameNotFoundException e) {
43 | LOG.warn("Cannot get the application version", e);
44 | }
45 |
46 | findPreference(getString(R.string.pref_h2h_version_key)).setSummary(BuildConfig.H2H_VERSION);
47 |
48 | // depends whether the user is logged in or not
49 | H2HApplication context = (H2HApplication) getActivity().getApplicationContext();
50 | File root = AndroidFileAgent.getStorageLocation(context, context.currentUser());
51 | findPreference(getString(R.string.pref_path_key)).setSummary(root.getAbsolutePath());
52 |
53 | }
54 |
55 | @Override
56 | public void onResume() {
57 | super.onResume();
58 | getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
59 | }
60 |
61 | @Override
62 | public void onPause() {
63 | super.onPause();
64 | getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
65 | }
66 |
67 | @Override
68 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
69 | updatePreferences(findPreference(key));
70 | }
71 |
72 | private void initSummary(Preference p) {
73 | if (p instanceof PreferenceCategory) {
74 | PreferenceCategory cat = (PreferenceCategory) p;
75 | for (int i = 0; i < cat.getPreferenceCount(); i++) {
76 | initSummary(cat.getPreference(i));
77 | }
78 | } else {
79 | updatePreferences(p);
80 | }
81 | }
82 |
83 | private void updatePreferences(Preference p) {
84 | if (p instanceof EditTextPreference) {
85 | EditTextPreference editTextPref = (EditTextPreference) p;
86 | p.setSummary(editTextPref.getText());
87 | } else if (p instanceof PortPickerPreference) {
88 | PortPickerPreference ppPref = (PortPickerPreference) p;
89 | p.setSummary(String.valueOf(ppPref.getValue()));
90 | } else if (p instanceof ListPreference) {
91 | ListPreference lPref = ((ListPreference) p);
92 | p.setSummary(lPref.getEntry());
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/security/SCSecurityClassProvider.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.security;
2 |
3 | import org.hive2hive.core.serializer.ISecurityClassProvider;
4 | import org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey;
5 | import org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey;
6 | import org.spongycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey;
7 | import org.spongycastle.jce.provider.BouncyCastleProvider;
8 |
9 | import java.security.interfaces.RSAPrivateCrtKey;
10 | import java.security.interfaces.RSAPrivateKey;
11 | import java.security.interfaces.RSAPublicKey;
12 |
13 | /**
14 | * @author Nico
15 | */
16 | public class SCSecurityClassProvider implements ISecurityClassProvider {
17 |
18 | public static final String SECURITY_PROVIDER = BouncyCastleProvider.PROVIDER_NAME;
19 |
20 | @Override
21 | public String getSecurityProvider() {
22 | return SECURITY_PROVIDER;
23 | }
24 |
25 | @Override
26 | public Class extends RSAPublicKey> getRSAPublicKeyClass() {
27 | return BCRSAPublicKey.class;
28 | }
29 |
30 | @Override
31 | public Class extends RSAPrivateKey> getRSAPrivateKeyClass() {
32 | return BCRSAPrivateKey.class;
33 | }
34 |
35 | @Override
36 | public Class extends RSAPrivateCrtKey> getRSAPrivateCrtKeyClass() {
37 | return BCRSAPrivateCrtKey.class;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/security/SCStrongAESEncryption.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.security;
2 |
3 | import org.hive2hive.core.security.IStrongAESEncryption;
4 | import org.spongycastle.crypto.CipherParameters;
5 | import org.spongycastle.crypto.DataLengthException;
6 | import org.spongycastle.crypto.InvalidCipherTextException;
7 | import org.spongycastle.crypto.engines.AESEngine;
8 | import org.spongycastle.crypto.modes.CBCBlockCipher;
9 | import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
10 | import org.spongycastle.crypto.params.KeyParameter;
11 | import org.spongycastle.crypto.params.ParametersWithIV;
12 |
13 | import java.security.GeneralSecurityException;
14 |
15 | import javax.crypto.SecretKey;
16 |
17 | /**
18 | * Copy of {@link org.hive2hive.core.security.BCStrongAESEncryption}, but using spongy castle
19 | *
20 | * @author Nico
21 | */
22 | public class SCStrongAESEncryption implements IStrongAESEncryption {
23 |
24 | @Override
25 | public byte[] encryptStrongAES(byte[] data, SecretKey key, byte[] initVector) throws GeneralSecurityException {
26 | try {
27 | return processAESCipher(true, data, key, initVector);
28 | } catch (DataLengthException | IllegalStateException | InvalidCipherTextException e) {
29 | throw new GeneralSecurityException("Cannot encrypt the data with AES 256bit", e);
30 | }
31 | }
32 |
33 | @Override
34 | public byte[] decryptStrongAES(byte[] data, SecretKey key, byte[] initVector) throws GeneralSecurityException {
35 | try {
36 | return processAESCipher(false, data, key, initVector);
37 | } catch (DataLengthException | IllegalStateException | InvalidCipherTextException e) {
38 | throw new GeneralSecurityException("Cannot decrypt the data with AES 256bit", e);
39 | }
40 | }
41 |
42 | private static byte[] processAESCipher(boolean encrypt, byte[] data, SecretKey key, byte[] initVector)
43 | throws DataLengthException, IllegalStateException, InvalidCipherTextException {
44 | // seat up engine, block cipher mode and padding
45 | AESEngine aesEngine = new AESEngine();
46 | CBCBlockCipher cbc = new CBCBlockCipher(aesEngine);
47 | PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbc);
48 |
49 | // apply parameters
50 | CipherParameters parameters = new ParametersWithIV(new KeyParameter(key.getEncoded()), initVector);
51 | cipher.init(encrypt, parameters);
52 |
53 | // process ciphering
54 | byte[] output = new byte[cipher.getOutputSize(data.length)];
55 |
56 | int bytesProcessed1 = cipher.processBytes(data, 0, data.length, output, 0);
57 | int bytesProcessed2 = cipher.doFinal(output, bytesProcessed1);
58 | byte[] result = new byte[bytesProcessed1 + bytesProcessed2];
59 | System.arraycopy(output, 0, result, 0, result.length);
60 | return result;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/java/org/hive2hive/mobile/security/SpongyCastleEncryption.java:
--------------------------------------------------------------------------------
1 | package org.hive2hive.mobile.security;
2 |
3 | import org.hive2hive.core.security.H2HDefaultEncryption;
4 | import org.hive2hive.core.serializer.IH2HSerialize;
5 |
6 | import java.security.Security;
7 |
8 | /**
9 | * @author Nico
10 | */
11 | public class SpongyCastleEncryption extends H2HDefaultEncryption {
12 |
13 |
14 | public SpongyCastleEncryption(IH2HSerialize serializer) {
15 | super(serializer, SCSecurityClassProvider.SECURITY_PROVIDER, new SCStrongAESEncryption());
16 |
17 | // install the SC provider instead of the BC provider
18 | if (Security.getProvider(SCSecurityClassProvider.SECURITY_PROVIDER) == null) {
19 | Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/animator/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/animator/slide_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/animator/slide_out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/animator/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_action_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_action_upload.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_action_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_action_upload.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_action_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_action_upload.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_action_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_action_upload.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/h2h_logo_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/h2h_logo_large.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_archive_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_archive_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_archive_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_archive_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_audio_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_audio_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_audio_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_audio_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_blank_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_blank_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_blank_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_blank_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_calendar_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_calendar_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_calendar_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_calendar_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_cloud_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_cloud_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_code_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_code_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_code_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_code_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_download_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_download_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_loading.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_shared.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_shared.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_folder_upload.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_image_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_image_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_image_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_image_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_loading_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_loading_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_powerpoint_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_powerpoint_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_powerpoint_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_powerpoint_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_spreadsheet_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_spreadsheet_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_spreadsheet_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_spreadsheet_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_text_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_text_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_text_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_text_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_upload_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_upload_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_video_ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_video_ex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/ic_video_inex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/ic_video_inex.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/drawable/login_lock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/app/src/main/res/drawable/login_lock.png
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/layout/activity_connect.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
22 |
23 |
27 |
28 |
34 |
35 |
36 |
43 |
44 |
50 |
51 |
57 |
58 |
65 |
66 |
71 |
72 |
73 |
77 |
78 |
86 |
87 |
96 |
97 |
98 |
99 |
100 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/layout/activity_files.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
23 |
24 |
25 |
32 |
33 |
37 |
38 |
43 |
44 |
45 |
48 |
49 |
57 |
58 |
66 |
67 |
75 |
76 |
82 |
83 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/layout/dialog_share.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
28 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/layout/fragment_files.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
17 |
18 |
19 |
29 |
30 |
31 |
39 |
40 |
41 |
49 |
50 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/menu/menu_files.xml:
--------------------------------------------------------------------------------
1 |
44 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/menu/menu_settings.xml:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 12dp
4 | 12dp
5 |
6 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hive2Hive
5 | Settings
6 | Help
7 |
8 | https://github.com/Hive2Hive/Android/wiki
9 | https://github.com/Hive2Hive/Android/wiki/Guide-for-App-Users#login
10 | https://github.com/Hive2Hive/Android/wiki/Guide-for-App-Users#file-management
11 |
12 |
13 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings_activity_connect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Connect to the Network
5 | Mode
6 | Bootstrap Address
7 | Port
8 | Map update interval (s)
9 | Show advanced settings
10 | Connect
11 | Disconnect
12 | Node is connected
13 | Node could not connect
14 |
15 | Configure the GCM sender ID to use GCM Push
16 | No network connection detected …
17 |
18 | GCM Push
19 | Open TCP
20 | Full Peer
21 | (recommended)
22 |
23 | Connecting to network …
24 | Resolving network address …
25 | Bootstrapping …
26 | Registering mobile device …
27 | Connecting to relay …
28 |
29 | Disconnecting …
30 | Shutting down peer …
31 |
32 | Go to login
33 |
34 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings_activity_files.xml:
--------------------------------------------------------------------------------
1 |
2 | Cannot load the file list. Use refresh button to re-try
3 | Failed to delete the file
4 | Non-empty folders cannot be deleted
5 | Failed to add a copy of the selected file
6 | Uploading file %1$s failed
7 | Downloading file %1$s failed
8 | We did not find any application that can open this kind of files
9 | Please install a file manager to browse your files
10 | Cannot share the folder. Does user \'%1$s\' really exist?
11 | You only have read access to this folder
12 |
13 | Press again to logout
14 |
15 | empty
16 | 1 item
17 | %1$d items
18 |
19 | Loading file list…
20 |
21 |
22 | Download
23 | Upload changes
24 | Open
25 | Delete on phone
26 | Delete permanently
27 | Share with…
28 | See shared list
29 |
30 |
31 | Refresh
32 | Logout
33 | Add File
34 | Create Folder
35 |
36 |
37 | synchronized
38 | downloading…
39 | tap to download
40 | tap to download newest version
41 | uploading…
42 | deleting…
43 | sharing…
44 | shared
45 |
46 |
47 | New folder
48 | Enter the name of the folder:
49 |
50 |
51 | Share folder
52 | Enter the username of the user to invite:
53 | Allow changes
54 |
55 |
56 | Access list
57 | The following users have access to folder \'%1$s\':
58 | (read-only)
59 |
60 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings_activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 | Login
3 |
4 |
5 | Username
6 | Password
7 | PIN
8 | Remember credentials
9 | Sign in or register
10 |
11 | These credentials are incorrect
12 | This field is required
13 |
14 | Logging in…
15 | Encrypting your credentials…
16 | Checking for existing user…
17 | Registering…
18 | Logging in…
19 |
20 | Logging out…
21 | Please wait…
22 | Logout failed
23 |
24 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings_activity_power.xml:
--------------------------------------------------------------------------------
1 |
2 | Statistics
3 |
4 |
5 | Send message
6 | Put data
7 | Start measurement
8 | Stop measurement
9 | Logs saved at
10 |
11 |
12 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/strings_activity_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Networking
5 | About
6 |
7 | Binding port
8 | pref.port
9 |
10 | Poll interval
11 | pref.map
12 |
13 | - Every 30 seconds
14 | - Every minute
15 | - Every 2 minutes seconds (default)
16 | - Every 5 minutes
17 | - Every 10 minutes
18 |
19 |
20 | - 30
21 | - 60
22 | - 120
23 | - 300
24 | - 600
25 |
26 |
27 | GCM sender ID
28 | pref.gcmsender
29 |
30 | Hive2Hive Root path
31 | pref.path
32 |
33 | Hive2Hive version
34 | pref.version.h2h
35 |
36 | App version
37 | pref.version.app
38 |
39 | Author
40 |
41 | Contact
42 | Give feedback or ask a question
43 | mailto:info@hive2hive.com
44 | Feedback Android App
45 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
10 |
11 |
18 |
19 |
25 |
26 |
27 |
29 |
30 |
35 |
40 |
45 |
51 |
52 |
56 |
59 |
62 |
63 | />
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
--------------------------------------------------------------------------------
/org.hive2hive.mobile/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/org.hive2hive.mobile/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hive2Hive/Android/68599adabe7284df58be55e03688a4f999c1b510/org.hive2hive.mobile/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/org.hive2hive.mobile/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Dec 12 09:32:44 CET 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/org.hive2hive.mobile.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/org.hive2hive.mobile/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------