Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support to have p2p #300

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<!-- READ_EXTERNAL_STORAGE is required if users want to include photos from their phone -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- SEND_SMS is required if users want to send reports as SMS.To able the feature add the following line:
<uses-permission android:name="android.permission.SEND_SMS"/>
-->
Expand Down
242 changes: 215 additions & 27 deletions src/main/java/org/medicmobile/webapp/mobile/EmbeddedBrowserActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,50 @@
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

import android.os.StrictMode;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.Toast;

import androidx.core.content.ContextCompat;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@SuppressWarnings({ "PMD.GodClass", "PMD.TooManyMethods" })
public class EmbeddedBrowserActivity extends Activity {

Button download_button;
Button upload_button;
public String role = "Placeholder";
private WebView container;
private SettingsStore settings;
private String appUrl;
Expand All @@ -59,13 +84,13 @@ public void onReceiveValue(String result) {
}
}
};
private List<String> userData;


//> ACTIVITY LIFECYCLE METHODS
//> ACTIVITY LIFECYCLE METHODS
@SuppressLint("ClickableViewAccessibility")
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

trace(this, "Starting webview...");

this.filePickerHandler = new FilePickerHandler(this);
Expand All @@ -80,10 +105,36 @@ public void onReceiveValue(String result) {

this.settings = SettingsStore.in(this);
this.appUrl = settings.getAppUrl();

this.requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.main);
download_button = findViewById(R.id.download_button);
upload_button = findViewById(R.id.upload_button);

download_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String userName = getUserData().get(0);

container.evaluateJavascript("console.log('"+ "username:"+ userName + "')", null);
String script = "window.PouchDB('medic-user-"+ userName+"')" +
".allDocs({include_docs: true, attachments: true})" +
".then(result => medicmobile_android.saveDocs(JSON.stringify(result),'"+userName+"'));";
container.evaluateJavascript(script, null);
}
});
Log.d("Screen", getApplicationContext().toString());

upload_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i2 = new Intent(Intent.ACTION_GET_CONTENT);
i2.setType("*/*");
i2.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(i2, 106);

}
});
// Add an alarming red border if using configurable (i.e. dev)
// app with a medic production server.
if (settings.allowsConfiguration() && appUrl != null && appUrl.contains("app.medicmobile.org")) {
Expand All @@ -101,9 +152,9 @@ public void onReceiveValue(String result) {

container = findViewById(R.id.wbvMain);
getFragmentManager()
.beginTransaction()
.add(new OpenSettingsDialogFragment(container), OpenSettingsDialogFragment.class.getName())
.commit();
.beginTransaction()
.add(new OpenSettingsDialogFragment(container), OpenSettingsDialogFragment.class.getName())
.commit();

configureUserAgent();

Expand All @@ -128,6 +179,56 @@ public void onReceiveValue(String result) {
if (isValidNavigationUrl(appUrl, recentNavigation)) {
container.loadUrl(recentNavigation);
}
container.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d("URL used in the client.", url);
if (!url.contains("login") ) {
upload_button.setVisibility(View.VISIBLE);
download_button.setVisibility(View.VISIBLE);
role = getUserData().get(1);
role = role.substring(1, role.length() - 1);
boolean isUpdateRole = role != "Placeholder" && role.equals("chw_supervisor");
boolean isDownloadRole = role != "Placeholder" && role.equals("chw");
if (isDownloadRole){
upload_button.setVisibility(View.GONE);
}else if (isUpdateRole){
download_button.setVisibility(View.GONE);
}
} else {
upload_button.setVisibility(View.GONE);
download_button.setVisibility(View.GONE);
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload){
if (!Objects.isNull(url) && !url.contains("report") && !url.contains("login") && url.split("/").length > 3) {
Log.d(String.valueOf((url.split("/").length)),"printing URL ...");
upload_button.setVisibility(View.VISIBLE);
download_button.setVisibility(View.VISIBLE);
if (getUserData()!=null){
role = getUserData().get(1);
role = role.substring(1, role.length() - 1);
boolean isUpdateRole = role != "Placeholder" && role.equals("chw_supervisor");
boolean isDownloadRole = role != "Placeholder" && role.equals("chw");
if (isDownloadRole){
upload_button.setVisibility(View.GONE);
}else if (isUpdateRole){
download_button.setVisibility(View.GONE);
}
}
} else {
upload_button.setVisibility(View.GONE);
download_button.setVisibility(View.GONE);
}
super.doUpdateVisitedHistory(view,url,isReload);
}
@Override
public void onPageFinished(WebView view, String url) {
//page has finished loading
}
});
}

@SuppressWarnings("PMD.CallSuperFirst")
Expand All @@ -136,13 +237,17 @@ protected void onStart() {
trace(this, "onStart() :: Checking Crosswalk migration ...");
XWalkMigration xWalkMigration = new XWalkMigration(this.getApplicationContext());
if (xWalkMigration.hasToMigrate()) {

log(this, "onStart() :: Running Crosswalk migration ...");
isMigrationRunning = true;
Intent intent = new Intent(this, UpgradingActivity.class)
.putExtra("isClosable", false)
.putExtra("backPressedMessage", getString(R.string.waitMigration));
.putExtra("isClosable", false)
.putExtra("backPressedMessage", getString(R.string.waitMigration));
startActivity(intent);
xWalkMigration.run();
role = getUserData().get(0);
Log.d("Role is ", role);

} else {
trace(this, "onStart() :: Crosswalk installation not found - skipping migration");
}
Expand Down Expand Up @@ -175,6 +280,7 @@ protected void onStop() {
backButtonHandler);
}

@SuppressLint("Recycle")
@Override
protected void onActivityResult(int requestCd, int resultCode, Intent intent) {
Optional<RequestCode> requestCodeOpt = RequestCode.valueOf(requestCd);
Expand All @@ -190,6 +296,21 @@ protected void onActivityResult(int requestCd, int resultCode, Intent intent) {
trace(this, "onActivityResult() :: requestCode=%s, resultCode=%s", requestCode.name(), resultCode);

switch (requestCode) {
case PICK_FILE_REQUEST:
if (resultCode == RESULT_OK && intent != null) {
if(intent.getClipData() != null) {
int count = intent.getClipData().getItemCount();
int currentItem = 0;
while(currentItem < count) {
Uri data_uri = intent.getClipData().getItemAt(currentItem).getUri();
uploadFile(data_uri, currentItem);
currentItem = currentItem + 1;
}
} else{
Uri data_uri = intent.getData();
uploadFile(data_uri, 1);
}
}
case FILE_PICKER_ACTIVITY:
this.filePickerHandler.processResult(resultCode, intent);
return;
Expand All @@ -214,11 +335,38 @@ protected void onActivityResult(int requestCd, int resultCode, Intent intent) {
} catch (Exception ex) {
String action = intent == null ? null : intent.getAction();
warn(ex, "Problem handling intent %s (%s) with requestCode=%s & resultCode=%s",
intent, action, requestCode.name(), resultCode);
intent, action, requestCode.name(), resultCode);
}
}

//> ACCESSORS
private void uploadFile(Uri data_uri, int currentItem){
String content;
try {
InputStream in = getContentResolver().openInputStream(data_uri);
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
total.append(line);
}
if (Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
content =total.toString().replaceAll("\"total_rows\".*\"rows\":","\"docs\":");
String script = "new PouchDB('temp')" +
".bulkDocs("+content+");";
container.evaluateJavascript(script, null);
String script_sync = "window.PouchDB('temp')" +
".replicate.to('"+appUrl+"/medic').then(result =>" +
"medicmobile_android.toastResult('Uploaded file number "+(currentItem+1)+" Successfully')).catch(err =>" +
"medicmobile_android.toastResult(JSON.stringify(err)));";
container.evaluateJavascript(script_sync, null);
}catch (Exception e) {
warn(e, "Could not open the specified file");
toast("Could not open the specified file");
}
}
//> ACCESSORS
MrdtSupport getMrdtSupport() {
return this.mrdt;
}
Expand All @@ -230,8 +378,7 @@ SmsSender getSmsSender() {
ChtExternalAppHandler getChtExternalAppHandler() {
return this.chtExternalAppHandler;
}

//> PUBLIC API
//> PUBLIC API
public void evaluateJavascript(final String js) {
evaluateJavascript(js, true);
}
Expand Down Expand Up @@ -272,17 +419,57 @@ public boolean getLocationPermissions() {

trace(this, "getLocationPermissions() :: Fine or Coarse location not granted before, requesting access...");
startActivityForResult(
new Intent(this, RequestLocationPermissionActivity.class),
RequestCode.ACCESS_LOCATION_PERMISSION.getCode()
new Intent(this, RequestLocationPermissionActivity.class),
RequestCode.ACCESS_LOCATION_PERMISSION.getCode()
);
return false;
}

//> PRIVATE HELPERS
//> PRIVATE HELPERS
private void locationRequestResolved() {
evaluateJavascript("window.CHTCore.AndroidApi.v1.locationPermissionRequestResolved();");
}

public List<String> getUserData(){
List<String> userData = new ArrayList<>();
try {
String cookies = CookieManager.getInstance().getCookie(appUrl);
if (Objects.isNull(cookies)){
return null;
}
Log.d("updating user data", ": updated");

if ( cookies != null && !cookies.isEmpty()){
String encodedUserCtxCookie = Arrays.stream(cookies.split(";"))
.map(field -> field.split("="))
.filter(pair -> "userCtx".equals(pair[0].trim()))
.map(pair -> pair[1].trim())
.findAny()
.get();
String userCtxData = URLDecoder.decode(encodedUserCtxCookie, "utf-8")
.replace("{", "")
.replace("}", "");
String userName = Arrays.stream(userCtxData.split(","))
.map(field -> field.split(":"))
.filter(pair -> "\"name\"".equals(pair[0].trim()))
.map(pair -> pair[1].replace("\"", "").trim())
.findAny()
.get();
userData.add(userName);
role = (Arrays.stream(userCtxData.split(","))
.map(field -> field.split(":"))
.filter(pair -> "\"roles\"".equals(pair[0].trim()))
.map(pair -> pair[1].replace("\"", "").trim())
.findAny()
.get());
userData.add(role);
return userData;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
private void processChtExternalAppResult(int resultCode, Intent intentData) {
String script = this.chtExternalAppHandler.processResult(resultCode, intentData);
trace(this, "ChtExternalAppHandler :: Executing JavaScript: %s", script);
Expand Down Expand Up @@ -311,10 +498,10 @@ private void processStoragePermissionResult(int resultCode, Intent intent) {
}

trace(
this,
"EmbeddedBrowserActivity :: No handling for trigger: %s, requestCode: %s",
triggerClass,
RequestCode.ACCESS_STORAGE_PERMISSION.name()
this,
"EmbeddedBrowserActivity :: No handling for trigger: %s, requestCode: %s",
triggerClass,
RequestCode.ACCESS_STORAGE_PERMISSION.name()
);
}

Expand Down Expand Up @@ -398,14 +585,15 @@ private void registerRetryConnectionBroadcastReceiver() {
registerReceiver(broadcastReceiver, new IntentFilter("retryConnection"));
}

//> ENUMS
//> ENUMS
public enum RequestCode {
ACCESS_LOCATION_PERMISSION(100),
ACCESS_STORAGE_PERMISSION(101),
ACCESS_SEND_SMS_PERMISSION(102),
CHT_EXTERNAL_APP_ACTIVITY(103),
GRAB_MRDT_PHOTO_ACTIVITY(104),
FILE_PICKER_ACTIVITY(105);
FILE_PICKER_ACTIVITY(105),
PICK_FILE_REQUEST(106);

private final int requestCode;

Expand All @@ -415,9 +603,9 @@ public enum RequestCode {

public static Optional<RequestCode> valueOf(int code) {
return Arrays
.stream(RequestCode.values())
.filter(e -> e.getCode() == code)
.findFirst();
.stream(RequestCode.values())
.filter(e -> e.getCode() == code)
.findFirst();
}

public int getCode() {
Expand Down
Loading