Commit a2847753 authored by Lucas Braz Cunha's avatar Lucas Braz Cunha

Merge after bug fix

Signed-off-by: Lucas Braz Cunha's avatarLucas B. Cunha <lbc16@inf.ufpr.br>
parents 85b51733 2e819f86
......@@ -32,4 +32,6 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support.test.espresso:espresso-core:2.2.2'
compile 'com.firebase:firebase-jobdispatcher:0.6.0'
}
......@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
......@@ -44,6 +45,19 @@
<activity android:name=".ForgotPasswordActivity">
</activity>
<service android:name=".services.ImageUpdateService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
</application>
</manifest>
\ No newline at end of file
package br.ufpr.c3sl.agendador.agendador;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
......@@ -20,6 +21,7 @@ import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
......@@ -27,9 +29,14 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.UserPhotoHelper;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.presenters.HomePresenter;
import br.ufpr.c3sl.agendador.agendador.services.ImageUpdateService;
import br.ufpr.c3sl.agendador.agendador.views.HomeView;
/**
......@@ -235,4 +242,5 @@ public class HomeActivity extends AppCompatActivity implements HomeView,
}
}
}
......@@ -42,6 +42,8 @@ public class UserPhotoHelper {
//Constructor for LoginActivity use
// TODO: 08/05/17 check usage of getExternalFilesDirs
//https://developer.android.com/guide/topics/data/data-storage.html
public UserPhotoHelper(Context context, String uid){
this.mContext = context;
this.filePath = mContext.getExternalFilesDir(null) + File.separator + Utils.DIR_PICTRS + File.separator + Utils.USR_PICT_FILE_NAME;
......@@ -51,6 +53,10 @@ public class UserPhotoHelper {
//Function to save bitmap received from server on login
public void saveBitmap(Bitmap bmp) throws IOException {
File f2 = new File(mContext.getExternalFilesDir(null) + File.separator + Utils.DIR_PICTRS + File.separator);
f2.mkdirs();
File f = new File(photoFileUri.getPath());
f.createNewFile();
FileOutputStream out = new FileOutputStream(photoFileUri.getPath());
bmp.compress(Bitmap.CompressFormat.PNG, 100, out); //100-best quality
out.close();
......@@ -62,10 +68,10 @@ public class UserPhotoHelper {
this.mContext = context;
osb = ObscuredSharedPreferences.getPrefs(mContext, "Agendador", Context.MODE_PRIVATE);
this.filePath = mContext.getExternalFilesDir(null) + File.separator + Utils.DIR_PICTRS + File.separator + Utils.USR_PICT_FILE_NAME;
createFile();
initVariables();
}
private void createFile() {
private void initVariables() {
this.userUid = osb.getString("uid", null);
this.photo = new File(filePath + userUid + ".bmp");
this.tempPhoto = new File(filePath + "temp_" + userUid);
......
......@@ -24,6 +24,8 @@ public class Utils {
public final static String DIR_PICTRS = "pictures";
public final static String USR_PICT_FILE_NAME = "usr_prof_pic_";
public final static String SERVICE_UPDATE_IMAGE = "br.c3sl.ufpr.image_update";
public static int getPixelValue(int dp, Context context) {
Resources resources = context.getResources();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
......
package br.ufpr.c3sl.agendador.agendador.models;
import android.content.Context;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
/**
* Created by Bruno Freitas Tissei on 2/3/17.
*/
......
......@@ -39,4 +39,7 @@ public interface ApiEndpoints {
@GET("citizens/{id}/picture")
Call<ResponseBody> requestPhoto(@Path("id") int id, @Query("size") String size);
@GET("accounts/self")
Call<AccountOutput> requestSelf();
}
\ No newline at end of file
......@@ -2,7 +2,10 @@ package br.ufpr.c3sl.agendador.agendador.presenters;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
......@@ -11,6 +14,7 @@ import java.util.HashMap;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.AccountOutput;
import br.ufpr.c3sl.agendador.agendador.models.AccountUpdate;
import br.ufpr.c3sl.agendador.agendador.models.Address;
......@@ -24,8 +28,6 @@ import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static android.util.Log.d;
/**
* Created by Horstmann on 02/03/17.
*/
......@@ -35,20 +37,89 @@ public class AccountPresenter extends BasePresenter<AccountView> {
private ObscuredSharedPreferences osb;
private Context context;
private AccountPresenter accountPresenter;
private boolean isPicUpdate;
public AccountPresenter(Context context) {
this.context = context;
accountPresenter = this;
isPicUpdate = false;
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
}
private void onSuccessfulCheck(AccountOutput accountOutput, Headers headers){
osb.edit().putString("expiry", headers.get("expiry")).apply();
accountOutput.getCitizen().save(context);
String token = headers.get("access-token");
if(token != null)
osb.edit().putString("access-token", token).apply();
}
public void updateCheck(){
accountPresenter.view().setProgressBar(true);
Map<String, String> header = new HashMap<>();
header.put("Content-Type", "application/json");
header.put("access-token", osb.getString("access-token", null));
header.put("client", osb.getString("client", null));
header.put("uid", osb.getString("uid", null));
ApiEndpoints service = ApiUtils.request(header);
Call<AccountOutput> listCall = service.requestSelf();
listCall.enqueue(new Callback<AccountOutput>() {
@Override
public void onResponse(Call<AccountOutput> call, Response<AccountOutput> response) {
Headers headers = response.headers();
int status = response.code();
AccountOutput accountOutput = response.body();
Log.d("SELF Request", "Got " + status + " from server on self request!!!");
switch (status) {
case 200:
//info downloaded
accountPresenter.view().setUpdated(true);
onSuccessfulCheck(accountOutput, headers);
accountPresenter.view().setProgressBar(false);
accountPresenter.view().successfulUpdate();
accountPresenter.view().enableButtonEdit(true);
accountPresenter.view().enableButtonSync(true);
break;
default:
accountPresenter.view().setUpdated(false);
accountPresenter.view().setProgressBar(false);
accountPresenter.view().enableAllFields(false);
accountPresenter.view().enableButtonEdit(false);
accountPresenter.view().enableButtonSync(true);
accountPresenter.view().setConnectionError(true);
break;
}
}
@Override
public void onFailure(Call<AccountOutput> call, Throwable t) {
accountPresenter.view().setUpdated(false);
accountPresenter.view().setProgressBar(false);
accountPresenter.view().enableAllFields(false);
accountPresenter.view().enableButtonEdit(false);
accountPresenter.view().enableButtonSync(true);
accountPresenter.view().setNoConnection(true);
}
});
}
private void onSuccessfulUpdate(AccountOutput accountOutput, Headers headers) {
updateToken(headers);
accountOutput.getCitizen().save(context);
//cancelling job because photo has been updated from app.
if(isPicUpdate){
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
dispatcher.cancel(Utils.SERVICE_UPDATE_IMAGE);
isPicUpdate = false;
}
}
private void updateToken(Headers headers) {
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
osb.edit().putString("access-token", headers.get("access-token")).apply();
osb.edit().putString("client", headers.get("client")).apply();
osb.edit().putString("uid", headers.get("uid")).apply();
String token = headers.get("access-token");
......@@ -57,11 +128,10 @@ public class AccountPresenter extends BasePresenter<AccountView> {
}
@Override
protected void updateView() {
protected void updateView() {}
}
public void onUpdateClicked(){
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
Map<String, String> header = new HashMap<>();
header.put("Content-Type", "application/json");
......@@ -75,16 +145,16 @@ public class AccountPresenter extends BasePresenter<AccountView> {
UserUpdate user = new UserUpdate(body);
final AccountUpdate account;
if(body.get("photo_type") != null)
if(body.get("photo_type") != null) {
user.setImage(body.get("photo_type"), body.get("photo_name"), body.get("photo_content"));
isPicUpdate = true;
}
if (body.get("password") == null || body.get("password_confirmation") == null){
account = new AccountUpdate(user);
} else{
account = new AccountUpdate(user, body.get("current_password"), body.get("password"), body.get("password_confirmation"));
}
Call<AccountOutput> listCall = service.update(account);
accountPresenter.view().setProgressBar(true);
listCall.enqueue(new Callback<AccountOutput>() {
......@@ -99,6 +169,7 @@ public class AccountPresenter extends BasePresenter<AccountView> {
case 404:
Log.d("Server response", "404 - Falha!");
accountPresenter.view().setProgressBar(false);
accountPresenter.view().setConnectionError(true);
break;
case 422:
Log.d("Server response", "422 - Erro na requisição!");
......@@ -119,7 +190,6 @@ public class AccountPresenter extends BasePresenter<AccountView> {
@Override
public void onFailure(Call<AccountOutput> call, Throwable t) {
Log.d("Server response", "Requisição falhou!!");
accountPresenter.view().setProgressBar(false);
accountPresenter.view().setNoConnection(true);
......@@ -127,8 +197,6 @@ public class AccountPresenter extends BasePresenter<AccountView> {
});
}
public void onCepNotFocused(String cep) {
Map<String, String> header = new HashMap<>();
header.put("Content-Type", "application/json");
......@@ -152,7 +220,6 @@ public class AccountPresenter extends BasePresenter<AccountView> {
values.put("cityname_su", address.getCity_name());
values.put("statename_su", address.getState_name());
accountPresenter.view().setProgressBar(false);
break;
case 404:
......@@ -192,7 +259,8 @@ public class AccountPresenter extends BasePresenter<AccountView> {
@Override
public void onFailure(Call<Address> call, Throwable t) {
accountPresenter.view().setProgressBar(false);
accountPresenter.view().setNoConnectionCep(true);
accountPresenter.view().setConnectionCepError(true);
Log.d("Aaaa","aaaaaaaa2222222");
}
});
}
......
......@@ -2,12 +2,17 @@ package br.ufpr.c3sl.agendador.agendador.presenters;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import java.util.HashMap;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.LoginActivity;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.SignOutOutput;
import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints;
import br.ufpr.c3sl.agendador.agendador.network.ApiUtils;
......@@ -35,52 +40,16 @@ public class HomePresenter extends BasePresenter<HomeView> {
}
public void onSuccessfulSignOut() {
public void onSignOutClicked() {
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
dispatcher.cancel(Utils.SERVICE_UPDATE_IMAGE);
osb.edit().clear().apply();
Intent intent = new Intent(context, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
public void onSignOutClicked() {
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
Map<String, String> header = new HashMap<>();
header.put("Content-Type", "application/json");
header.put("access-token", osb.getString("access-token", null));
header.put("client", osb.getString("client", null));
header.put("uid", osb.getString("uid", null));
ApiEndpoints service = ApiUtils.request(header);
Call<SignOutOutput> listCall = service.signOut();
// loginPresenter.view().setProgressBar(true);
listCall.enqueue(new Callback<SignOutOutput>() {
@Override
public void onResponse(Call<SignOutOutput> call, Response<SignOutOutput> response) {
int status = response.code();
switch (status) {
case 401:
// homePresenter.view().setProgressBar(false);
break;
case 200:
onSuccessfulSignOut();
// homePresenter.view().setProgressBar(false);
break;
default:
break;
}
}
@Override
public void onFailure(Call<SignOutOutput> call, Throwable t) {
// homePresenter.view().setNoConnection(true);
// homePresenter.view().setProgressBar(false);
}
});
}
}
\ No newline at end of file
......@@ -3,8 +3,17 @@ package br.ufpr.c3sl.agendador.agendador.presenters;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import com.firebase.jobdispatcher.Constraint;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import com.firebase.jobdispatcher.Job;
import com.firebase.jobdispatcher.Lifetime;
import com.firebase.jobdispatcher.RetryStrategy;
import com.firebase.jobdispatcher.Trigger;
import java.io.File;
import java.io.FilenameFilter;
import java.text.DateFormat;
......@@ -25,6 +34,7 @@ import br.ufpr.c3sl.agendador.agendador.models.Account;
import br.ufpr.c3sl.agendador.agendador.models.AccountOutput;
import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints;
import br.ufpr.c3sl.agendador.agendador.network.ApiUtils;
import br.ufpr.c3sl.agendador.agendador.services.ImageUpdateService;
import br.ufpr.c3sl.agendador.agendador.views.LoginView;
import okhttp3.Headers;
import okhttp3.ResponseBody;
......@@ -41,9 +51,15 @@ public class LoginPresenter extends BasePresenter<LoginView> {
private Context context;
private LoginPresenter loginPresenter;
private FirebaseJobDispatcher dispatcher;
public LoginPresenter(Context context) {
this.context = context;
loginPresenter = this;
dispatcher = new FirebaseJobDispatcher(
new GooglePlayDriver(context)
);
}
@Override
......@@ -80,6 +96,7 @@ public class LoginPresenter extends BasePresenter<LoginView> {
Call<AccountOutput> listCall = service.signIn(account);
loginPresenter.view().setProgressBar(true);
Log.d("Login Request", "pedindo login!!!");
listCall.enqueue(new Callback<AccountOutput>() {
@Override
......@@ -90,20 +107,24 @@ public class LoginPresenter extends BasePresenter<LoginView> {
switch (status) {
case 401:
Log.d("Login Request", "Voltou 401!!!");
loginPresenter.view().setWrongPassword(true);
loginPresenter.view().setProgressBar(false);
break;
case 200:
Log.d("Login Request", "Voltou 200!!!");
onSuccessfulLogin(accountOutput, headers);
checkLocalPhoto();
break;
default:
Log.d("Login Request", "Voltou " + status + "!!!");
break;
}
}
@Override
public void onFailure(Call<AccountOutput> call, Throwable t) {
Log.d("Login Request", "Falhou!!!");
loginPresenter.view().setNoConnection(true);
loginPresenter.view().setProgressBar(false);
}
......@@ -132,9 +153,10 @@ public class LoginPresenter extends BasePresenter<LoginView> {
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int status = response.code();
Log.d("Request Imagem", "Retorno da request de imagem: " + status);
switch (status) {
case 500:
//image not found
Log.d("Request Imagem", "500 - Servidor: Internal Error");
loginPresenter.view().setProgressBar(false);
loginPresenter.view().afterSuccessfulLogin();
break;
......@@ -142,21 +164,49 @@ public class LoginPresenter extends BasePresenter<LoginView> {
loginPresenter.view().afterSuccessfulPhoto(BitmapFactory.decodeStream(response.body().byteStream()), uid);
loginPresenter.view().setProgressBar(false);
break;
case 404:
//user has no picture on back-end side
loginPresenter.view().setProgressBar(false);
loginPresenter.view().afterSuccessfulLogin();
break;
default:
break;
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// TODO: 17/04/17 what to do if request fails to get image?
/*
Service running "always" to check if there is internet connection
and update info of the current activity
*/
loginPresenter.view().setNoConnection(true);
Bundle extras = new Bundle();
extras.putString("access-token",osb.getString("access-token", null));
extras.putString("uid",osb.getString("uid", null));
extras.putString("client",osb.getString("client", null));
extras.putInt("id",osb.getInt("id", 0));
Job job = dispatcher.newJobBuilder()
.setService(ImageUpdateService.class)
.setTag(Utils.SERVICE_UPDATE_IMAGE)
//time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600
.setTrigger(Trigger.executionWindow(60, 3600))
//will be retried if it fails.
.setRecurring(true)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.setConstraints(
// only run on network
Constraint.ON_ANY_NETWORK
)
.setExtras(extras)
//if device is rebooted the job will be restarted
.setLifetime(Lifetime.FOREVER)
.build();
dispatcher.mustSchedule(job);
loginPresenter.view().setProgressBar(false);
loginPresenter.view().afterSuccessfulLogin();
}
});
......@@ -214,4 +264,6 @@ public class LoginPresenter extends BasePresenter<LoginView> {
}
}
}
\ No newline at end of file
package br.ufpr.c3sl.agendador.agendador.services;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.helpers.UserPhotoHelper;
import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints;
import br.ufpr.c3sl.agendador.agendador.network.ApiUtils;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by Lucas B. Cunha on 11/05/17.
*/
public class ImageUpdateService extends JobService {
/**
* The entry point to your Job. Implementations should offload work to another thread of
* execution as soon as possible.
*
* @param job
* @return whether there is more work remaining.
*/
@Override
public boolean onStartJob(final JobParameters job) {
Log.d("AGNDDR-ImgService", "Rodando " + ImageUpdateService.class.getName());
Bundle extras = job.getExtras();
Map<String, String> header = new HashMap<>();
final String uid = extras.getString("uid", null);
header.put("Content-Type", "application/json");
header.put("access-token", extras.getString("access-token", null));
header.put("client", extras.getString("client", null));
header.put("uid", uid);
ApiEndpoints service = ApiUtils.request(header);
Call<ResponseBody> listCall = service.requestPhoto(extras.getInt("id", 0), "large");
listCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int status = response.code();
switch (status) {
case 200:
UserPhotoHelper userPhotoHelper = new UserPhotoHelper(getBaseContext(), uid);
try {
userPhotoHelper.saveBitmap(BitmapFactory.decodeStream(response.body().byteStream()));
} catch (IOException e) {
Log.d("AGNDDR-ImgService", "Ocorreu um problema ao atualizar sua foto de perfil");
e.printStackTrace();
}
Log.d("AGNDDR-ImgService", "Job teve sucesso!!111!");
jobFinished(job, false);
break;
case 404:
//user has no picture on back-end side
jobFinished(job, false);
default:
Log.d("AGNDDR-ImgService", "Job Foi executado mas recebeu retorno " + status);
jobFinished(job, true);
break;
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("AGNDDR-ImgService", "Job fahlou e será remarcado!!");
jobFinished(job, true);
}
});
return true;
}
/**
* Called when the scheduling engine has decided to interrupt the execution of a running job,
* most likely because the runtime constraints associated with the job are no longer satisfied.
*
* @param job
* @return whether the job should be retried
*/
@Override
public boolean onStopJob(JobParameters job) {
return true;
}
}
......@@ -19,10 +19,18 @@ public interface AccountView {
void showPasswordWarning();
void setConnectionError(boolean enabled);
void setConnectionCepError(boolean enabled);
void setNoConnection(boolean enabled);
void cancelUpdate();
void setUpdated(boolean updated);
void enableButtonEdit(boolean enable);
void enableAllFields(boolean enable);
void setNoConnectionCep(boolean enabled);
void enableButtonSync(boolean enable);
}