Merge pull request #116 from Microsoft/removeServices

Replace Services with WorkManager
This commit is contained in:
Alex Crown 2019-04-05 15:14:04 -07:00 коммит произвёл GitHub
Родитель a507d791f1 885e5abea8
Коммит 0a0389d08a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
55 изменённых файлов: 826 добавлений и 1335 удалений

Просмотреть файл

@ -91,6 +91,11 @@ dependencies {
api 'com.squareup:otto:1.3.6'
api 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
api 'com.squareup.okhttp3:okhttp:3.1.2'
implementation ('androidx.work:work-runtime:2.0.0') {
// workaround for build issue regarding com.google.common.util.concurrent.ListenableFuture
//https://stackoverflow.com/questions/52467819/compile-errors-after-updating-to-workmanager-1-0-0-alpha09
exclude group: 'com.google.guava', module: 'listenablefuture'
}
api 'androidx.appcompat:appcompat:1.0.0'
api 'androidx.recyclerview:recyclerview:1.0.0'
api 'androidx.cardview:cardview:1.0.0'

Просмотреть файл

@ -6,9 +6,7 @@
package com.microsoft.embeddedsocial.account;
import com.facebook.login.LoginManager;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.actions.OngoingActions;
import com.microsoft.embeddedsocial.auth.MicrosoftLiveAuthenticator;
import com.microsoft.embeddedsocial.auth.SocialNetworkTokens;
import com.microsoft.embeddedsocial.autorest.models.FollowerStatus;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
@ -28,14 +26,23 @@ import com.microsoft.embeddedsocial.pending.PendingAction;
import com.microsoft.embeddedsocial.pending.PendingBlock;
import com.microsoft.embeddedsocial.pending.PendingFollow;
import com.microsoft.embeddedsocial.server.model.view.UserCompactView;
import com.microsoft.embeddedsocial.service.worker.SignInWorker;
import com.microsoft.embeddedsocial.service.worker.SignOutWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.util.NotificationCountChecker;
import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.webkit.CookieManager;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.Fragment;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.Operation;
import androidx.work.WorkManager;
/**
* Manages functionality related to user account.
@ -58,8 +65,13 @@ public class UserAccount {
/**
* Launches sign-in process via third party account.
*/
public Action signInUsingThirdParty(SocialNetworkAccount thirdPartyAccount) {
return ActionsLauncher.signInUsingThirdParty(context, thirdPartyAccount);
public Operation signInUsingThirdParty(SocialNetworkAccount thirdPartyAccount) {
Data inputData = new Data.Builder()
.putString(SignInWorker.SOCIAL_NETWORK_ACCOUNT,
WorkerHelper.serialize(thirdPartyAccount)).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SignInWorker.class)
.setInputData(inputData).addTag(SignInWorker.TAG).build();
return WorkManager.getInstance().enqueue(workRequest);
}
/**
@ -107,7 +119,7 @@ public class UserAccount {
* Whether sign-in is in progress now.
*/
public boolean isSigningIn() {
return OngoingActions.hasActionsWithTag(Action.Tags.SIGN_IN);
return WorkerHelper.isOngoing(SignInWorker.TAG);
}
/**
@ -128,7 +140,22 @@ public class UserAccount {
* Clears all the data associated with the current user (except the data in the database) and launch the request to the server to sign-out.
*/
public void signOut() {
ActionsLauncher.signOut(context, Preferences.getInstance().getAuthorizationToken());
Data inputData = new Data.Builder()
.putString(SignOutWorker.AUTHORIZATION, Preferences.getInstance().getAuthorizationToken())
.build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SignOutWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
signOutOfDevice();
}
/**
* Clears all the data associated with the current user (except the data in the database)
*/
public void signOutOfDevice() {
MicrosoftLiveAuthenticator.signOut(context);
clearCookies();
AccountDataStorage.clear(context);
Preferences.getInstance().setUserHandle(null);
Preferences.getInstance().setAuthorizationToken(null);
@ -141,6 +168,19 @@ public class UserAccount {
SocialNetworkTokens.clearAll();
}
/**
* Removes all cookies
*/
private void clearCookies() {
CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(null);
} else {
//noinspection deprecation
cookieManager.removeAllCookie();
}
}
/**
* Replaces the current user's account details.
*/

Просмотреть файл

@ -1,129 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.actions;
import java.util.concurrent.atomic.AtomicLong;
/**
* Some program's action (with progress visible in UI).
*/
public class Action {
/**
* Action tag constants.
*/
public static class Tags {
public static final String SIGN_IN = "signIn";
public static final String SIGN_OUT = "signOut";
public static final String CREATE_ACCOUNT = "createAccount";
public static final String UPDATE_ACCOUNT = "updateAccount";
public static final String DELETE_ACCOUNT = "deleteAccount";
public static final String GET_COMMENT = "getComment";
public static final String GET_REPLY = "getReply";
public static final String REMOVE_FOLLOWER = "removeFollower";
}
private static AtomicLong NEXT_ID = new AtomicLong();
private final long id = NEXT_ID.incrementAndGet();
private final String tag;
private boolean failed;
private String error;
/**
* Creates a new instance.
*
* @param tag string id of the action set this action belongs to; it can be used for action filtering
*/
Action(String tag) {
this.tag = tag;
}
/**
* Marks this action as running.
*/
public void start() {
OngoingActions.add(this);
}
/**
* Marks this action as completed successfully.
*/
public void complete() {
OngoingActions.notifyCompleted(this);
}
/**
* Marks this action as completed with an error.
* @param errorMessage error message
*/
public void fail(String errorMessage) {
failed = true;
error = errorMessage;
complete();
}
/**
* Marks this action as completed with an error (error message is empty).
*/
public void fail() {
fail(null);
}
/**
* Returns whether this action is completed (successfully or not).
*/
public boolean isCompleted() {
return OngoingActions.isCompleted(this);
}
/**
* Returns an error message (passed to {@link #fail(String)} method.
*/
public String getError() {
return error;
}
/**
* Returns whether this action failed.
*/
public boolean isFailed() {
return failed;
}
/**
* Returns the id of this action (unique among all actions). The action can be found by id via {@link OngoingActions#findActionById(Long)}
*/
public long getId() {
return id;
}
/**
* Returns action's tag.
*/
public String getTag() {
return tag;
}
// XXX: assume Action's are equal if their ids are equal
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Action action = (Action) o;
return id == action.id;
}
@Override
public int hashCode() {
return (int) (id);
}
}

Просмотреть файл

@ -1,18 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.actions;
/**
* Determines which actions are interesting for an application's component.
*/
public interface ActionFilter {
/**
* Whether the action is interesting for a component.
*/
boolean filter(Action action);
}

Просмотреть файл

@ -1,32 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.actions;
import java.util.Arrays;
import java.util.Collection;
/**
* Filters actions by tag.
*/
public class ActionTagFilter implements ActionFilter {
private final Collection<String> tags;
public ActionTagFilter(String... tags) {
this.tags = Arrays.asList(tags);
}
@Override
public boolean filter(Action action) {
String actionTag = action.getTag();
for (String tag : tags) {
if (actionTag.equals(tag)) {
return true;
}
}
return false;
}
}

Просмотреть файл

@ -1,139 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.actions;
import com.microsoft.embeddedsocial.data.model.AccountDataDifference;
import com.microsoft.embeddedsocial.data.model.CreateAccountData;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
import android.content.Context;
import android.os.Bundle;
/**
* Launches actions.
*/
public final class ActionsLauncher {
private ActionsLauncher() {
}
public static Action signInUsingThirdParty(Context context, SocialNetworkAccount thirdPartyAccount) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.SIGN_IN)
.setThirdPartyAccount(thirdPartyAccount)
.launch(context, ServiceAction.SIGN_IN);
}
public static Action getComment(Context context, String commentHandle) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.GET_COMMENT)
.setCommentHandle(commentHandle)
.launch(context, ServiceAction.GET_COMMENT);
}
public static Action getReply(Context context, String replyHandle) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.GET_REPLY)
.setReplyHandle(replyHandle)
.launch(context, ServiceAction.GET_REPLY);
}
public static Action signOut(Context context, String authorization) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.SIGN_OUT)
.setAuthorization(authorization)
.launch(context, ServiceAction.SIGN_OUT);
}
public static Action createAccount(Context context, CreateAccountData createAccountData) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.CREATE_ACCOUNT)
.setCreateAccountData(createAccountData)
.launch(context, ServiceAction.CREATE_ACCOUNT);
}
public static Action updateAccount(Context context, AccountDataDifference difference) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.UPDATE_ACCOUNT)
.setAccountDataDifference(difference)
.launch(context, ServiceAction.UPDATE_ACCOUNT);
}
public static Action deleteAccount(Context context) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.DELETE_ACCOUNT).launch(context, ServiceAction.DELETE_ACCOUNT);
}
public static Action removeFollower(Context context, String userHandle) {
return ActionIntentBuilder.forActionWithTag(Action.Tags.REMOVE_FOLLOWER)
.setUserHandle(userHandle)
.launch(context, ServiceAction.REMOVE_FOLLOWER);
}
private static Action createAndStartAction(String tag) {
Action action = new Action(tag);
action.start();
return action;
}
/**
* Builds a service intent and sends it.
*/
private static final class ActionIntentBuilder {
private final Bundle extras = new Bundle();
private final Action action;
private ActionIntentBuilder(Action action) {
this.action = action;
extras.putLong(IntentExtras.ACTION_ID, action.getId());
}
ActionIntentBuilder setAuthorization(String authorization) {
extras.putString(IntentExtras.AUTHORIZATION, authorization);
return this;
}
ActionIntentBuilder setThirdPartyAccount(SocialNetworkAccount thirdPartyAccount) {
extras.putParcelable(IntentExtras.THIRD_PARTY_ACCOUNT, thirdPartyAccount);
return this;
}
ActionIntentBuilder setUserHandle(String userHandle) {
extras.putString(IntentExtras.USER_HANDLE, userHandle);
return this;
}
ActionIntentBuilder setCreateAccountData(CreateAccountData createAccountData) {
extras.putParcelable(IntentExtras.CREATE_ACCOUNT_DATA, createAccountData);
return this;
}
ActionIntentBuilder setAccountDataDifference(AccountDataDifference difference) {
extras.putParcelable(IntentExtras.ACCOUNT_DATA_DIFFERENCE, difference);
return this;
}
ActionIntentBuilder setCommentHandle(String commentHandle) {
extras.putString(IntentExtras.COMMENT_HANDLE, commentHandle);
return this;
}
ActionIntentBuilder setReplyHandle(String replyHandle) {
extras.putString(IntentExtras.REPLY_HANDLE, replyHandle);
return this;
}
Action launch(Context context, ServiceAction serviceAction) {
WorkerService.getLauncher(context).launchService(serviceAction, extras);
return action;
}
static ActionIntentBuilder forActionWithTag(String tag) {
Action action = createAndStartAction(tag);
return new ActionIntentBuilder(action);
}
}
}

Просмотреть файл

@ -1,96 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.actions;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.event.action.ActionCompletedEvent;
import com.microsoft.embeddedsocial.event.action.ActionStartedEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Holds information about currently running actions and their errors.
*/
public final class OngoingActions {
private static final Map<Long, Action> ACTIONS = new HashMap<>();
private static final Map<Action, Boolean> COMPLETED_ACTIONS = new WeakHashMap<>();
private OngoingActions() {
}
/**
* Finds a currently running (i.e. started and not completed) action by it's id
*
* @param id action's id
*/
public static Action findActionById(Long id) {
synchronized (OngoingActions.class) {
return ACTIONS.get(id);
}
}
/**
* Returns whether there is a running action satisfying the filter.
* @param filter action filter
*/
public static boolean hasActions(ActionFilter filter) {
synchronized (OngoingActions.class) {
for (Action action : ACTIONS.values()) {
if (filter.filter(action)) {
return true;
}
}
}
return false;
}
/**
* Returns whether there is a running action with such tag.
*/
public static boolean hasActionsWithTag(String tag) {
return hasActions(new ActionTagFilter(tag));
}
/**
* Register the action as running.
*/
static void add(Action action) {
synchronized (OngoingActions.class) {
if (ACTIONS.containsKey(action.getId())) {
throw new RuntimeException("Action has been already started");
}
ACTIONS.put(action.getId(), action);
}
EventBus.post(new ActionStartedEvent(action));
}
/**
* returns whether the action is already completed.
*/
static boolean isCompleted(Action action) {
synchronized (OngoingActions.class) {
return COMPLETED_ACTIONS.containsKey(action);
}
}
/**
* Marks the action as completed.
*/
static void notifyCompleted(Action action) {
synchronized (OngoingActions.class) {
if (!ACTIONS.containsKey(action.getId())) {
throw new RuntimeException("Action has been already completed");
}
ACTIONS.remove(action.getId());
COMPLETED_ACTIONS.put(action, Boolean.TRUE);
}
EventBus.post(new ActionCompletedEvent(action));
}
}

Просмотреть файл

@ -7,16 +7,19 @@ package com.microsoft.embeddedsocial.data.model;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Encapsulates changes in account data. Used to track changes during account editing.
*/
public final class AccountDataDifference implements android.os.Parcelable {
public final class AccountDataDifference implements Parcelable, Serializable {
private boolean photoUriChanged = false;
private boolean coverUriChanged = false;
private Uri photoUri;
private Uri coverUri;
private String photoUri;
private String coverUri;
private boolean publicInfoChanged = false;
private String firstName;
@ -32,8 +35,8 @@ public final class AccountDataDifference implements android.os.Parcelable {
private AccountDataDifference(Parcel in) {
this.photoUriChanged = in.readByte() != 0;
this.coverUriChanged = in.readByte() != 0;
this.photoUri = in.readParcelable(Uri.class.getClassLoader());
this.coverUri = in.readParcelable(Uri.class.getClassLoader());
this.photoUri = in.readString();
this.coverUri = in.readString();
this.publicInfoChanged = in.readByte() != 0;
this.firstName = in.readString();
this.lastName = in.readString();
@ -54,12 +57,12 @@ public final class AccountDataDifference implements android.os.Parcelable {
* @param newPhotoUri local Uri to the new photo (may be null)
*/
public void setNewPhoto(Uri newPhotoUri) {
photoUri = newPhotoUri;
photoUri = newPhotoUri == null ? null : newPhotoUri.toString();
photoUriChanged = true;
}
public void setNewCover(Uri newCoverUri) {
coverUri = newCoverUri;
coverUri = newCoverUri == null ? null : newCoverUri.toString();
coverUriChanged = true;
}
@ -98,11 +101,19 @@ public final class AccountDataDifference implements android.os.Parcelable {
}
public Uri getPhotoUri() {
return photoUri;
if (photoUri == null) {
return null;
}
return Uri.parse(photoUri);
}
public Uri getCoverUri() {
return coverUri;
if (coverUri == null) {
return null;
}
return Uri.parse(coverUri);
}
/**
@ -142,8 +153,8 @@ public final class AccountDataDifference implements android.os.Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte(photoUriChanged ? (byte) 1 : (byte) 0);
dest.writeByte(coverUriChanged ? (byte) 1 : (byte) 0);
dest.writeParcelable(this.photoUri, 0);
dest.writeParcelable(this.coverUri, 0);
dest.writeString(this.photoUri);
dest.writeString(this.coverUri);
dest.writeByte(publicInfoChanged ? (byte) 1 : (byte) 0);
dest.writeString(this.firstName);
dest.writeString(this.lastName);

Просмотреть файл

@ -11,14 +11,18 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Information needed to create an account.
*/
public class CreateAccountData implements Parcelable {
public class CreateAccountData implements Parcelable, Serializable {
private static final long serialVersionUID = 6172725706417779546L;
private String firstName;
private String lastName;
private String bio;
private Uri photoUri;
private String photoUri;
private IdentityProvider identityProvider;
private String thirdPartyAccessToken;
private String thirdPartyRequestToken;
@ -50,11 +54,19 @@ public class CreateAccountData implements Parcelable {
}
public Uri getPhotoUri() {
return photoUri;
if (photoUri == null) {
return null;
}
return Uri.parse(photoUri);
}
public void setPhotoUri(Uri photoUri) {
this.photoUri = photoUri;
if (photoUri == null) {
this.photoUri = null;
} else {
this.photoUri = photoUri.toString();
}
}
public IdentityProvider getIdentityProvider() {
@ -90,7 +102,7 @@ public class CreateAccountData implements Parcelable {
this.firstName = in.readString();
this.lastName = in.readString();
this.bio = in.readString();
this.photoUri = in.readParcelable(Uri.class.getClassLoader());
this.photoUri = in.readString();
this.identityProvider = IdentityProvider.fromValue(in.readString());
this.thirdPartyAccessToken = in.readString();
this.thirdPartyRequestToken = in.readString();
@ -101,7 +113,7 @@ public class CreateAccountData implements Parcelable {
dest.writeString(this.firstName);
dest.writeString(this.lastName);
dest.writeString(this.bio);
dest.writeParcelable(this.photoUri, 0);
dest.writeString(this.photoUri);
dest.writeString(this.identityProvider.toValue());
dest.writeString(this.thirdPartyAccessToken);
dest.writeString(this.thirdPartyRequestToken);

Просмотреть файл

@ -17,14 +17,15 @@ import com.microsoft.embeddedsocial.server.model.notification.RegisterPushNotifi
import com.microsoft.embeddedsocial.server.model.notification.UnRegisterPushNotificationRequest;
import com.microsoft.embeddedsocial.server.model.notification.UpdateNotificationStatusRequest;
import com.microsoft.embeddedsocial.server.model.view.ActivityView;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.SynchronizationWorker;
import android.content.Context;
import android.text.TextUtils;
import java.sql.SQLException;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import retrofit2.Response;
/**
@ -143,6 +144,7 @@ public class NotificationServiceCachingWrapper implements INotificationService {
}
private void launchSync() {
WorkerService.getLauncher(context).launchService(ServiceAction.SYNC_DATA);
OneTimeWorkRequest backgroundInit = new OneTimeWorkRequest.Builder(SynchronizationWorker.class).build();
WorkManager.getInstance().enqueue(backgroundInit);
}
}

Просмотреть файл

@ -30,13 +30,15 @@ import com.microsoft.embeddedsocial.sdk.BuildConfig;
import com.microsoft.embeddedsocial.server.model.view.CommentView;
import com.microsoft.embeddedsocial.server.model.view.ReplyView;
import com.microsoft.embeddedsocial.server.model.view.TopicView;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.SynchronizationWorker;
import android.content.Context;
import java.sql.SQLException;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Is used as a facade class allowing to perform user actions such as likes/pins/etc.
*/
@ -77,7 +79,8 @@ public class UserActionProxy {
}
private void launchSync() {
WorkerService.getLauncher(context).launchService(ServiceAction.SYNC_DATA);
OneTimeWorkRequest backgroundInit = new OneTimeWorkRequest.Builder(SynchronizationWorker.class).build();
WorkManager.getInstance().enqueue(backgroundInit);
}
/**

Просмотреть файл

@ -1,22 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.event.action;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.event.HandlingThread;
import com.microsoft.embeddedsocial.base.event.ThreadType;
/**
* Action was completed event.
*/
@HandlingThread(ThreadType.MAIN)
public class ActionCompletedEvent extends ActionEvent {
public ActionCompletedEvent(Action action) {
super(action);
}
}

Просмотреть файл

@ -1,26 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.event.action;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.event.AbstractEvent;
/**
* Base event class for actions.
*/
abstract class ActionEvent extends AbstractEvent {
private final Action action;
ActionEvent(Action action) {
this.action = action;
}
public Action getAction() {
return action;
}
}

Просмотреть файл

@ -1,23 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.event.action;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.event.HandlingThread;
import com.microsoft.embeddedsocial.base.event.ThreadType;
/**
* Action started event.
*/
@HandlingThread(ThreadType.MAIN)
public class ActionStartedEvent extends ActionEvent {
public ActionStartedEvent(Action action) {
super(action);
}
}

Просмотреть файл

@ -25,8 +25,7 @@ import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.NetworkAvailability;
import com.microsoft.embeddedsocial.server.RequestInfoProvider;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.BackgroundInitializationWorker;
import com.microsoft.embeddedsocial.telemetry.Telemetry;
import com.microsoft.embeddedsocial.ui.activity.ActivityFeedActivity;
import com.microsoft.embeddedsocial.ui.activity.AddPostActivity;
@ -62,6 +61,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Embedded Social SDK facade.
@ -102,7 +103,8 @@ public final class EmbeddedSocial {
options.verify();
GlobalObjectRegistry.addObject(options);
initGlobalObjects(application, options);
WorkerService.getLauncher(application).launchService(ServiceAction.BACKGROUND_INIT);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(BackgroundInitializationWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
if (telemetryToken != null) {
options.setTelemetryToken(telemetryToken);
Telemetry.setAnalyticsSolution(application, telemetryToken);

Просмотреть файл

@ -8,6 +8,10 @@ package com.microsoft.embeddedsocial.service;
import com.google.firebase.iid.FirebaseInstanceIdService;
import com.microsoft.embeddedsocial.fcm.FcmTokenHolder;
import com.microsoft.embeddedsocial.service.worker.GetFcmIdWorker;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Listens to InstanceID API callbacks.
@ -17,6 +21,7 @@ public class FcmInstanceIdListenerService extends FirebaseInstanceIdService {
public void onTokenRefresh() {
super.onTokenRefresh();
FcmTokenHolder.create(this).resetToken();
WorkerService.getLauncher(this).launchService(ServiceAction.FCM_REGISTER);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetFcmIdWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
}
}

Просмотреть файл

@ -1,62 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service;
import com.microsoft.embeddedsocial.base.service.IServiceIntentProcessor;
import com.microsoft.embeddedsocial.base.service.IntentProcessor;
import com.microsoft.embeddedsocial.service.handler.BackgroundInitializationHandler;
import com.microsoft.embeddedsocial.service.handler.CreateAccountHandler;
import com.microsoft.embeddedsocial.service.handler.DeleteAccountHandler;
import com.microsoft.embeddedsocial.service.handler.DeleteSearchHistoryHandler;
import com.microsoft.embeddedsocial.service.handler.GetCommentHandler;
import com.microsoft.embeddedsocial.service.handler.GetFcmIdHandler;
import com.microsoft.embeddedsocial.service.handler.GetReplyHandler;
import com.microsoft.embeddedsocial.service.handler.LinkUserThirdPartyAccountHandler;
import com.microsoft.embeddedsocial.service.handler.RemoveFollowerHandler;
import com.microsoft.embeddedsocial.service.handler.SignInHandler;
import com.microsoft.embeddedsocial.service.handler.SignOutHandler;
import com.microsoft.embeddedsocial.service.handler.SynchronizationHandler;
import com.microsoft.embeddedsocial.service.handler.UnlinkUserThirdPartyAccountHandler;
import com.microsoft.embeddedsocial.service.handler.UpdateAccountHandler;
import com.microsoft.embeddedsocial.service.handler.UpdateNotificationCountHandler;
import android.content.Context;
/**
* Builds intents processor.
*/
public class IntentProcessorFactory {
private static final int WORKER_THREADS = 2;
private final Context context;
IntentProcessorFactory(Context context) {
this.context = context;
}
IServiceIntentProcessor createIntentProcessor() {
IntentProcessor<ServiceAction> processor = new IntentProcessor<>(context, ServiceAction.class, WORKER_THREADS);
processor.registerIntentHandler(ServiceAction.SIGN_IN, new SignInHandler(context));
processor.registerIntentHandler(ServiceAction.SIGN_OUT, new SignOutHandler(context));
processor.registerIntentHandler(ServiceAction.SYNC_DATA, new SynchronizationHandler(context));
processor.registerIntentHandler(ServiceAction.CREATE_ACCOUNT, new CreateAccountHandler(context));
processor.registerIntentHandler(ServiceAction.UPDATE_ACCOUNT, new UpdateAccountHandler(context));
processor.registerIntentHandler(ServiceAction.FCM_REGISTER, new GetFcmIdHandler(context));
processor.registerIntentHandler(ServiceAction.BACKGROUND_INIT, new BackgroundInitializationHandler(context));
processor.registerIntentHandler(ServiceAction.UPDATE_NOTIFICATION_COUNT, new UpdateNotificationCountHandler());
processor.registerIntentHandler(ServiceAction.GET_COMMENT, new GetCommentHandler());
processor.registerIntentHandler(ServiceAction.GET_REPLY, new GetReplyHandler());
processor.registerIntentHandler(ServiceAction.DELETE_SEARCH_HISTORY, new DeleteSearchHistoryHandler());
processor.registerIntentHandler(ServiceAction.DELETE_ACCOUNT, new DeleteAccountHandler());
processor.registerIntentHandler(ServiceAction.LINK_USER_THIRD_PARTY_ACCOUNT, new LinkUserThirdPartyAccountHandler());
processor.registerIntentHandler(ServiceAction.UNLINK_USER_THIRD_PARTY_ACCOUNT, new UnlinkUserThirdPartyAccountHandler());
processor.registerIntentHandler(ServiceAction.REMOVE_FOLLOWER, new RemoveFollowerHandler());
return processor;
}
}

Просмотреть файл

@ -1,42 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service;
/**
* Service actions.
*/
public enum ServiceAction {
BACKGROUND_INIT,
DELETE_ACCOUNT,
DELETE_SEARCH_HISTORY,
FCM_REGISTER,
GET_COMMENT,
GET_REPLY,
SIGN_IN,
SIGN_OUT,
SYNC_DATA,
CREATE_ACCOUNT,
UPDATE_ACCOUNT,
UPDATE_NOTIFICATION_COUNT,
LINK_USER_THIRD_PARTY_ACCOUNT,
UNLINK_USER_THIRD_PARTY_ACCOUNT,
REMOVE_FOLLOWER,
}

Просмотреть файл

@ -1,29 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service;
import com.microsoft.embeddedsocial.base.service.AbstractProcessingService;
import com.microsoft.embeddedsocial.base.service.IServiceIntentProcessor;
import com.microsoft.embeddedsocial.base.service.ServiceLauncher;
import android.content.Context;
/**
* Worker service.
*/
public class WorkerService extends AbstractProcessingService {
IntentProcessorFactory factory = new IntentProcessorFactory(this);
@Override
protected IServiceIntentProcessor createIntentProcessor() {
return factory.createIntentProcessor();
}
public static ServiceLauncher<ServiceAction> getLauncher(Context context) {
return new ServiceLauncher<>(context, WorkerService.class);
}
}

Просмотреть файл

@ -1,45 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.OngoingActions;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
/**
* Base class for {@link IServiceIntentHandler} implementation dealing with {@link Action}.
*/
public abstract class ActionHandler implements IServiceIntentHandler<ServiceAction> {
@Override
public final void handleIntent(ServiceAction serviceAction, Intent intent) {
long actionId = intent.getLongExtra(IntentExtras.ACTION_ID, -1);
Action action = OngoingActions.findActionById(actionId);
if (action == null) {
DebugLog.e("Action is null");
return;
}
try {
handleAction(action, serviceAction, intent);
} finally {
if (!action.isCompleted()) {
action.complete();
}
}
}
protected abstract void handleAction(Action action, ServiceAction serviceAction, Intent intent);
@Override
public void dispose() {
}
}

Просмотреть файл

@ -1,30 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import android.content.Context;
import android.content.Intent;
public class BackgroundInitializationHandler implements IServiceIntentHandler<ServiceAction> {
private final Context context;
public BackgroundInitializationHandler(Context context) {
this.context = context;
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
WorkerService.getLauncher(context).launchService(ServiceAction.FCM_REGISTER);
}
@Override
public void dispose() { }
}

Просмотреть файл

@ -1,112 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.data.model.AccountData;
import com.microsoft.embeddedsocial.data.model.AccountDataDifference;
import com.microsoft.embeddedsocial.data.model.CreateAccountData;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAccountService;
import com.microsoft.embeddedsocial.server.IAuthenticationService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.UserRequest;
import com.microsoft.embeddedsocial.server.model.account.CreateUserRequest;
import com.microsoft.embeddedsocial.server.model.account.GetUserAccountRequest;
import com.microsoft.embeddedsocial.server.model.account.GetUserAccountResponse;
import com.microsoft.embeddedsocial.server.model.auth.AuthenticationResponse;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import java.io.IOException;
/**
* Sends a create account request to the server.
*/
public class CreateAccountHandler extends ActionHandler {
private final IAccountService accountService = GlobalObjectRegistry
.getObject(EmbeddedSocialServiceProvider.class)
.getAccountService();
private final IAuthenticationService authenticationService = GlobalObjectRegistry
.getObject(EmbeddedSocialServiceProvider.class)
.getAuthenticationService();
private final Context context;
public CreateAccountHandler(Context context) {
this.context = context;
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
Bundle extras = intent.getExtras();
CreateAccountData createAccountData = extras.getParcelable(IntentExtras.CREATE_ACCOUNT_DATA);
CreateUserRequest createUserRequest = new CreateUserRequest.Builder()
.setFirstName(createAccountData.getFirstName())
.setLastName(createAccountData.getLastName())
.setBio(createAccountData.getBio())
.setIdentityProvider(createAccountData.getIdentityProvider())
.setAccessToken(createAccountData.getThirdPartyAccessToken())
.setRequestToken(createAccountData.getThirdPartyRequestToken())
.build();
try {
AuthenticationResponse createUserResponse = accountService.createUser(createUserRequest);
handleSuccessfulResult(action, createUserResponse);
uploadPhoto(createAccountData.getPhotoUri());
} catch (IOException | NetworkRequestException e) {
DebugLog.logException(e);
UserAccount.getInstance().onCreateUserFailed();
action.fail();
}
}
private void handleSuccessfulResult(Action action, AuthenticationResponse response)
throws NetworkRequestException {
String userHandle = response.getUserHandle();
String sessionToken = UserRequest.createSessionAuthorization(response.getSessionToken());
GetUserAccountRequest getUserRequest = new GetUserAccountRequest(sessionToken);
GetUserAccountResponse userAccount = accountService.getUserAccount(getUserRequest);
AccountData accountData = AccountData.fromServerResponse(userAccount.getUser());
if (!action.isCompleted()) {
int messageId = R.string.es_msg_general_create_user_success;
UserAccount.getInstance().onSignedIn(userHandle, sessionToken, accountData, messageId);
WorkerService.getLauncher(context).launchService(ServiceAction.FCM_REGISTER);
}
}
/**
* Uploads the profile photo
*/
private void uploadPhoto(Uri photoUri) throws IOException, NetworkRequestException {
// TODO this is a separate call which could fail and leave the wrong public access
if (photoUri != null) {
AccountDataDifference difference = new AccountDataDifference();
difference.setNewPhoto(photoUri);
ActionsLauncher.updateAccount(context, difference);
}
}
@Override
public void dispose() {
}
}

Просмотреть файл

@ -1,27 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.data.storage.SearchHistory;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
/**
* Deletes the search history.
*/
public class DeleteSearchHistoryHandler implements IServiceIntentHandler<ServiceAction> {
@Override
public void handleIntent(ServiceAction action, Intent intent) {
new SearchHistory().clear();
}
@Override
public void dispose() {
}
}

Просмотреть файл

@ -1,59 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.auth.MicrosoftLiveAuthenticator;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAuthenticationService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.auth.SignOutRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.webkit.CookieManager;
/**
* Performs sign-out.
*/
public class SignOutHandler extends ActionHandler {
private final Context context;
public SignOutHandler(Context context) {
this.context = context;
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
String authorization = intent.getStringExtra(IntentExtras.AUTHORIZATION);
IAuthenticationService server = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAuthenticationService();
try {
SignOutRequest request = new SignOutRequest(authorization);
server.signOut(request);
} catch (NetworkRequestException e) {
// ignore server errors
DebugLog.logException(e);
}
MicrosoftLiveAuthenticator.signOut(context);
clearCookies();
}
private void clearCookies() {
CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(null);
} else {
//noinspection deprecation
cookieManager.removeAllCookie();
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.worker;
import android.content.Context;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Initializes the SDK for use
*/
public class BackgroundInitializationWorker extends Worker {
public BackgroundInitializationWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
public Result doWork() {
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetFcmIdWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
return Result.success();
}
}

Просмотреть файл

@ -0,0 +1,109 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.data.model.AccountData;
import com.microsoft.embeddedsocial.data.model.AccountDataDifference;
import com.microsoft.embeddedsocial.data.model.CreateAccountData;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAccountService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.UserRequest;
import com.microsoft.embeddedsocial.server.model.account.CreateUserRequest;
import com.microsoft.embeddedsocial.server.model.account.GetUserAccountRequest;
import com.microsoft.embeddedsocial.server.model.account.GetUserAccountResponse;
import com.microsoft.embeddedsocial.server.model.auth.AuthenticationResponse;
import android.content.Context;
import android.net.Uri;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends a create account request to the server and updates the account's profile image if necessary
*/
public class CreateAccountWorker extends Worker {
public static final String CREATE_ACCOUNT_DATA = "createAccountData";
public static final String TAG = "createAccountWorker";
private final IAccountService accountService = GlobalObjectRegistry
.getObject(EmbeddedSocialServiceProvider.class)
.getAccountService();
public CreateAccountWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
public Result doWork() {
String serializedAccountData = getInputData().getString(CREATE_ACCOUNT_DATA);
CreateAccountData createAccountData = WorkerHelper.deserialize(serializedAccountData);
if (serializedAccountData == null) {
UserAccount.getInstance().onCreateUserFailed();
return Result.failure();
}
try {
CreateUserRequest createUserRequest = new CreateUserRequest.Builder()
.setFirstName(createAccountData.getFirstName())
.setLastName(createAccountData.getLastName())
.setBio(createAccountData.getBio())
.setIdentityProvider(createAccountData.getIdentityProvider())
.setAccessToken(createAccountData.getThirdPartyAccessToken())
.setRequestToken(createAccountData.getThirdPartyRequestToken())
.build();
AuthenticationResponse createUserResponse = accountService.createUser(createUserRequest);
handleSuccessfulResult(createUserResponse);
uploadPhoto(createAccountData.getPhotoUri());
} catch (NetworkRequestException e) {
DebugLog.logException(e);
UserAccount.getInstance().onCreateUserFailed();
return Result.failure();
}
return Result.success();
}
private void handleSuccessfulResult(AuthenticationResponse response) throws NetworkRequestException {
String userHandle = response.getUserHandle();
String sessionToken = UserRequest.createSessionAuthorization(response.getSessionToken());
GetUserAccountRequest getUserRequest = new GetUserAccountRequest(sessionToken);
GetUserAccountResponse userAccount = accountService.getUserAccount(getUserRequest);
AccountData accountData = AccountData.fromServerResponse(userAccount.getUser());
int messageId = R.string.es_msg_general_create_user_success;
UserAccount.getInstance().onSignedIn(userHandle, sessionToken, accountData, messageId);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetFcmIdWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
}
/**
* Uploads the profile photo
*/
private void uploadPhoto(Uri photoUri) {
// TODO this is a separate call which could fail and leave the wrong public access
if (photoUri != null) {
AccountDataDifference difference = new AccountDataDifference();
difference.setNewPhoto(photoUri);
Data inputData = new Data.Builder()
.putString(UpdateAccountWorker.ACCOUNT_DATA_DIFFERENCE,
WorkerHelper.serialize(difference)).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UpdateAccountWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
}

Просмотреть файл

@ -3,34 +3,42 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAccountService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.account.DeleteUserRequest;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends a delete account request to the server.
* Sends a delete account request to the server
*/
public class DeleteAccountHandler extends ActionHandler {
public class DeleteAccountWorker extends Worker {
public static String TAG = "deleteAccountWorker";
public DeleteAccountWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
public Result doWork() {
IAccountService server = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAccountService();
try {
server.deleteUser(new DeleteUserRequest());
UserAccount.getInstance().signOut();
action.complete();
UserAccount.getInstance().signOutOfDevice();
} catch (NetworkRequestException e) {
DebugLog.logException(e);
action.fail();
return Result.failure();
}
return Result.success();
}
}

Просмотреть файл

@ -0,0 +1,28 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.data.storage.SearchHistory;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Deletes search history from the device
*/
public class DeleteSearchHistoryWorker extends Worker {
public DeleteSearchHistoryWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
public Result doWork() {
new SearchHistory().clear();
return Result.success();
}
}

Просмотреть файл

@ -3,9 +3,8 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
@ -15,21 +14,28 @@ import com.microsoft.embeddedsocial.server.IContentService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.content.comments.GetCommentRequest;
import com.microsoft.embeddedsocial.server.model.content.comments.GetCommentResponse;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Get single comment.
* Fetches a comment from the server
*/
public class GetCommentHandler extends ActionHandler {
public class GetCommentWorker extends Worker {
public static final String COMMENT_HANDLE = "commentHandle";
public GetCommentWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
public Result doWork() {
IContentService contentService
= GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getContentService();
final String commentHandle = intent.getExtras().getString(IntentExtras.COMMENT_HANDLE);
final String commentHandle = getInputData().getString(COMMENT_HANDLE);
try {
final GetCommentRequest request = new GetCommentRequest(commentHandle);
@ -37,8 +43,10 @@ public class GetCommentHandler extends ActionHandler {
EventBus.post(new GetCommentEvent(response.getComment(), response.getComment() != null));
} catch (NetworkRequestException e) {
DebugLog.logException(e);
action.fail(e.getMessage());
EventBus.post(new GetCommentEvent(null, false));
return Result.failure();
}
return Result.success();
}
}

Просмотреть файл

@ -3,39 +3,39 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.fcm.FcmTokenHolder;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Registers the app with Firebase Cloud Messaging framework.
* Gets FCM tokens and stores them
*/
public class GetFcmIdHandler implements IServiceIntentHandler<ServiceAction> {
public class GetFcmIdWorker extends Worker {
private final Context context;
private final FcmTokenHolder tokenHolder;
public GetFcmIdHandler(Context context) {
public GetFcmIdWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
this.context = context;
this.tokenHolder = FcmTokenHolder.create(context);
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
public Result doWork() {
if (!tokenHolder.hasValidToken()) {
DebugLog.i("obtaining new FCM token");
FirebaseInstanceId instanceId = FirebaseInstanceId.getInstance();
@ -45,7 +45,8 @@ public class GetFcmIdHandler implements IServiceIntentHandler<ServiceAction> {
FcmTokenHolder.create(context).storeToken(instanceIdResult.getToken());
DebugLog.i("FCM token obtained successfully");
WorkerService.getLauncher(context).launchService(ServiceAction.SYNC_DATA);
OneTimeWorkRequest backgroundInit = new OneTimeWorkRequest.Builder(SynchronizationWorker.class).build();
WorkManager.getInstance().enqueue(backgroundInit);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
@ -54,9 +55,7 @@ public class GetFcmIdHandler implements IServiceIntentHandler<ServiceAction> {
}
});
}
}
@Override
public void dispose() {
return Result.success();
}
}

Просмотреть файл

@ -3,9 +3,8 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
@ -15,21 +14,28 @@ import com.microsoft.embeddedsocial.server.IContentService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.content.replies.GetReplyRequest;
import com.microsoft.embeddedsocial.server.model.content.replies.GetReplyResponse;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Get single reply.
* Fetches a reply from the server
*/
public class GetReplyHandler extends ActionHandler {
public class GetReplyWorker extends Worker {
public static final String REPLY_HANDLE = "replyHandle";
public GetReplyWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
public Result doWork() {
IContentService contentService
= GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getContentService();
final String replyHandle = intent.getExtras().getString(IntentExtras.REPLY_HANDLE);
final String replyHandle = getInputData().getString(REPLY_HANDLE);
try {
final GetReplyRequest request = new GetReplyRequest(replyHandle);
@ -37,8 +43,10 @@ public class GetReplyHandler extends ActionHandler {
EventBus.post(new GetReplyEvent(response.getReply(), response.getReply() != null));
} catch (NetworkRequestException e) {
DebugLog.logException(e);
action.fail(e.getMessage());
EventBus.post(new GetReplyEvent(null, false));
return Result.failure();
}
return Result.success();
}
}

Просмотреть файл

@ -1,13 +1,7 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.event.LinkUserThirdPartyAccountEvent;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
@ -15,34 +9,41 @@ import com.microsoft.embeddedsocial.server.IAccountService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.exception.StatusException;
import com.microsoft.embeddedsocial.server.model.account.LinkThirdPartyRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends a link user third party account request to the server.
*/
public class LinkUserThirdPartyAccountHandler implements IServiceIntentHandler<ServiceAction> {
public class LinkUserThirdPartyAccountWorker extends Worker {
public static final String SOCIAL_NETWORK_ACCOUNT = "socialNetworkAccount";
public LinkUserThirdPartyAccountWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
final SocialNetworkAccount account = intent.getExtras().getParcelable(IntentExtras.SOCIAL_NETWORK_ACCOUNT);
public Result doWork() {
final SocialNetworkAccount account = WorkerHelper.deserialize(getInputData().getString(SOCIAL_NETWORK_ACCOUNT));
IAccountService service = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAccountService();
LinkThirdPartyRequest linkUserThirdPartyAccountRequest = new LinkThirdPartyRequest(
account.getAccountType(),
account.getThirdPartyAccessToken());
intent.removeExtra(IntentExtras.SOCIAL_NETWORK_ACCOUNT);
account.clearTokens();
try {
service.linkUserThirdPartyAccount(linkUserThirdPartyAccountRequest);
EventBus.post(LinkUserThirdPartyAccountEvent.createLinkEvent(account));
return Result.success();
} catch (NetworkRequestException e) {
DebugLog.logException(e);
LinkUserThirdPartyAccountEvent event;
// Notify the handler that the request failed
if (e instanceof StatusException) {
event = LinkUserThirdPartyAccountEvent.createLinkEvent(account, e.getMessage(),
((StatusException)e).getStatusCode());
@ -50,11 +51,7 @@ public class LinkUserThirdPartyAccountHandler implements IServiceIntentHandler<S
event = LinkUserThirdPartyAccountEvent.createLinkEvent(account, e.getMessage());
}
EventBus.post(event);
return Result.failure();
}
}
@Override
public void dispose() {
}
}

Просмотреть файл

@ -3,48 +3,45 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IRelationshipService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.relationship.RemoveFollowerRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.os.Bundle;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends a remove follower request to the server.
* Sends remove follower requests to the server
*/
public class RemoveFollowerHandler extends ActionHandler {
public class RemoveFollowerWorker extends Worker {
public static final String USER_HANDLE = "userHandle";
private final IRelationshipService relationshipService = GlobalObjectRegistry
.getObject(EmbeddedSocialServiceProvider.class)
.getRelationshipService();
public RemoveFollowerHandler() { }
public RemoveFollowerWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
Bundle extras = intent.getExtras();
String userHandle = extras.getString(IntentExtras.USER_HANDLE);
public Result doWork() {
String userHandle = getInputData().getString(USER_HANDLE);
RemoveFollowerRequest removeFollowerRequest = new RemoveFollowerRequest(userHandle);
try {
relationshipService.removeFollower(removeFollowerRequest);
} catch (NetworkRequestException e) {
DebugLog.logException(e);
action.fail();
return Result.failure();
}
}
@Override
public void dispose() {
return Result.success();
}
}

Просмотреть файл

@ -3,10 +3,9 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.data.model.AccountData;
@ -24,8 +23,6 @@ import com.microsoft.embeddedsocial.server.model.account.GetUserProfileResponse;
import com.microsoft.embeddedsocial.server.model.auth.AuthenticationResponse;
import com.microsoft.embeddedsocial.server.model.auth.CreateSessionRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.ui.activity.CreateProfileActivity;
import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
@ -33,10 +30,19 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends sign-in requests.
* Sends sign in requests. Launches the create user page if necessary.
*/
public class SignInHandler extends ActionHandler {
public class SignInWorker extends Worker {
public static final String SOCIAL_NETWORK_ACCOUNT = "thirdPartyAccount";
public static final String TAG = "signInWorker";
private final Context context;
private final IAccountService accountService = GlobalObjectRegistry
.getObject(EmbeddedSocialServiceProvider.class)
@ -46,53 +52,57 @@ public class SignInHandler extends ActionHandler {
.getObject(EmbeddedSocialServiceProvider.class)
.getAuthenticationService();
private final Context context;
public SignInHandler(Context context) {
public SignInWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
this.context = context;
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
signinWithThirdParty(action, intent.getParcelableExtra(IntentExtras.THIRD_PARTY_ACCOUNT));
intent.removeExtra(IntentExtras.SOCIAL_NETWORK_ACCOUNT);
}
public Result doWork() {
String serializedNetworkAccount = getInputData().getString(SOCIAL_NETWORK_ACCOUNT);
SocialNetworkAccount socialNetworkAccount = WorkerHelper.deserialize(serializedNetworkAccount);
if (serializedNetworkAccount == null) {
UserAccount.getInstance().onSignInWithThirdPartyFailed();
return Result.failure();
}
private void signinWithThirdParty(Action action, SocialNetworkAccount thirdPartyAccount) {
CreateSessionRequest signInWithThirdPartyRequest = new CreateSessionRequest(
thirdPartyAccount.getAccountType(),
thirdPartyAccount.getThirdPartyAccessToken(),
thirdPartyAccount.getThirdPartyRequestToken());
String authorization = signInWithThirdPartyRequest.getAuthorization();
GetMyProfileRequest getMyProfileRequest = new GetMyProfileRequest(authorization);
socialNetworkAccount.getAccountType(),
socialNetworkAccount.getThirdPartyAccessToken(),
socialNetworkAccount.getThirdPartyRequestToken());
try {
String authorization = signInWithThirdPartyRequest.getAuthorization();
GetMyProfileRequest getMyProfileRequest = new GetMyProfileRequest(authorization);
// Determine the user's user handle
GetUserProfileResponse getUserProfileResponse = getMyProfileRequest.send();
// set the user handle and attempt sign in
signInWithThirdPartyRequest.setRequestUserHandle(getUserProfileResponse.getUser().getHandle());
AuthenticationResponse signInResponse = authenticationService.signInWithThirdParty(signInWithThirdPartyRequest);
handleSuccessfulResult(action, signInResponse);
handleSuccessfulResult(signInResponse);
} catch (NotFoundException e) {
// User handle not found; create an account
Intent i = new Intent(context, CreateProfileActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle extras = new Bundle();
extras.putParcelable(IntentExtras.THIRD_PARTY_ACCOUNT, thirdPartyAccount);
extras.putParcelable(IntentExtras.THIRD_PARTY_ACCOUNT, socialNetworkAccount);
i.putExtras(extras);
context.startActivity(i);
} catch (Exception e) {
} catch (NetworkRequestException e) {
DebugLog.logException(e);
UserAccount.getInstance().onSignInWithThirdPartyFailed();
return Result.failure();
} finally {
thirdPartyAccount.clearTokens();
socialNetworkAccount.clearTokens();
}
return Result.success();
}
private void handleSuccessfulResult(Action action, AuthenticationResponse response)
private void handleSuccessfulResult(AuthenticationResponse response)
throws NetworkRequestException {
String userHandle = response.getUserHandle();
@ -100,15 +110,9 @@ public class SignInHandler extends ActionHandler {
GetUserAccountRequest getUserRequest = new GetUserAccountRequest(sessionToken);
GetUserAccountResponse userAccount = accountService.getUserAccount(getUserRequest);
AccountData accountData = AccountData.fromServerResponse(userAccount.getUser());
if (!action.isCompleted()) {
int messageId = R.string.es_msg_general_signin_success;
UserAccount.getInstance().onSignedIn(userHandle, sessionToken, accountData, messageId);
WorkerService.getLauncher(context).launchService(ServiceAction.FCM_REGISTER);
}
}
@Override
public void dispose() {
int messageId = R.string.es_msg_general_signin_success;
UserAccount.getInstance().onSignedIn(userHandle, sessionToken, accountData, messageId);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetFcmIdWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
}
}

Просмотреть файл

@ -0,0 +1,47 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAuthenticationService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.auth.SignOutRequest;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Performs the sign out operation
*/
public class SignOutWorker extends Worker {
public static final String AUTHORIZATION = "authorization";
Context context;
public SignOutWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
this.context = context;
}
@Override
public Result doWork() {
String authorization = getInputData().getString(AUTHORIZATION);
IAuthenticationService server = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAuthenticationService();
try {
SignOutRequest request = new SignOutRequest(authorization);
server.signOut(request);
} catch (NetworkRequestException e) {
// ignore server errors
DebugLog.logException(e);
}
return Result.success();
}
}

Просмотреть файл

@ -3,9 +3,8 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.data.storage.ActivityCache;
import com.microsoft.embeddedsocial.data.storage.PostStorage;
@ -13,24 +12,21 @@ import com.microsoft.embeddedsocial.data.storage.UserActionCache;
import com.microsoft.embeddedsocial.data.storage.UserCache;
import com.microsoft.embeddedsocial.fcm.FcmTokenHolder;
import com.microsoft.embeddedsocial.server.sync.DataSynchronizer;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Context;
import android.content.Intent;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Uploads all available data to the server.
* Synchronizes local data with the server
*/
public class SynchronizationHandler implements IServiceIntentHandler<ServiceAction> {
public class SynchronizationWorker extends Worker {
public static final String PENDING_POST_SYNC_NAME = "posts";
private final DataSynchronizer synchronizer = new DataSynchronizer();
/**
* Creates an instance.
*/
public SynchronizationHandler(Context context) {
public SynchronizationWorker(Context context, WorkerParameters workerParameters) {
super(context, workerParameters);
UserActionCache userActionCache = new UserActionCache();
PostStorage postStorage = new PostStorage(context);
synchronizer.registerSyncProducer(postStorage::getPendingPosts, PENDING_POST_SYNC_NAME);
@ -40,26 +36,25 @@ public class SynchronizationHandler implements IServiceIntentHandler<ServiceActi
synchronizer.registerSyncProducer(userActionCache::getPendingPinActions, "pins");
synchronizer.registerSyncProducer(userActionCache::getPendingHideTopicActions, "hidden topics");
synchronizer.registerSyncProducer(userActionCache::getPendingReportContentActions,
"reported content");
"reported content");
synchronizer.registerSyncProducer(new ActivityCache(context)::getActivityHandleSyncActions,
"notification updates");
"notification updates");
synchronizer.registerSyncProducer(new UserCache()::getPendingUserRelationOperations,
"user relations");
"user relations");
synchronizer.registerSyncProducer(userActionCache::getPendingContentRemovalActions,
"removals");
"removals");
synchronizer.registerSyncProducer(FcmTokenHolder.create(context)::getTokenSyncOperations,
"fcm");
"fcm");
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
public Result doWork() {
// currently this should be synchronized in app scope
synchronized (SynchronizationHandler.class) {
synchronized (SynchronizationWorker.class) {
boolean synced = synchronizer.synchronize();
DebugLog.i(synced ? "sync succeeded" : "sync failed");
}
}
@Override
public void dispose() { }
return Result.success();
}
}

Просмотреть файл

@ -3,30 +3,37 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.autorest.models.IdentityProvider;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.event.LinkUserThirdPartyAccountEvent;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.IAccountService;
import com.microsoft.embeddedsocial.server.exception.StatusException;
import com.microsoft.embeddedsocial.server.model.account.UnlinkUserThirdPartyAccountRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Sends a unlink user third party account request to the server.
* Sends an unlink user third party account request to the server.
*/
public class UnlinkUserThirdPartyAccountHandler implements IServiceIntentHandler<ServiceAction> {
public class UnlinkUserThirdPartyAccountWorker extends Worker {
public static final String IDENTITY_PROVIDER = "identityProvider";
public UnlinkUserThirdPartyAccountWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
final IdentityProvider accountType = IdentityProvider.fromValue(intent.getExtras().getString(IntentExtras.IDENTITY_PROVIDER));
public Result doWork() {
final IdentityProvider accountType =
IdentityProvider.fromValue(getInputData().getString(IDENTITY_PROVIDER));
IAccountService accountService = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAccountService();
UnlinkUserThirdPartyAccountRequest unlinkUserThirdPartyAccountRequest
@ -35,21 +42,20 @@ public class UnlinkUserThirdPartyAccountHandler implements IServiceIntentHandler
try {
accountService.unlinkUserThirdPartyAccount(unlinkUserThirdPartyAccountRequest);
EventBus.post(LinkUserThirdPartyAccountEvent.createUnlinkEvent(accountType));
return Result.success();
} catch (Exception e) {
DebugLog.logException(e);
LinkUserThirdPartyAccountEvent event;
// Notify the handler that the request failed
if (e instanceof StatusException) {
event = LinkUserThirdPartyAccountEvent.createUnlinkEvent(accountType, e.getMessage(),
((StatusException)e).getStatusCode());
((StatusException) e).getStatusCode());
} else {
event = LinkUserThirdPartyAccountEvent.createUnlinkEvent(accountType, e.getMessage());
}
EventBus.post(event);
return Result.failure();
}
}
@Override
public void dispose() {
}
}

Просмотреть файл

@ -3,10 +3,9 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.autorest.models.ImageType;
import com.microsoft.embeddedsocial.autorest.models.Visibility;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
@ -20,43 +19,45 @@ import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.account.UpdateUserPhotoRequest;
import com.microsoft.embeddedsocial.server.model.account.UpdateUserPublicAccountInfoRequest;
import com.microsoft.embeddedsocial.server.model.account.UpdateUserVisibilityRequest;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import java.io.IOException;
/**
* Updates account.
*/
public class UpdateAccountHandler extends ActionHandler {
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class UpdateAccountWorker extends Worker {
public static final String ACCOUNT_DATA_DIFFERENCE = "accountDataDifference";
public static final String TAG = "updateAccountWorker";
private final Context context;
private final IAccountService server = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getAccountService();
public UpdateAccountHandler(Context context) {
public UpdateAccountWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
this.context = context;
}
@Override
protected void handleAction(Action action, ServiceAction serviceAction, Intent intent) {
Bundle extras = intent.getExtras();
AccountDataDifference difference = extras.getParcelable(IntentExtras.ACCOUNT_DATA_DIFFERENCE);
public Result doWork() {
String serializedData = getInputData().getString(ACCOUNT_DATA_DIFFERENCE);
AccountDataDifference difference = WorkerHelper.deserialize(serializedData);
AccountData accountData = UserAccount.getInstance().getAccountDetails();
try {
updatePhotoIfNeeded(difference, accountData);
updatePublicInfoIfNeeded(difference, accountData);
updatePrivacyIfNeeded(difference, accountData);
} catch (IOException | NetworkRequestException e) {
DebugLog.logException(e);
action.fail();
return Result.failure();
} finally {
UserAccount.getInstance().updateAccountDetails(accountData);
}
return Result.success();
}
private void updatePrivacyIfNeeded(AccountDataDifference difference, AccountData accountData) throws NetworkRequestException {
@ -70,9 +71,9 @@ public class UpdateAccountHandler extends ActionHandler {
private void updatePublicInfoIfNeeded(AccountDataDifference difference, AccountData accountData) throws NetworkRequestException {
if (difference.isPublicInfoChanged()) {
server.updateUserPublicAccountInfo(new UpdateUserPublicAccountInfoRequest(
difference.getFirstName(),
difference.getLastName(),
difference.getBio()));
difference.getFirstName(),
difference.getLastName(),
difference.getBio()));
accountData.setFirstName(difference.getFirstName());
accountData.setLastName(difference.getLastName());
accountData.setBio(difference.getBio());
@ -87,5 +88,4 @@ public class UpdateAccountHandler extends ActionHandler {
accountData.setUserPhotoUrl(photoUrl);
}
}
}

Просмотреть файл

@ -3,27 +3,32 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.handler;
package com.microsoft.embeddedsocial.service.worker;
import com.microsoft.embeddedsocial.autorest.models.CountResponse;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.service.IServiceIntentHandler;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.data.Preferences;
import com.microsoft.embeddedsocial.server.EmbeddedSocialServiceProvider;
import com.microsoft.embeddedsocial.server.INotificationService;
import com.microsoft.embeddedsocial.server.exception.NetworkRequestException;
import com.microsoft.embeddedsocial.server.model.notification.GetNotificationCountRequest;
import com.microsoft.embeddedsocial.service.ServiceAction;
import android.content.Intent;
import android.content.Context;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Updates notification count from the server.
*/
public class UpdateNotificationCountHandler implements IServiceIntentHandler<ServiceAction> {
public class UpdateNotificationCountWorker extends Worker {
public UpdateNotificationCountWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
}
@Override
public void handleIntent(ServiceAction action, Intent intent) {
public Result doWork() {
INotificationService server = GlobalObjectRegistry.getObject(EmbeddedSocialServiceProvider.class).getNotificationService();
try {
CountResponse response = server.getNotificationCount(new GetNotificationCountRequest());
@ -31,11 +36,9 @@ public class UpdateNotificationCountHandler implements IServiceIntentHandler<Ser
Preferences.getInstance().setNotificationCount(notificationCount);
} catch (NetworkRequestException e) {
DebugLog.logException(e);
return Result.failure();
}
}
@Override
public void dispose() {
return Result.success();
}
}

Просмотреть файл

@ -0,0 +1,129 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.service.worker;
import com.google.common.util.concurrent.ListenableFuture;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import android.util.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import static androidx.work.WorkInfo.State.CANCELLED;
import static androidx.work.WorkInfo.State.FAILED;
import static androidx.work.WorkInfo.State.SUCCEEDED;
/**
* Implements utility functions to aid in setting up and handling androidx
*/
public class WorkerHelper {
/**
* Serialize the given Object to a String
* @param data data to serialize
* @return String containing the serialized data
*/
public static String serialize(Serializable data) {
String serializedData = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(data);
serializedData = Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT);
os.close();
} catch (IOException e) {
DebugLog.logException(e);
}
return serializedData;
}
/**
* Deserialize the given string to an object
* @param serializedData data to deserialize
* @param <DataType> type to cast the data
* @return deserialized object
*/
public static <DataType> DataType deserialize(String serializedData) {
if (serializedData == null) {
return null;
}
DataType data = null;
InputStream inputStream = new ByteArrayInputStream(Base64.decode(serializedData, Base64.DEFAULT));
try {
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
data = (DataType)objectInputStream.readObject();
} catch (ClassNotFoundException|IOException e) {
DebugLog.logException(e);
}
return data;
}
/**
* Determines if any workers matching the given tag are enqueued or running
* @param tag Tag to match with active workers
* @return true if any workers matching the tag are enqueued or running; false otherwise
*/
public static boolean isOngoing(String tag) {
ListenableFuture<List<WorkInfo>> workInfoListenableFutureList =
WorkManager.getInstance().getWorkInfosByTag(tag);
try {
List<WorkInfo> workInfoList = workInfoListenableFutureList.get();
boolean running = false;
for (WorkInfo workInfo : workInfoList) {
running = running || !workInfo.getState().isFinished();
}
return running;
} catch (InterruptedException|ExecutionException e) {
return false;
}
}
/**
* Handle the result of a completed work request
* @param lifecycleOwner the lifecycle owner used to observe the work request
* @param workerId ID of the work request
* @param handler ResultHandler to invoke upon work completion
*/
public static void handleResult(LifecycleOwner lifecycleOwner, UUID workerId, ResultHandler handler) {
LiveData<WorkInfo> liveData = WorkManager.getInstance().getWorkInfoByIdLiveData(workerId);
liveData.observe(lifecycleOwner, workInfo -> {
WorkInfo.State state = workInfo.getState();
if (state.isFinished()) {
if (state.equals(SUCCEEDED)) {
handler.onSuccess();
} else if (state.equals(FAILED) || state.equals(CANCELLED)) {
handler.onFailure();
}
}
});
}
/**
* Defines functions to run upon success or failure of a single work request
*/
public interface ResultHandler {
void onSuccess();
void onFailure();
}
}

Просмотреть файл

@ -6,18 +6,22 @@
package com.microsoft.embeddedsocial.ui.adapter.renderer;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.autorest.models.FollowerStatus;
import com.microsoft.embeddedsocial.data.model.AccountData;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.model.view.UserCompactView;
import com.microsoft.embeddedsocial.service.worker.RemoveFollowerWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.adapter.viewholder.UserListItemHolder;
import android.view.View;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Renders my followers with context menu.
@ -46,14 +50,25 @@ public class MyFollowersRenderer extends UserRenderer {
button.setVisibility(View.VISIBLE);
button.setEnabled(true);
button.setOnClickListener(v -> {
Action action = ActionsLauncher.removeFollower(context, otherUser.getHandle());
if (!action.isFailed()) {
// redraw the button
button.setText(R.string.es_removed_follower);
getStyleHelper().applyRedCompletedStyle(button);
// decrement local followers count
currUser.setFollowersCount(Math.max(0, currUser.getFollowersCount() - 1));
}
Data inputData = new Data.Builder()
.putString(RemoveFollowerWorker.USER_HANDLE, otherUser.getHandle()).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(RemoveFollowerWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
WorkerHelper.handleResult(ProcessLifecycleOwner.get(), workRequest.getId(), new WorkerHelper.ResultHandler() {
@Override
public void onSuccess() {
// redraw the button
button.setText(R.string.es_removed_follower);
getStyleHelper().applyRedCompletedStyle(button);
// decrement local followers count
currUser.setFollowersCount(Math.max(0, currUser.getFollowersCount() - 1));
}
@Override
public void onFailure() { }
});
});
button.setText(R.string.es_remove_follower);
getStyleHelper().applyRedStyle(button);

Просмотреть файл

@ -11,8 +11,7 @@ import com.microsoft.embeddedsocial.base.utils.ObjectUtils;
import com.microsoft.embeddedsocial.data.storage.PostStorage;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.SynchronizationWorker;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseEditPostFragment;
import com.microsoft.embeddedsocial.ui.fragment.module.PhotoProviderModule;
import com.microsoft.embeddedsocial.ui.util.FitWidthSizeSpec;
@ -28,6 +27,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment for adding a new post.
@ -140,7 +141,8 @@ public class AddPostFragment extends BaseEditPostFragment implements OnClickList
@Override
protected void onFinishedEditing() {
postStorage.storePost(getTitle(), getDescription(), imageUri, PublisherType.USER);
WorkerService.getLauncher(getContext()).launchService(ServiceAction.SYNC_DATA);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SynchronizationWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
finishActivity();
}

Просмотреть файл

@ -6,9 +6,6 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.actions.OngoingActions;
import com.microsoft.embeddedsocial.base.utils.BitmapUtils;
import com.microsoft.embeddedsocial.base.utils.ViewUtils;
import com.microsoft.embeddedsocial.data.model.AccountData;
@ -22,6 +19,8 @@ import com.microsoft.embeddedsocial.image.ImageViewContentLoader;
import com.microsoft.embeddedsocial.image.UserPhotoLoader;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.worker.CreateAccountWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseFragmentWithProgress;
import com.microsoft.embeddedsocial.ui.fragment.module.PhotoProviderModule;
import com.microsoft.embeddedsocial.ui.theme.ThemeAttributes;
@ -43,6 +42,9 @@ import java.util.LinkedList;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment to create profile.
@ -125,7 +127,15 @@ public class CreateProfileFragment extends BaseFragmentWithProgress {
.build();
thirdPartyAccount.clearTokens();
ActionsLauncher.createAccount(getContext(), createAccountData);
Data inputData = new Data.Builder()
.putString(CreateAccountWorker.CREATE_ACCOUNT_DATA,
WorkerHelper.serialize(createAccountData)).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(CreateAccountWorker.class)
.setInputData(inputData)
.addTag(CreateAccountWorker.TAG)
.build();
WorkManager.getInstance().enqueue(workRequest);
}
}
@ -231,7 +241,7 @@ public class CreateProfileFragment extends BaseFragmentWithProgress {
@Override
public boolean onBackPressed() {
hideKeyboard();
if (OngoingActions.hasActionsWithTag(Action.Tags.UPDATE_ACCOUNT)) {
if (WorkerHelper.isOngoing(CreateAccountWorker.TAG)) {
showToast(R.string.es_message_wait_until_account_created);
return false;
}

Просмотреть файл

@ -5,49 +5,23 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionTagFilter;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.actions.OngoingActions;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.ui.fragment.base.ActionListener;
import com.microsoft.embeddedsocial.service.worker.DeleteAccountWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseFragmentWithProgress;
import android.os.Bundle;
import android.view.View;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment for deleting an account.
*/
public class DeleteAccountFragment extends BaseFragmentWithProgress {
public DeleteAccountFragment() {
addActionListener(new ActionTagFilter(Action.Tags.DELETE_ACCOUNT), new ActionListener() {
@Override
protected void onActionSucceeded(Action action) {
onAccountDeleted();
}
@Override
protected void onActionFailed(Action action, String error) {
onError();
}
@Override
protected void onActionsCompletionMissed(List<Action> completedActions, List<Action> succeededActions, List<Action> failedActions) {
if (!succeededActions.isEmpty()) {
onAccountDeleted();
} else if (!failedActions.isEmpty()) {
onError();
}
}
});
}
@Override
protected int getContentLayoutId() {
return R.layout.es_fragment_delete_account;
@ -59,14 +33,28 @@ public class DeleteAccountFragment extends BaseFragmentWithProgress {
setOnClickListener(view, R.id.es_cancelButton, v -> finishActivity());
setOnClickListener(view, R.id.es_deleteButton, v -> {
setProgressVisible(true);
ActionsLauncher.deleteAccount(v.getContext());
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(DeleteAccountWorker.class)
.addTag(DeleteAccountWorker.TAG)
.build();
WorkManager.getInstance().enqueue(workRequest);
WorkerHelper.handleResult(this, workRequest.getId(), new WorkerHelper.ResultHandler() {
@Override
public void onSuccess() {
getActivity().runOnUiThread(() -> onAccountDeleted());
}
@Override
public void onFailure() {
getActivity().runOnUiThread(() -> onError());
}
});
});
}
@Override
public void onResume() {
super.onResume();
setProgressVisible(OngoingActions.hasActionsWithTag(Action.Tags.DELETE_ACCOUNT));
setProgressVisible(WorkerHelper.isOngoing(DeleteAccountWorker.TAG));
}
private void onAccountDeleted() {

Просмотреть файл

@ -5,7 +5,6 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.event.content.CommentRemovedEvent;
import com.microsoft.embeddedsocial.event.content.GetCommentEvent;
@ -14,6 +13,7 @@ import com.microsoft.embeddedsocial.fetcher.base.ViewStateListener;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.model.view.CommentView;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.worker.GetCommentWorker;
import com.microsoft.embeddedsocial.ui.activity.TopicActivity;
import com.microsoft.embeddedsocial.ui.adapter.viewholder.CommentButtonListener;
import com.microsoft.embeddedsocial.ui.adapter.viewholder.CommentViewHolder;
@ -28,6 +28,9 @@ import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment to display single comment.
@ -62,7 +65,14 @@ public class DisplayCommentFragment extends BaseFragment implements ViewStateLis
initView(view);
final String commentHandle = arguments.getString(IntentExtras.COMMENT_HANDLE);
ActionsLauncher.getComment(getActivity(), commentHandle);
Data inputData = new Data.Builder()
.putString(GetCommentWorker.COMMENT_HANDLE, commentHandle)
.build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetCommentWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
displayLoadView();
}

Просмотреть файл

@ -5,13 +5,13 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.base.utils.debug.DebugLog;
import com.microsoft.embeddedsocial.event.content.GetReplyEvent;
import com.microsoft.embeddedsocial.event.content.ReplyRemovedEvent;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.model.view.ReplyView;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.worker.GetReplyWorker;
import com.microsoft.embeddedsocial.ui.activity.DisplayNoteActivity;
import com.microsoft.embeddedsocial.ui.adapter.viewholder.ReplyButtonListener;
import com.microsoft.embeddedsocial.ui.adapter.viewholder.ReplyViewHolder;
@ -26,6 +26,9 @@ import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment to display single reply.
@ -60,7 +63,14 @@ public class DisplayReplyFragment extends BaseFragment {
initView(view);
final String replyHandle = arguments.getString(IntentExtras.REPLY_HANDLE);
ActionsLauncher.getReply(getActivity(), replyHandle);
Data inputData = new Data.Builder()
.putString(GetReplyWorker.REPLY_HANDLE, replyHandle)
.build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(GetReplyWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
displayLoadView();
}

Просмотреть файл

@ -6,10 +6,6 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionTagFilter;
import com.microsoft.embeddedsocial.actions.ActionsLauncher;
import com.microsoft.embeddedsocial.actions.OngoingActions;
import com.microsoft.embeddedsocial.base.GlobalObjectRegistry;
import com.microsoft.embeddedsocial.base.utils.BitmapUtils;
import com.microsoft.embeddedsocial.base.utils.ObjectUtils;
@ -23,7 +19,8 @@ import com.microsoft.embeddedsocial.image.ImageViewContentLoader;
import com.microsoft.embeddedsocial.image.UserPhotoLoader;
import com.microsoft.embeddedsocial.sdk.Options;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.ui.fragment.base.ActionListener;
import com.microsoft.embeddedsocial.service.worker.UpdateAccountWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseFragmentWithProgress;
import com.microsoft.embeddedsocial.ui.fragment.module.PhotoProviderModule;
import com.microsoft.embeddedsocial.ui.theme.ThemeAttributes;
@ -46,6 +43,9 @@ import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Fragment to edit profile.
@ -82,26 +82,6 @@ public class EditProfileFragment extends BaseFragmentWithProgress {
photoProvider = new PhotoProviderModule(this, new SelectProfilePhotoConsumer());
addModule(photoProvider);
addActionListener(new ActionTagFilter(Action.Tags.UPDATE_ACCOUNT), new ActionListener() {
@Override
protected void onActionFailed(Action action, String error) {
onUpdateFailed();
}
@Override
protected void onActionSucceeded(Action action) {
onUpdateSucceeded();
}
@Override
protected void onActionsCompletionMissed(List<Action> completedActions, List<Action> succeededActions, List<Action> failedActions) {
if (!succeededActions.isEmpty()) {
onUpdateSucceeded();
} else if (!failedActions.isEmpty()) {
onUpdateFailed();
}
}
});
}
@Override
@ -146,7 +126,27 @@ public class EditProfileFragment extends BaseFragmentWithProgress {
finishActivity();
} else {
setProgressVisible(true);
ActionsLauncher.updateAccount(getContext(), difference);
Data inputData = new Data.Builder()
.putString(UpdateAccountWorker.ACCOUNT_DATA_DIFFERENCE,
WorkerHelper.serialize(difference)).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UpdateAccountWorker.class)
.setInputData(inputData)
.addTag(UpdateAccountWorker.TAG)
.build();
WorkManager.getInstance().enqueue(workRequest);
WorkerHelper.handleResult(this, workRequest.getId(), new WorkerHelper.ResultHandler() {
@Override
public void onSuccess() {
getActivity().runOnUiThread(() -> onUpdateSucceeded());
}
@Override
public void onFailure() {
getActivity().runOnUiThread(() -> onUpdateFailed());
}
});
}
}
}
@ -279,7 +279,7 @@ public class EditProfileFragment extends BaseFragmentWithProgress {
@Override
public boolean onBackPressed() {
hideKeyboard();
if (OngoingActions.hasActionsWithTag(Action.Tags.UPDATE_ACCOUNT)) {
if (WorkerHelper.isOngoing(UpdateAccountWorker.TAG)) {
showToast(R.string.es_message_wait_until_account_updated);
return false;
}

Просмотреть файл

@ -21,9 +21,9 @@ import com.microsoft.embeddedsocial.sdk.Options;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.server.exception.ConflictException;
import com.microsoft.embeddedsocial.server.model.view.ThirdPartyAccountView;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.LinkUserThirdPartyAccountWorker;
import com.microsoft.embeddedsocial.service.worker.UnlinkUserThirdPartyAccountWorker;
import com.microsoft.embeddedsocial.service.worker.WorkerHelper;
import com.microsoft.embeddedsocial.ui.adapter.LinkedAccountsAdapter;
import com.microsoft.embeddedsocial.ui.dialog.AlertDialogFragment;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseListContentFragment;
@ -31,12 +31,15 @@ import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
import com.squareup.otto.Subscribe;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Screen with linked accounts state.
*/
@ -103,9 +106,12 @@ public class LinkedAccountsFragment extends BaseListContentFragment<LinkedAccoun
.show(getActivity(), null);
getAdapter().notifyDataSetChanged();
} else {
Bundle extras = new Bundle();
extras.putString(IntentExtras.IDENTITY_PROVIDER, identityProvider.toValue());
WorkerService.getLauncher(getContext()).launchService(ServiceAction.UNLINK_USER_THIRD_PARTY_ACCOUNT, extras);
Data inputData = new Data.Builder()
.putString(UnlinkUserThirdPartyAccountWorker.IDENTITY_PROVIDER,
identityProvider.toValue()).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UnlinkUserThirdPartyAccountWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
@ -131,9 +137,13 @@ public class LinkedAccountsFragment extends BaseListContentFragment<LinkedAccoun
public void onAuthenticationSuccess(SocialNetworkAccount account) {
ThreadUtils.runOnMainThread(() -> {
onAuthenticationCompleted();
Bundle extras = new Bundle();
extras.putParcelable(IntentExtras.SOCIAL_NETWORK_ACCOUNT, account);
WorkerService.getLauncher(getContext()).launchService(ServiceAction.LINK_USER_THIRD_PARTY_ACCOUNT, extras);
Data inputData = new Data.Builder()
.putString(LinkUserThirdPartyAccountWorker.SOCIAL_NETWORK_ACCOUNT,
WorkerHelper.serialize(account)).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(LinkUserThirdPartyAccountWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
});
}

Просмотреть файл

@ -76,7 +76,7 @@ public class NavigationFragment extends BaseFragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
notificationCountChecker = new NotificationCountChecker(getContext());
notificationCountChecker = new NotificationCountChecker();
activeItemId = getArguments().getInt(CURRENT_ITEM_EXTRA);
isShowProfile = getArguments().getBoolean(SHOW_PROFILE_EXTRA);
}

Просмотреть файл

@ -14,8 +14,7 @@ import com.microsoft.embeddedsocial.data.storage.DatabaseHelper;
import com.microsoft.embeddedsocial.sdk.Options;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.service.IntentExtras;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.DeleteSearchHistoryWorker;
import com.microsoft.embeddedsocial.ui.activity.DeleteAccountActivity;
import com.microsoft.embeddedsocial.ui.activity.FriendlistActivity;
import com.microsoft.embeddedsocial.ui.activity.LinkedAccountsActivity;
@ -34,6 +33,8 @@ import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Settings fragment.
@ -123,7 +124,8 @@ public class OptionsFragment extends BaseFragment {
}
private void deleteSearchHistory() {
WorkerService.getLauncher(getContext()).launchService(ServiceAction.DELETE_SEARCH_HISTORY);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(DeleteSearchHistoryWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
showToast(R.string.es_msg_general_search_history_deleted);
}
}

Просмотреть файл

@ -6,7 +6,6 @@
package com.microsoft.embeddedsocial.ui.fragment;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.auth.AbstractAuthenticator;
import com.microsoft.embeddedsocial.auth.FacebookAuthenticator;
import com.microsoft.embeddedsocial.auth.GoogleAppAuthAuthenticator;
@ -20,6 +19,7 @@ import com.microsoft.embeddedsocial.event.signin.SignInWithThirdPartyFailedEvent
import com.microsoft.embeddedsocial.event.signin.UserSignedInEvent;
import com.microsoft.embeddedsocial.sdk.Options;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.service.worker.SignInWorker;
import com.microsoft.embeddedsocial.ui.fragment.base.BaseFragment;
import com.microsoft.embeddedsocial.ui.fragment.module.SlowConnectionMessageModule;
import com.microsoft.embeddedsocial.ui.util.SocialNetworkAccount;
@ -40,6 +40,8 @@ import android.widget.Toast;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.work.Operation;
import androidx.work.WorkManager;
/**
* Sign-in fragment.
@ -53,14 +55,14 @@ public class SignInFragment extends BaseFragment implements IAuthenticationCallb
private AbstractAuthenticator authenticator;
private boolean isGettingThirdPartyCredentials;
private Action signInAction;
private Operation signInOperation;
private final SlowConnectionMessageModule slowConnectionMessageModule = new SlowConnectionMessageModule(
this,
R.string.es_cancel,
SIGN_IN_TIMEOUT,
() -> {
if (signInAction != null) {
signInAction.fail();
if (signInOperation != null && !signInOperation.getResult().isDone()) {
WorkManager.getInstance().cancelAllWorkByTag(SignInWorker.TAG);
setProgressVisible(false);
}
}
@ -239,7 +241,7 @@ public class SignInFragment extends BaseFragment implements IAuthenticationCallb
clearAuthenticator();
ThreadUtils.runOnMainThread(() -> {
onSignInStarted();
signInAction = UserAccount.getInstance().signInUsingThirdParty(account);
signInOperation = UserAccount.getInstance().signInUsingThirdParty(account);
});
}

Просмотреть файл

@ -1,76 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*/
package com.microsoft.embeddedsocial.ui.fragment.base;
import com.microsoft.embeddedsocial.actions.Action;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* Listens for actions state.
*/
@SuppressWarnings("UnusedParameters")
public abstract class ActionListener {
private List<Action> ongoingActions = new LinkedList<>();
protected void onActionStarted(Action action) {
}
protected void onActionCompleted(Action action) {
}
protected void onActionSucceeded(Action action) {
}
protected void onActionFailed(Action action, String error) {
}
protected void onActionsCompletionMissed(List<Action> completedActions, List<Action> succeededActions, List<Action> failedActions) {
}
void notifyActionStarted(Action action) {
ongoingActions.add(action);
onActionStarted(action);
}
void notifyActionCompleted(Action action) {
ongoingActions.remove(action);
if (action.isFailed()) {
onActionFailed(action, action.getError());
} else {
onActionSucceeded(action);
}
onActionCompleted(action);
}
void notifyOnResume() {
if (!ongoingActions.isEmpty()) {
List<Action> completedActions = new ArrayList<>();
List<Action> succeededActions = new ArrayList<>();
List<Action> failedActions = new ArrayList<>();
Iterator<Action> iterator = ongoingActions.iterator();
while (iterator.hasNext()) {
Action action = iterator.next();
if (action.isCompleted()) {
completedActions.add(action);
if (action.isFailed()) {
failedActions.add(action);
} else {
succeededActions.add(action);
}
iterator.remove();
}
}
if (!completedActions.isEmpty()) {
onActionsCompletionMissed(completedActions, succeededActions, failedActions);
}
}
}
}

Просмотреть файл

@ -5,12 +5,8 @@
package com.microsoft.embeddedsocial.ui.fragment.base;
import com.microsoft.embeddedsocial.actions.Action;
import com.microsoft.embeddedsocial.actions.ActionFilter;
import com.microsoft.embeddedsocial.base.event.EventBus;
import com.microsoft.embeddedsocial.base.utils.ViewUtils;
import com.microsoft.embeddedsocial.event.action.ActionCompletedEvent;
import com.microsoft.embeddedsocial.event.action.ActionStartedEvent;
import com.microsoft.embeddedsocial.sdk.BuildConfig;
import com.microsoft.embeddedsocial.sdk.R;
import com.microsoft.embeddedsocial.telemetry.Event;
@ -18,13 +14,11 @@ import com.microsoft.embeddedsocial.telemetry.Telemetry;
import com.microsoft.embeddedsocial.ui.activity.PopularActivity;
import com.microsoft.embeddedsocial.ui.activity.base.BaseActivity;
import com.microsoft.embeddedsocial.ui.util.CommonBehaviorEventListener;
import com.squareup.otto.Subscribe;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
@ -55,43 +49,13 @@ public abstract class BaseFragment extends Fragment {
private final List<Module> modules = new LinkedList<>();
private final List<Pair<ActionFilter, ActionListener>> actionListeners = new LinkedList<>();
private final List<Object> eventListeners = new LinkedList<>();
@SuppressWarnings("FieldCanBeLocal")
private final Object actionEventListener = new Object() {
@Subscribe
public void onActionStartedEvent(ActionStartedEvent event) {
Action action = event.getAction();
for (Pair<ActionFilter, ActionListener> pair : actionListeners) {
ActionFilter actionFilter = pair.first;
if (actionFilter.filter(action)) {
ActionListener actionListener = pair.second;
actionListener.notifyActionStarted(action);
}
}
}
@Subscribe
public void onActionCompletedEvent(ActionCompletedEvent event) {
Action action = event.getAction();
for (Pair<ActionFilter, ActionListener> pair : actionListeners) {
ActionFilter actionFilter = pair.first;
if (actionFilter.filter(action)) {
ActionListener actionListener = pair.second;
actionListener.notifyActionCompleted(action);
}
}
}
};
protected BaseFragment() {
addThemeToMerge(R.style.EmbeddedSocialSdkThemeOverlayBaseFragment);
setRetainInstance(true);
eventListeners.add(this);
eventListeners.add(actionEventListener);
if (Telemetry.isTelemetryEnabled()) {
Event fragmentCreate = Telemetry.newEvent("FragmentCreate");
@ -114,10 +78,6 @@ public abstract class BaseFragment extends Fragment {
modules.add(module);
}
protected void addActionListener(ActionFilter filter, ActionListener listener) {
actionListeners.add(new Pair<>(filter, listener));
}
/**
* Adds an event listener. Call it only from constructor (or at least before onResume)
*/
@ -249,9 +209,6 @@ public abstract class BaseFragment extends Fragment {
for (Module module : modules) {
module.onResume();
}
for (Pair<ActionFilter, ActionListener> actionListener : actionListeners) {
actionListener.second.notifyOnResume();
}
for (Object eventListener : eventListeners) {
EventBus.register(eventListener);
}

Просмотреть файл

@ -6,15 +6,16 @@
package com.microsoft.embeddedsocial.ui.util;
import com.microsoft.embeddedsocial.account.UserAccount;
import com.microsoft.embeddedsocial.service.ServiceAction;
import com.microsoft.embeddedsocial.service.WorkerService;
import com.microsoft.embeddedsocial.service.worker.UpdateNotificationCountWorker;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.text.format.DateUtils;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
/**
* Periodically updates notification count.
*/
@ -24,12 +25,10 @@ public class NotificationCountChecker {
private static long lastUpdateTime;
private final Context context;
private final Handler handler;
private Runnable updateTask = this::updateNotificationCount;
public NotificationCountChecker(Context context) {
this.context = context;
public NotificationCountChecker() {
handler = new Handler(Looper.getMainLooper());
}
@ -50,7 +49,9 @@ public class NotificationCountChecker {
private void updateNotificationCount() {
lastUpdateTime = SystemClock.elapsedRealtime();
WorkerService.getLauncher(context).launchService(ServiceAction.UPDATE_NOTIFICATION_COUNT);
OneTimeWorkRequest workRequest =
new OneTimeWorkRequest.Builder(UpdateNotificationCountWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
handler.postDelayed(updateTask, PERIOD);
}

Просмотреть файл

@ -10,11 +10,14 @@ import com.microsoft.embeddedsocial.autorest.models.IdentityProvider;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Model for social network data
*/
public class SocialNetworkAccount implements Parcelable {
public class SocialNetworkAccount implements Parcelable, Serializable {
private static final long serialVersionUID = -113535768434512586L;
private final IdentityProvider identityProvider;
private final String thirdPartyAccountHandle;
private String thirdPartyAccessToken;