36 | * Sample execution is shown below 37 | *
38 | * OneoffTask toggleTask = new OneoffTask.Builder()
39 | * .setService(SyncNotificationsService.class)
40 | * .setExecutionWindow(0, 5) // execute now +/- 5 min
41 | * .setExtras(bundle) // Bundle fron NotificationUtils
42 | * .setPersisted(false) // Persist Task Across reboots
43 | * .setRequiredNetwork(Task.NETWORK_STATE_ANY) // Requires network (yes)
44 | * .setRequiresCharging(false) // Requires charging (false)
45 | * .build();
46 | */
47 | public class SyncNotificationsService extends GcmTaskService {
48 |
49 | private static final String PERIODIC_UPDATE_TASK = "NetworkManagerDashboardSyncPeriodic";
50 |
51 | public SyncNotificationsService() {
52 |
53 | }
54 |
55 | private static void schedulePeriodicNotifications(Context context) {
56 |
57 | long periodSecs = 60 * 60 * 24; // Auto-update should be performed no more than once per 24 hours
58 |
59 | PeriodicTask dailyUpdate = new PeriodicTask.Builder()
60 | .setService(SyncNotificationsService.class)
61 | .setPeriod(periodSecs)
62 | .setTag(PERIODIC_UPDATE_TASK)
63 | .setPersisted(true)
64 | .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
65 | .setRequiresCharging(false)
66 | .setUpdateCurrent(true)
67 | .build();
68 |
69 | GcmNetworkManager.getInstance(context).schedule(dailyUpdate);
70 | Timber.d("Scheduled auto-update");
71 | }
72 |
73 | @Override
74 | public void onInitializeTasks() {
75 | //schedulePeriodicNotifications(getApplicationContext());
76 | }
77 |
78 | @Override
79 | public int onStartCommand(Intent intent, int flags, int startId) {
80 |
81 | BaseApplication.get(getApplicationContext()).getComponent().inject(this);
82 |
83 | return super.onStartCommand(intent, flags, startId);
84 | }
85 |
86 | @Override
87 | public int onRunTask(TaskParams taskParams) {
88 |
89 | /**
90 | * Sync Data with the server
91 | */
92 | boolean isComplete = true;
93 | boolean isReschedule = false;
94 |
95 |
96 | if (isComplete && !isReschedule) {
97 | return GcmNetworkManager.RESULT_SUCCESS;
98 | } else if (isComplete) {
99 | return GcmNetworkManager.RESULT_RESCHEDULE;
100 | } else {
101 | return GcmNetworkManager.RESULT_FAILURE;
102 | }
103 |
104 | }
105 |
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/test/java/com/twolinessoftware/android/test/ui/RegisterPresenterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 2LinesSoftware Inc
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *
15 | */
16 |
17 | package com.twolinessoftware.android.test.ui;
18 |
19 | import android.content.Context;
20 | import android.test.suitebuilder.annotation.SmallTest;
21 |
22 | import com.twolinessoftware.ErrorException;
23 | import com.twolinessoftware.PreferencesHelper;
24 | import com.twolinessoftware.activities.login.LoginViewCallback;
25 | import com.twolinessoftware.activities.login.RegisterPresenter;
26 | import com.twolinessoftware.authentication.AuthenticationManager;
27 | import com.twolinessoftware.authentication.Token;
28 | import com.twolinessoftware.model.User;
29 | import com.twolinessoftware.network.UserNetworkApi;
30 |
31 | import org.junit.Before;
32 | import org.junit.Test;
33 | import org.junit.runner.RunWith;
34 | import org.mockito.Mock;
35 | import org.mockito.runners.MockitoJUnitRunner;
36 |
37 | import rx.Observable;
38 | import rx.schedulers.Schedulers;
39 |
40 | import static org.mockito.Matchers.any;
41 | import static org.mockito.Mockito.never;
42 | import static org.mockito.Mockito.verify;
43 | import static org.mockito.Mockito.when;
44 | import static org.mockito.MockitoAnnotations.initMocks;
45 |
46 | @SmallTest
47 | @RunWith(MockitoJUnitRunner.class)
48 | public class RegisterPresenterTest {
49 |
50 | @Mock
51 | LoginViewCallback mLoginViewCallback;
52 |
53 | @Mock
54 | UserNetworkApi mUserNetworkApi;
55 |
56 | @Mock
57 | AuthenticationManager mAuthenticationManager;
58 |
59 | @Mock
60 | PreferencesHelper mPreferencesHelper;
61 |
62 | @Mock
63 | Context mContext;
64 |
65 | private RegisterPresenter mRegisterPresenter;
66 |
67 | @Before
68 | public void before() {
69 | initMocks(this);
70 |
71 | mRegisterPresenter = new RegisterPresenter(mUserNetworkApi, mAuthenticationManager, Schedulers.immediate(), mPreferencesHelper);
72 | mRegisterPresenter.attachView(mLoginViewCallback);
73 | }
74 |
75 | @Test
76 | public void registerPresenter_EnsureLoginIsCalled() {
77 |
78 | when(mUserNetworkApi.register(any(), any())).thenReturn(Observable.just(new Token("test", 10)));
79 |
80 | when(mUserNetworkApi.createUser(any(), any())).thenReturn(Observable.just(new User("email")));
81 |
82 | when(mPreferencesHelper.getUserUid()).thenReturn("uid");
83 |
84 | mRegisterPresenter.register("email", "password");
85 |
86 |
87 | verify(mLoginViewCallback).showProgress(true);
88 | verify(mUserNetworkApi).register("email", "password");
89 | verify(mUserNetworkApi).createUser("uid", "email");
90 |
91 | verify(mLoginViewCallback).showProgress(false);
92 | verify(mLoginViewCallback).onFinishLogin(any());
93 |
94 | }
95 |
96 | @Test
97 | public void registerPresenter_ShowErrorOnInvalidPassword() {
98 |
99 | when(mUserNetworkApi.register(any(), any())).thenReturn(Observable.error(new ErrorException(ErrorException.Code.EMAIL_TAKEN)));
100 |
101 | mRegisterPresenter.register("email", "password");
102 | verify(mLoginViewCallback).showProgress(true);
103 | verify(mUserNetworkApi).register("email", "password");
104 | verify(mUserNetworkApi, never()).createUser(any(), any());
105 |
106 | verify(mLoginViewCallback).showProgress(false);
107 | verify(mLoginViewCallback).onError(ErrorException.Code.EMAIL_TAKEN);
108 |
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/twolinessoftware/activities/login/RegisterPresenter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 2LinesSoftware Inc
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *
15 | */
16 |
17 | package com.twolinessoftware.activities.login;
18 |
19 | import android.support.annotation.Nullable;
20 |
21 | import com.twolinessoftware.ErrorException;
22 | import com.twolinessoftware.PreferencesHelper;
23 | import com.twolinessoftware.activities.BasePresenter;
24 | import com.twolinessoftware.authentication.AuthenticationManager;
25 | import com.twolinessoftware.authentication.Token;
26 | import com.twolinessoftware.network.UserNetworkApi;
27 |
28 | import javax.inject.Inject;
29 |
30 | import rx.Scheduler;
31 | import timber.log.Timber;
32 |
33 | public class RegisterPresenter implements BasePresenter extends RecyclerView.Adapter> mDataSource;
29 | private ListChangesSubscriber mListChangesSubscriber;
30 | private ReplaySubject
mEntries;
32 |
33 |
34 | private final Handler mRefreshHandler = new Handler(Looper.getMainLooper()) {
35 | @Override
36 | public void handleMessage(Message msg) {
37 | notifyDataSetChanged();
38 | }
39 | };
40 |
41 | public RxAdapter(@LayoutRes int childLayoutResId, Observable> data) {
42 | mChildLayoutResId = childLayoutResId;
43 | mPublishSubjectData = ReplaySubject.create();
44 | mListChangesSubscriber = new ListChangesSubscriber();
45 | mEntries = new ArrayList<>();
46 | updateQuery(data);
47 | }
48 |
49 | public Observable
> newQuery) {
56 | Timber.v("Updating data query");
57 | mDataSource = newQuery;
58 | registerObservers();
59 | }
60 |
61 | public void refresh() {
62 | mRefreshHandler.sendEmptyMessage(0);
63 | }
64 |
65 | public LayoutViewBinder
getNewLayoutViewBinder(View view) {
66 | return new LayoutViewBinder(view);
67 | }
68 |
69 | private class ListChangesSubscriber extends Subscriber> {
70 |
71 | @Override
72 | public void onCompleted() {
73 | Timber.v("Refresh completed");
74 | }
75 |
76 | @Override
77 | public void onError(Throwable e) {
78 | Timber.e("Error loading data: " + Log.getStackTraceString(e));
79 | }
80 |
81 | @Override
82 | public void onNext(List
items) {
83 |
84 | Timber.v("Updating list with " + items.size() + " items");
85 |
86 | mEntries.clear();
87 | mEntries.addAll(items);
88 |
89 | refresh();
90 |
91 | }
92 | }
93 |
94 | private void cleanup() {
95 | Timber.v("Removing last subscriber");
96 | unregisterObservers();
97 | }
98 |
99 | private void registerObservers() {
100 | unregisterObservers();
101 | Timber.v("Registering data listeners");
102 | mListChangesSubscriber = new ListChangesSubscriber();
103 |
104 | mDataSource
105 | .subscribeOn(Schedulers.newThread())
106 | .subscribe(mListChangesSubscriber);
107 | }
108 |
109 | private void unregisterObservers() {
110 |
111 | if (mListChangesSubscriber != null) {
112 | Timber.v("Cleaning up data listeners");
113 | mListChangesSubscriber.unsubscribe();
114 | }
115 | }
116 |
117 | @Override
118 | public LayoutViewBinder onCreateViewHolder(ViewGroup parent, int viewType) {
119 |
120 | View v = LayoutInflater.from(parent.getContext())
121 | .inflate(mChildLayoutResId, parent, false);
122 | return getNewLayoutViewBinder(v);
123 | }
124 |
125 | @Override
126 | public void onBindViewHolder(LayoutViewBinder holder, int position) {
127 | S item = mEntries.get(position);
128 |
129 | holder.setPositionIndex(position);
130 | holder.setData(item);
131 | mPublishSubjectData.onNext(holder);
132 | }
133 |
134 | @Override
135 | public int getItemCount() {
136 | return mEntries.size();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |