Merge lp:~karni/ubuntuone-android-files/handling-expired-tokens-better into lp:ubuntuone-android-files

Proposed by Michał Karnicki
Status: Merged
Merged at revision: 469
Proposed branch: lp:~karni/ubuntuone-android-files/handling-expired-tokens-better
Merge into: lp:ubuntuone-android-files
Diff against target: 856 lines (+292/-114)
10 files modified
src/com/ubuntuone/android/files/UbuntuOneFiles.java (+23/-1)
src/com/ubuntuone/android/files/activity/FilesActivity.java (+66/-83)
src/com/ubuntuone/android/files/activity/LoginActivity.java (+10/-1)
src/com/ubuntuone/android/files/event/ActivityStateEvent.java (+37/-0)
src/com/ubuntuone/android/files/event/AuthStateEvent.java (+41/-0)
src/com/ubuntuone/android/files/event/SyncStateEvent.java (+37/-0)
src/com/ubuntuone/android/files/fragment/SignInFragment.java (+4/-1)
src/com/ubuntuone/android/files/receiver/BatteryStatusReceiver.java (+10/-3)
src/com/ubuntuone/android/files/service/MetaService.java (+32/-15)
src/com/ubuntuone/android/files/service/UpDownService.java (+32/-10)
To merge this branch: bzr merge lp:~karni/ubuntuone-android-files/handling-expired-tokens-better
Reviewer Review Type Date Requested Status
Mike McCracken (community) visual only Approve
Review via email: mp+196220@code.launchpad.net

Description of the change

We didn't get robust enough UX for handling sign-out situation (i.e. notification not dismissed when log-in form shown, app not showing log-in form when simply restoring state when relaunched from home screen), so this time I used Otto event bus to nail it.

- Robust notification/foreground reauthentication.
- Fix the metadata sync indicator/spinner for good.
- Silence some battery charging logs in auto upload service.

To post a comment you must log in.
Revision history for this message
Michał Karnicki (karni) wrote :

Tested by removing the auth token when:
- app is in background. Upload a picture. Notice the re-authentication notification.
- app is in foreground. Do anything. Notice the login form show up.

In case the log in form shows up when launched from the home screen, the notification goes away (as it should). If app is in foreground, it goes back to the app once you use the log in form, rather than drop to home screen.

Revision history for this message
Mike McCracken (mikemc) wrote :

Looks reasonable to me.

review: Approve (visual only)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'libs/otto-1.3.3.jar'
2Binary files libs/otto-1.3.3.jar 1970-01-01 00:00:00 +0000 and libs/otto-1.3.3.jar 2013-11-22 03:45:33 +0000 differ
3=== modified file 'src/com/ubuntuone/android/files/UbuntuOneFiles.java'
4--- src/com/ubuntuone/android/files/UbuntuOneFiles.java 2013-01-15 23:02:20 +0000
5+++ src/com/ubuntuone/android/files/UbuntuOneFiles.java 2013-11-22 03:45:33 +0000
6@@ -1,7 +1,7 @@
7 /*
8 * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
9 *
10- * Copyright 2011-2012 Canonical Ltd.
11+ * Copyright 2011-2013 Canonical Ltd.
12 *
13 * This file is part of Ubuntu One Files.
14 *
15@@ -29,9 +29,13 @@
16 import android.content.pm.PackageManager.NameNotFoundException;
17 import android.preference.PreferenceManager;
18
19+import com.squareup.otto.Bus;
20+import com.squareup.otto.Produce;
21+import com.squareup.otto.ThreadEnforcer;
22 import com.ubuntuone.android.files.activity.FilesActivity;
23 import com.ubuntuone.android.files.activity.LoginActivity;
24 import com.ubuntuone.android.files.activity.StorageActivity;
25+import com.ubuntuone.android.files.event.AuthStateEvent;
26 import com.ubuntuone.android.files.provider.MetaUtilities;
27 import com.ubuntuone.android.files.provider.TransfersContract.TransferPriority;
28 import com.ubuntuone.android.files.service.AutoUploadService;
29@@ -46,12 +50,29 @@
30
31 private static UbuntuOneFiles sAppInstance;
32
33+ private Bus mBus = new Bus(ThreadEnforcer.ANY);
34+ private AuthStateEvent mAuthStateEvent = new AuthStateEvent();
35+
36+ public static Bus getBus() {
37+ return sAppInstance.mBus;
38+ }
39+
40 private MediaScannerHelper mMediaScannerHelper;
41
42 public UbuntuOneFiles() {
43 super();
44 sAppInstance = this;
45 setupLogging();
46+ mBus.register(this);
47+ }
48+
49+ @Produce
50+ public AuthStateEvent lastAuthStateEvent() {
51+ return mAuthStateEvent;
52+ }
53+
54+ public void setLastAuthStateEvent(AuthStateEvent event) {
55+ mAuthStateEvent = event;
56 }
57
58 @Override
59@@ -97,6 +118,7 @@
60
61 @Override
62 public void onTerminate() {
63+ mBus.unregister(this);
64 Log.i(TAG, "Terminating application");
65 super.onTerminate();
66 }
67
68=== modified file 'src/com/ubuntuone/android/files/activity/FilesActivity.java'
69--- src/com/ubuntuone/android/files/activity/FilesActivity.java 2013-11-21 19:16:17 +0000
70+++ src/com/ubuntuone/android/files/activity/FilesActivity.java 2013-11-22 03:45:33 +0000
71@@ -1,7 +1,7 @@
72 /*
73 * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
74 *
75- * Copyright 2011-2012 Canonical Ltd.
76+ * Copyright 2011-2013 Canonical Ltd.
77 *
78 * This file is part of Ubuntu One Files.
79 *
80@@ -41,13 +41,11 @@
81 import android.app.Dialog;
82 import android.app.ProgressDialog;
83 import android.content.ActivityNotFoundException;
84-import android.content.BroadcastReceiver;
85 import android.content.ContentResolver;
86 import android.content.Context;
87 import android.content.DialogInterface;
88 import android.content.DialogInterface.OnClickListener;
89 import android.content.Intent;
90-import android.content.IntentFilter;
91 import android.content.res.Configuration;
92 import android.database.Cursor;
93 import android.graphics.Bitmap;
94@@ -78,17 +76,24 @@
95 import android.widget.Toast;
96
97 import com.google.android.apps.analytics.GoogleAnalyticsTracker;
98+import com.squareup.otto.Bus;
99+import com.squareup.otto.Produce;
100+import com.squareup.otto.Subscribe;
101 import com.ubuntuone.android.files.Analytics;
102 import com.ubuntuone.android.files.Preferences;
103 import com.ubuntuone.android.files.R;
104+import com.ubuntuone.android.files.UbuntuOneFiles;
105+import com.ubuntuone.android.files.event.ActivityStateEvent;
106+import com.ubuntuone.android.files.event.AuthStateEvent;
107+import com.ubuntuone.android.files.event.SyncStateEvent;
108 import com.ubuntuone.android.files.holder.FileViewHolder;
109 import com.ubuntuone.android.files.provider.MetaContract.Nodes;
110 import com.ubuntuone.android.files.provider.MetaContract.ResourceState;
111 import com.ubuntuone.android.files.provider.MetaUtilities;
112 import com.ubuntuone.android.files.provider.TransfersContract.Downloads;
113+import com.ubuntuone.android.files.service.AutoUploadService;
114 import com.ubuntuone.android.files.service.MetaService;
115 import com.ubuntuone.android.files.service.MetaService.Status;
116-import com.ubuntuone.android.files.service.AutoUploadService;
117 import com.ubuntuone.android.files.service.MetaServiceHelper;
118 import com.ubuntuone.android.files.service.UpDownService;
119 import com.ubuntuone.android.files.service.UpDownService.OnDownloadListener;
120@@ -161,10 +166,11 @@
121
122 private GoogleAnalyticsTracker mTracker;
123
124+ private Bus mBus;
125+ private ActivityStateEvent mActivityStateEvent = new ActivityStateEvent();
126+
127 private Handler mHandler;
128 private DetachableResultReceiver mReceiver;
129- private SignOutBroadcastReceiver mSignOutReceiver;
130- private boolean mSignOutReceiverRegistered = false;
131
132 private ContentResolver mResolver;
133
134@@ -197,6 +203,8 @@
135 protected void onCreate(Bundle savedInstanceState) {
136 super.onCreate(savedInstanceState);
137
138+ mBus = UbuntuOneFiles.getBus();
139+
140 mTracker = GoogleAnalyticsTracker.getInstance();
141 mTracker.start(Analytics.U1F_ACCOUNT, this);
142 mTracker.trackPageView(TAG);
143@@ -360,23 +368,48 @@
144 }
145
146 @Override
147+ protected void onStart() {
148+ super.onStart();
149+
150+ mActivityStateEvent.setIsVisible(true);
151+ mBus.post(mActivityStateEvent);
152+ }
153+
154+ @Override
155 protected void onResume() {
156 super.onResume();
157+ mBus.register(this);
158+
159 // This should be moved to onCreate, really.
160 ChangeLogUtils.maybeShowChangelog(this);
161
162 if (mReceiver != null) {
163 mReceiver.setReceiver(this);
164- if (MetaService.isSyncRunning()) {
165- awaitWithListEmptyTextView();
166- showSpinner();
167- } else {
168- hideSpinner();
169- }
170 }
171- registerSignOutReceiver();
172 setCursorAdapterInBackground();
173 }
174+
175+ @Subscribe
176+ public void onSyncStateEvent(final SyncStateEvent event) {
177+ if (event.isRunning()) {
178+ awaitWithListEmptyTextView();
179+ showSpinner();
180+ } else {
181+ hideSpinner();
182+ }
183+ }
184+
185+ @Produce
186+ public ActivityStateEvent lastActivityStateEvent() {
187+ return mActivityStateEvent;
188+ }
189+
190+ @Subscribe
191+ public void onAuthStateEvent(final AuthStateEvent event) {
192+ if (!event.isAuthenticated()) {
193+ signIn();
194+ }
195+ }
196
197 /**
198 * Requests appropriate cursor and sets the {@link FilesAdapter} on
199@@ -416,14 +449,22 @@
200
201 @Override
202 protected void onPause() {
203- unregisterSignOutReceiver();
204 if (mReceiver != null) {
205 mReceiver.detach();
206 }
207+ mBus.unregister(this);
208 super.onPause();
209 }
210
211 @Override
212+ protected void onStop() {
213+ mActivityStateEvent.setIsVisible(false);
214+ mBus.post(mActivityStateEvent);
215+
216+ super.onStop();
217+ }
218+
219+ @Override
220 public void onDestroy() {
221 if (mTracker != null) {
222 mTracker.dispatch();
223@@ -863,7 +904,9 @@
224
225 private void onActionBarRereshClicked() {
226 if (!NetworkUtil.isConnected(this)) {
227- hideSpinner();
228+ if (mLoaderItem != null) {
229+ mLoaderItem.setLoading(false);
230+ }
231 showDialog(DIALOG_NO_NETWORK);
232 } else if (mPathTracker.isAtRoot()) {
233 onRefresh(null);
234@@ -993,33 +1036,15 @@
235 resultData.getString(MetaService.EXTRA_RESOURCE_PATH);
236
237 switch (resultCode) {
238- case Status.RUNNING:
239- showSpinner();
240- awaitWithListEmptyTextView();
241- break;
242- case Status.PROGRESS:
243- // Unused.
244- break;
245 case Status.FINISHED:
246- hideSpinner();
247 setCursorAdapterInBackground();
248
249 if (lastResourcePath != null &&
250 lastResourcePath.equals(currentVolumeResourcePath)) {
251- resetListEmptyTextView(null);
252 isGettingVolume = false;
253 return;
254 }
255
256- final String currentResourcePath = mPathTracker.getCurrentNode();
257- if (currentResourcePath == null) {
258- // Most probably the user has no files yet. If he has,
259- // he should already see them and this will have no impact.
260- resetListEmptyTextView(null);
261- } else if (currentResourcePath.equals(lastResourcePath)) {
262- resetListEmptyTextView(lastResourcePath);
263- }
264-
265 if (mCheckDirectorySizeDialog != null
266 && mCheckDirectorySizeDialog.isShowing()) {
267 final String contextResourcePath =
268@@ -1073,7 +1098,7 @@
269 runOnUiThread(new Runnable() {
270 public void run() {
271 hideSpinner();
272- resetListEmptyTextView(lastResourcePath);
273+
274 final String msg = String.format(
275 getString(R.string.error_fmt), errorMessage);
276 UIUtil.showToast(FilesActivity.this, msg, true);
277@@ -1407,6 +1432,8 @@
278 // This should avoid delayed update of the list-empty label.
279 if (NetworkUtil.isConnected(this)) {
280 awaitWithListEmptyTextView();
281+ } else {
282+ mEmptyTextView.setText(R.string.no_network);
283 }
284
285 // Save the position of the list, just for the previous screen.
286@@ -1439,6 +1466,7 @@
287 private void showSpinner() {
288 mHandler.post(new Runnable() {
289 public void run() {
290+ mEmptyTextView.setText(R.string.loading_files);
291 if (mLoaderItem != null)
292 mLoaderItem.setLoading(true);
293 }
294@@ -1448,6 +1476,7 @@
295 private void hideSpinner() {
296 mHandler.post(new Runnable() {
297 public void run() {
298+ mEmptyTextView.setText(R.string.folder_is_empty);
299 if (mLoaderItem != null) {
300 mLoaderItem.setLoading(false);
301 }
302@@ -1473,28 +1502,6 @@
303 });
304 }
305
306- private void resetListEmptyTextView(final String resourcePath) {
307- if (!NetworkUtil.isConnected(FilesActivity.this)) {
308- mEmptyTextView.setText(R.string.no_network);
309- return;
310- }
311-
312- String directoryEmpty = getString(R.string.folder_is_empty);
313- if (mEmptyTextView != null &&
314- mEmptyTextView.getText().equals(directoryEmpty)) {
315- return;
316- }
317- mHandler.post(new Runnable() {
318- public void run() {
319- String node = mPathTracker.getCurrentNode();
320- if (resourcePath == null || node == null ||
321- resourcePath.equals(node)) {
322- mEmptyTextView.setText(R.string.folder_is_empty);
323- }
324- }
325- });
326- }
327-
328 public void downloadFile(final String resourcePath) {
329 if (NetworkUtil.isConnected(this)) {
330 TransferUtils.dequeueByResourcePath(getContentResolver(),
331@@ -1913,33 +1920,9 @@
332 changeCursor(filesCursor);
333 notifyDataSetChanged();
334
335- onRefresh(resourcePath);
336- }
337- }
338-
339- private void registerSignOutReceiver() {
340- if (mSignOutReceiver == null || !mSignOutReceiverRegistered) {
341- mSignOutReceiver = new SignOutBroadcastReceiver();
342- IntentFilter intentFilter =
343- new IntentFilter("com.ubuntuone.android.files.SIGN_OUT");
344- LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
345- lbm.registerReceiver(mSignOutReceiver, intentFilter);
346- mSignOutReceiverRegistered = true;
347- }
348- }
349-
350- private void unregisterSignOutReceiver() {
351- if (mSignOutReceiver != null && mSignOutReceiverRegistered) {
352- LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
353- lbm.unregisterReceiver(mSignOutReceiver);
354- mSignOutReceiverRegistered = false;
355- }
356- }
357-
358- private class SignOutBroadcastReceiver extends BroadcastReceiver {
359- @Override
360- public void onReceive(Context context, Intent intent) {
361- signIn();
362+ if (NetworkUtil.isConnected(FilesActivity.this)) {
363+ onRefresh(resourcePath);
364+ }
365 }
366 }
367
368
369=== modified file 'src/com/ubuntuone/android/files/activity/LoginActivity.java'
370--- src/com/ubuntuone/android/files/activity/LoginActivity.java 2013-11-21 19:15:53 +0000
371+++ src/com/ubuntuone/android/files/activity/LoginActivity.java 2013-11-22 03:45:33 +0000
372@@ -1,7 +1,7 @@
373 /*
374 * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
375 *
376- * Copyright (C) 2011 Canonical Ltd.
377+ * Copyright (C) 2011-2013 Canonical Ltd.
378 * Author: Michał Karnicki <michal.karnicki@canonical.com>
379 *
380 * This file is part of Ubuntu One Files.
381@@ -25,6 +25,7 @@
382 import android.accounts.Account;
383 import android.accounts.AccountAuthenticatorResponse;
384 import android.accounts.AccountManager;
385+import android.app.NotificationManager;
386 import android.content.Intent;
387 import android.os.Bundle;
388 import android.support.v4.app.FragmentActivity;
389@@ -82,6 +83,8 @@
390 protected void onCreate(Bundle savedInstanceState) {
391 super.onCreate(savedInstanceState);
392
393+ dismissReauthenticateNotification();
394+
395 setContentView(R.layout.fragment_content);
396
397 final Intent intent = getIntent();
398@@ -142,6 +145,12 @@
399 break;
400 }
401 }
402+
403+ public void dismissReauthenticateNotification() {
404+ NotificationManager nm = (NotificationManager)
405+ getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
406+ nm.cancel(R.id.stat_please_reauthenticate);
407+ }
408
409 @Override
410 public void finish() {
411
412=== added directory 'src/com/ubuntuone/android/files/event'
413=== added file 'src/com/ubuntuone/android/files/event/ActivityStateEvent.java'
414--- src/com/ubuntuone/android/files/event/ActivityStateEvent.java 1970-01-01 00:00:00 +0000
415+++ src/com/ubuntuone/android/files/event/ActivityStateEvent.java 2013-11-22 03:45:33 +0000
416@@ -0,0 +1,37 @@
417+/*
418+ * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
419+ *
420+ * Copyright 2011-2013 Canonical Ltd.
421+ *
422+ * This file is part of Ubuntu One Files.
423+ *
424+ * This program is free software: you can redistribute it and/or modify
425+ * it under the terms of the GNU Affero General Public License as
426+ * published by the Free Software Foundation, either version 3 of the
427+ * License, or (at your option) any later version.
428+ *
429+ * This program is distributed in the hope that it will be useful,
430+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
431+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
432+ * GNU Affero General Public License for more details.
433+ *
434+ * You should have received a copy of the GNU Affero General Public License
435+ * along with this program. If not, see http://www.gnu.org/licenses
436+ */
437+
438+package com.ubuntuone.android.files.event;
439+
440+public class ActivityStateEvent {
441+ boolean isVisible = true;
442+
443+ public ActivityStateEvent() {
444+ }
445+
446+ public void setIsVisible(boolean visible) {
447+ this.isVisible = visible;
448+ }
449+
450+ public boolean isVisible() {
451+ return isVisible;
452+ }
453+}
454
455=== added file 'src/com/ubuntuone/android/files/event/AuthStateEvent.java'
456--- src/com/ubuntuone/android/files/event/AuthStateEvent.java 1970-01-01 00:00:00 +0000
457+++ src/com/ubuntuone/android/files/event/AuthStateEvent.java 2013-11-22 03:45:33 +0000
458@@ -0,0 +1,41 @@
459+/*
460+ * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
461+ *
462+ * Copyright 2011-2013 Canonical Ltd.
463+ *
464+ * This file is part of Ubuntu One Files.
465+ *
466+ * This program is free software: you can redistribute it and/or modify
467+ * it under the terms of the GNU Affero General Public License as
468+ * published by the Free Software Foundation, either version 3 of the
469+ * License, or (at your option) any later version.
470+ *
471+ * This program is distributed in the hope that it will be useful,
472+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
473+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
474+ * GNU Affero General Public License for more details.
475+ *
476+ * You should have received a copy of the GNU Affero General Public License
477+ * along with this program. If not, see http://www.gnu.org/licenses
478+ */
479+
480+package com.ubuntuone.android.files.event;
481+
482+public class AuthStateEvent {
483+ boolean isAuthenticated = false;
484+
485+ public AuthStateEvent() {
486+ }
487+
488+ public AuthStateEvent(boolean isAuthenticated) {
489+ this.isAuthenticated = isAuthenticated;
490+ }
491+
492+ public void setIsAuthenticated(boolean authenticated) {
493+ this.isAuthenticated = authenticated;
494+ }
495+
496+ public boolean isAuthenticated() {
497+ return isAuthenticated;
498+ }
499+}
500
501=== added file 'src/com/ubuntuone/android/files/event/SyncStateEvent.java'
502--- src/com/ubuntuone/android/files/event/SyncStateEvent.java 1970-01-01 00:00:00 +0000
503+++ src/com/ubuntuone/android/files/event/SyncStateEvent.java 2013-11-22 03:45:33 +0000
504@@ -0,0 +1,37 @@
505+/*
506+ * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
507+ *
508+ * Copyright 2011-2013 Canonical Ltd.
509+ *
510+ * This file is part of Ubuntu One Files.
511+ *
512+ * This program is free software: you can redistribute it and/or modify
513+ * it under the terms of the GNU Affero General Public License as
514+ * published by the Free Software Foundation, either version 3 of the
515+ * License, or (at your option) any later version.
516+ *
517+ * This program is distributed in the hope that it will be useful,
518+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
519+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
520+ * GNU Affero General Public License for more details.
521+ *
522+ * You should have received a copy of the GNU Affero General Public License
523+ * along with this program. If not, see http://www.gnu.org/licenses
524+ */
525+
526+package com.ubuntuone.android.files.event;
527+
528+public class SyncStateEvent {
529+ boolean isRunning = false;
530+
531+ public SyncStateEvent() {
532+ }
533+
534+ public void setIsRunning(boolean isRunning) {
535+ this.isRunning = isRunning;
536+ }
537+
538+ public boolean isRunning() {
539+ return isRunning;
540+ }
541+}
542
543=== modified file 'src/com/ubuntuone/android/files/fragment/SignInFragment.java'
544--- src/com/ubuntuone/android/files/fragment/SignInFragment.java 2013-11-15 14:25:16 +0000
545+++ src/com/ubuntuone/android/files/fragment/SignInFragment.java 2013-11-22 03:45:33 +0000
546@@ -1,7 +1,7 @@
547 /*
548 * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
549 *
550- * Copyright 2011-2012 Canonical Ltd.
551+ * Copyright 2011-2013 Canonical Ltd.
552 *
553 * This file is part of Ubuntu One Files.
554 *
555@@ -47,6 +47,8 @@
556 import com.ubuntuone.android.files.Constants;
557 import com.ubuntuone.android.files.Preferences;
558 import com.ubuntuone.android.files.R;
559+import com.ubuntuone.android.files.UbuntuOneFiles;
560+import com.ubuntuone.android.files.event.AuthStateEvent;
561 import com.ubuntuone.android.files.service.AutoUploadService;
562 import com.ubuntuone.android.files.util.AuthenticateUserTask;
563 import com.ubuntuone.android.files.util.AuthenticateUserTask.AuthenticateUserTaskCallback;
564@@ -281,6 +283,7 @@
565 }
566 }
567
568+ UbuntuOneFiles.getInstance().setLastAuthStateEvent(new AuthStateEvent(true));
569 activity.setResult(Activity.RESULT_OK);
570 activity.finish();
571 }
572
573=== modified file 'src/com/ubuntuone/android/files/receiver/BatteryStatusReceiver.java'
574--- src/com/ubuntuone/android/files/receiver/BatteryStatusReceiver.java 2013-01-30 22:13:28 +0000
575+++ src/com/ubuntuone/android/files/receiver/BatteryStatusReceiver.java 2013-11-22 03:45:33 +0000
576@@ -35,7 +35,10 @@
577 {
578 private final static String TAG = BatteryStatusReceiver.class.getSimpleName();
579
580+ boolean lastIsPlugged = false;
581 boolean isPlugged = false;
582+
583+ boolean lastIsCharging = false;
584 boolean isCharging = false;
585
586 private OnAutoUploadEventListener stateListener;
587@@ -50,7 +53,7 @@
588 public void onReceive(Context context, Intent intent) {
589 String action = intent.getAction();
590 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
591- Log.i(TAG, action);
592+ Log.d(TAG, action);
593 onActionBatteryChanged(context);
594 } else {
595 Log.w(TAG, "Unhandled broadcast: " + action);
596@@ -64,7 +67,11 @@
597
598 public void onActionBatteryChanged(Context context) {
599 updateBatteryState(context);
600- stateListener.onAutoUploadEventReceived();
601+ if (lastIsPlugged != isPlugged || lastIsCharging != isCharging) {
602+ lastIsPlugged = isPlugged;
603+ lastIsCharging = isCharging;
604+ stateListener.onAutoUploadEventReceived();
605+ }
606 }
607
608 public void updateBatteryState(Context context) {
609@@ -79,7 +86,7 @@
610 isCharging = (statusFlag != -1) &&
611 (statusFlag == BatteryManager.BATTERY_STATUS_CHARGING ||
612 statusFlag == BatteryManager.BATTERY_STATUS_FULL);
613- Log.i(TAG, String.format(Locale.US,
614+ Log.d(TAG, String.format(Locale.US,
615 "Battery state: isPlugged %b, isCharging %b",
616 isPlugged, isCharging));
617 }
618
619=== modified file 'src/com/ubuntuone/android/files/service/MetaService.java'
620--- src/com/ubuntuone/android/files/service/MetaService.java 2013-02-06 23:07:30 +0000
621+++ src/com/ubuntuone/android/files/service/MetaService.java 2013-11-22 03:45:33 +0000
622@@ -1,7 +1,7 @@
623 /*
624 * Ubuntu One Files - access Ubuntu One cloud storage on Android platform.
625 *
626- * Copyright 2011-2012 Canonical Ltd.
627+ * Copyright 2011-2013 Canonical Ltd.
628 *
629 * This file is part of Ubuntu One Files.
630 *
631@@ -34,6 +34,7 @@
632 import android.content.ContentProviderOperation;
633 import android.content.ContentResolver;
634 import android.content.ContentValues;
635+import android.content.Context;
636 import android.content.Intent;
637 import android.content.OperationApplicationException;
638 import android.database.Cursor;
639@@ -42,11 +43,14 @@
640 import android.os.IBinder;
641 import android.os.RemoteException;
642 import android.os.ResultReceiver;
643-import android.support.v4.content.LocalBroadcastManager;
644
645+import com.squareup.otto.Bus;
646+import com.squareup.otto.Produce;
647 import com.ubuntuone.android.files.Constants;
648 import com.ubuntuone.android.files.Preferences;
649 import com.ubuntuone.android.files.UbuntuOneFiles;
650+import com.ubuntuone.android.files.event.AuthStateEvent;
651+import com.ubuntuone.android.files.event.SyncStateEvent;
652 import com.ubuntuone.android.files.provider.MetaContract;
653 import com.ubuntuone.android.files.provider.MetaContract.Nodes;
654 import com.ubuntuone.android.files.provider.MetaContract.ResourceState;
655@@ -106,7 +110,9 @@
656 public final int ERROR = 5;
657 }
658
659- public static boolean sSyncRunning = false;
660+ private Bus mBus;
661+ private SyncStateEvent mSyncStateEvent = new SyncStateEvent();
662+ private AuthStateEvent mAuthStateEvent = new AuthStateEvent();
663
664 private ContentResolver contentResolver;
665
666@@ -116,6 +122,7 @@
667
668 public MetaService() {
669 super(MetaService.class.getSimpleName());
670+ mBus = UbuntuOneFiles.getBus();
671 }
672
673 @Override
674@@ -123,10 +130,20 @@
675 return null;
676 }
677
678+ @Produce public SyncStateEvent lastSyncStateEvent() {
679+ return mSyncStateEvent;
680+ }
681+
682+ private void sendSyncState(boolean isRunning) {
683+ mSyncStateEvent.setIsRunning(isRunning);
684+ mBus.post(mSyncStateEvent);
685+ }
686+
687 @Override
688 public void onCreate() {
689 super.onCreate();
690 Log.d(TAG, "onCreate()");
691+ mBus.register(this);
692
693 contentResolver = getContentResolver();
694 httpClient = HttpClientProvider.getInstance();
695@@ -140,7 +157,7 @@
696
697 @Override
698 protected void onHandleIntent(Intent intent) {
699- sSyncRunning = true;
700+ sendSyncState(true);
701 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
702
703 final String action = intent.getAction();
704@@ -173,17 +190,14 @@
705 } else if (ACTION_DELETE_NODE.equals(action)) {
706 deleteNode(resourcePath, receiver);
707 }
708- sSyncRunning = false;
709+ sendSyncState(false);
710 }
711
712 @Override
713 public void onDestroy() {
714+ Log.d(TAG, "onDestroy()");
715+ mBus.unregister(this);
716 super.onDestroy();
717- Log.d(TAG, "onDestroy()");
718- }
719-
720- public static boolean isSyncRunning() {
721- return sSyncRunning;
722 }
723
724 public void onUbuntuOneFailure(U1Failure failure, ResultReceiver receiver) {
725@@ -202,11 +216,14 @@
726 Bundle data;
727 switch (statusCode) {
728 case HttpStatus.SC_UNAUTHORIZED:
729- Preferences.invalidateToken(this);
730-
731- Intent intent = new Intent("com.ubuntuone.android.files.SIGN_OUT");
732- LocalBroadcastManager.getInstance(getApplicationContext())
733- .sendBroadcast(intent);
734+ Log.w(TAG, "Received HTTP Unauthorized response.");
735+ Context context = UbuntuOneFiles.getInstance().getApplicationContext();
736+ Preferences.invalidateToken(context);
737+ UbuntuOneFiles.getInstance().setLastAuthStateEvent(new AuthStateEvent(false));
738+
739+ mAuthStateEvent.setIsAuthenticated(false);
740+ mBus.post(mAuthStateEvent);
741+
742 stopSelf();
743 break;
744 case HttpStatus.SC_NOT_FOUND:
745
746=== modified file 'src/com/ubuntuone/android/files/service/UpDownService.java'
747--- src/com/ubuntuone/android/files/service/UpDownService.java 2013-11-15 14:33:02 +0000
748+++ src/com/ubuntuone/android/files/service/UpDownService.java 2013-11-22 03:45:33 +0000
749@@ -54,6 +54,8 @@
750 import android.support.v4.content.LocalBroadcastManager;
751
752 import com.google.android.apps.analytics.GoogleAnalyticsTracker;
753+import com.squareup.otto.Bus;
754+import com.squareup.otto.Subscribe;
755 import com.ubuntuone.android.files.Alarms;
756 import com.ubuntuone.android.files.Analytics;
757 import com.ubuntuone.android.files.Constants;
758@@ -63,6 +65,8 @@
759 import com.ubuntuone.android.files.activity.FilesActivity;
760 import com.ubuntuone.android.files.activity.LoginActivity;
761 import com.ubuntuone.android.files.activity.PreferencesActivity;
762+import com.ubuntuone.android.files.event.ActivityStateEvent;
763+import com.ubuntuone.android.files.event.AuthStateEvent;
764 import com.ubuntuone.android.files.provider.MetaContract.Nodes;
765 import com.ubuntuone.android.files.provider.MetaContract.ResourceState;
766 import com.ubuntuone.android.files.provider.MetaContract.Volumes;
767@@ -120,6 +124,10 @@
768
769 private static final String PART = ".part";
770
771+ private Bus mBus;
772+ private AuthStateEvent mAuthStateEvent = new AuthStateEvent();
773+ private boolean isAppVisible = false;
774+
775 private ConnectivityManager connectivityManager;
776 private NotificationManager notificationManager;
777
778@@ -157,10 +165,16 @@
779 private final int downloadNotificationId = R.id.stat_ongoing_download_id;
780
781 private GoogleAnalyticsTracker mTracker;
782+
783+ @Subscribe public void onActivityStateEvent(final ActivityStateEvent event) {
784+ isAppVisible = event.isVisible();
785+ }
786
787 @Override
788 public void onCreate() {
789 super.onCreate();
790+ mBus = UbuntuOneFiles.getBus();
791+ mBus.register(this);
792 duration = System.currentTimeMillis();
793 }
794
795@@ -172,10 +186,10 @@
796 mTracker = GoogleAnalyticsTracker.getInstance();
797 mTracker.startNewSession(Analytics.U1F_ACCOUNT, this);
798
799- connectivityManager = (ConnectivityManager) getSystemService(
800- CONNECTIVITY_SERVICE);
801- notificationManager = (NotificationManager) getSystemService(
802- NOTIFICATION_SERVICE);
803+ connectivityManager = (ConnectivityManager)
804+ getSystemService(CONNECTIVITY_SERVICE);
805+ notificationManager = (NotificationManager) getApplicationContext()
806+ .getSystemService(NOTIFICATION_SERVICE);
807
808 contentResolver = getContentResolver();
809
810@@ -343,6 +357,7 @@
811
812 @Override
813 public void onDestroy() {
814+ mBus.unregister(this);
815 long elapsed = System.currentTimeMillis() - duration;
816 Log.i(TAG, "Operation time " + UIUtil.formatTime(elapsed));
817 super.onDestroy();
818@@ -1123,7 +1138,6 @@
819 // TODO log failure status codes in GA
820 switch (failure.getStatusCode()) {
821 case HttpStatus.SC_UNAUTHORIZED:
822- showReauthenticateNotification();
823 onUnauthorizedResponse();
824 break;
825 case HttpStatus.SC_PAYMENT_REQUIRED:
826@@ -1143,10 +1157,10 @@
827 Log.w(TAG, "Received HTTP Unauthorized response.");
828 Context context = UbuntuOneFiles.getInstance().getApplicationContext();
829 Preferences.invalidateToken(context);
830-
831- Intent intent = new Intent("com.ubuntuone.android.files.SIGN_OUT");
832- LocalBroadcastManager.getInstance(getApplicationContext())
833- .sendBroadcast(intent);
834+ UbuntuOneFiles.getInstance().setLastAuthStateEvent(new AuthStateEvent(false));
835+
836+ requireReauthentication();
837+
838 stopSelf();
839 }
840
841@@ -1207,7 +1221,15 @@
842 notificationManager.notify(R.id.stat_failed_upload_id, notification);
843 }
844
845- private void showReauthenticateNotification() {
846+ private void requireReauthentication() {
847+ if (isAppVisible) {
848+ // Show the log-in activity.
849+ mAuthStateEvent.setIsAuthenticated(false);
850+ mBus.post(mAuthStateEvent);
851+ return;
852+ }
853+
854+ // Post a log-in notification.
855 final String title = getString(R.string.please_reauthenticate);
856 final String text = getString(R.string.you_have_been_signed_out);
857

Subscribers

People subscribed via source and target branches

to status/vote changes: