mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1177855: Fetch and show avatar image as preference icon. r=nalexander
The profile JSON is stored in the Account bundle. There's no need to bump the bundle version, since missing (i.e., null) profile JSON is legal. This introduces and uses a general-purpose PicassoPreferenceIcon Picasso Target that, on API 11+ devices, dynamically loads a preference icon.
This commit is contained in:
parent
5785e7b90a
commit
5b362f8911
@ -863,6 +863,7 @@ sync_java_files = [
|
||||
'fxa/activities/FxAccountStatusFragment.java',
|
||||
'fxa/activities/FxAccountUpdateCredentialsActivity.java',
|
||||
'fxa/activities/FxAccountVerifiedAccountActivity.java',
|
||||
'fxa/activities/PicassoPreferenceIconTarget.java',
|
||||
'fxa/authenticator/AccountPickler.java',
|
||||
'fxa/authenticator/AndroidFxAccount.java',
|
||||
'fxa/authenticator/FxAccountAuthenticator.java',
|
||||
|
@ -24,7 +24,7 @@ public class FxAccountConstants {
|
||||
public static final String STAGE_PROFILE_SERVER_ENDPOINT = "https://latest.dev.lcip.org/profile/v1";
|
||||
|
||||
// Action to update on cached profile information.
|
||||
public static final String ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION = "org.mozilla.gecko.fxa.profile.cached";
|
||||
public static final String ACCOUNT_PROFILE_JSON_UPDATED_ACTION = "org.mozilla.gecko.fxa.profile.JSON.updated";
|
||||
|
||||
// You must be at least 13 years old, on the day of creation, to create a Firefox Account.
|
||||
public static final int MINIMUM_AGE_TO_CREATE_AN_ACCOUNT = 13;
|
||||
|
@ -50,6 +50,8 @@ import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
/**
|
||||
* A fragment that displays the status of an AndroidFxAccount.
|
||||
@ -140,13 +142,11 @@ public class FxAccountStatusFragment
|
||||
// Runnable to update last synced time.
|
||||
protected Runnable lastSyncedTimeUpdateRunnable;
|
||||
|
||||
// Runnable to retry fetching profile information.
|
||||
protected Runnable profileFetchRunnable;
|
||||
|
||||
// Broadcast Receiver to update profile Information.
|
||||
protected FxAccountProfileInformationReceiver accountProfileInformationReceiver;
|
||||
|
||||
protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
|
||||
private Target profileAvatarTarget;
|
||||
|
||||
protected Preference ensureFindPreference(String key) {
|
||||
Preference preference = findPreference(key);
|
||||
@ -485,6 +485,18 @@ public class FxAccountStatusFragment
|
||||
// register/unregister calls.
|
||||
FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusDelegate);
|
||||
|
||||
if (AppConstants.MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES) {
|
||||
// Register a local broadcast receiver to get profile cached notification.
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION);
|
||||
accountProfileInformationReceiver = new FxAccountProfileInformationReceiver();
|
||||
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(accountProfileInformationReceiver, intentFilter);
|
||||
|
||||
// profilePreference is set during onCreate, so it's definitely not null here.
|
||||
final float cornerRadius = getResources().getDimension(R.dimen.fxaccount_profile_image_width) / 2;
|
||||
profileAvatarTarget = new PicassoPreferenceIconTarget(getResources(), profilePreference, cornerRadius);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
@ -498,14 +510,15 @@ public class FxAccountStatusFragment
|
||||
handler.removeCallbacks(lastSyncedTimeUpdateRunnable);
|
||||
}
|
||||
|
||||
if (profileFetchRunnable != null) {
|
||||
handler.removeCallbacks(profileFetchRunnable);
|
||||
}
|
||||
|
||||
// Focus lost, unregister broadcast receiver.
|
||||
if (accountProfileInformationReceiver != null) {
|
||||
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(accountProfileInformationReceiver);
|
||||
}
|
||||
|
||||
if (profileAvatarTarget != null) {
|
||||
Picasso.with(getActivity()).cancelRequest(profileAvatarTarget);
|
||||
profileAvatarTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void hardRefresh() {
|
||||
@ -606,53 +619,60 @@ public class FxAccountStatusFragment
|
||||
return;
|
||||
}
|
||||
|
||||
final ExtendedJSONObject cachedProfileJSON = fxAccount.getCachedProfileJSON();
|
||||
if (cachedProfileJSON != null) {
|
||||
// Update profile information from the cached Json.
|
||||
updateProfileInformation(cachedProfileJSON);
|
||||
final ExtendedJSONObject profileJSON = fxAccount.getProfileJSON();
|
||||
if (profileJSON == null) {
|
||||
// Update the profile title with email as the fallback.
|
||||
// Profile icon by default use the default avatar as the fallback.
|
||||
profilePreference.setTitle(fxAccount.getEmail());
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the profile title with email as the fallback.
|
||||
// Profile icon by default use the default avatar as the fallback.
|
||||
profilePreference.setTitle(fxAccount.getEmail());
|
||||
|
||||
// Register a local broadcast receiver to get profile cached notification.
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION);
|
||||
accountProfileInformationReceiver = new FxAccountProfileInformationReceiver();
|
||||
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(accountProfileInformationReceiver, intentFilter);
|
||||
|
||||
// Fetch the profile from the server.
|
||||
fxAccount.maybeUpdateProfileJSON(false);
|
||||
|
||||
// Schedule an runnable to retry fetching profile.
|
||||
profileFetchRunnable = new ProfileFetchUpdateRunnable();
|
||||
handler.postDelayed(profileFetchRunnable, PROFILE_FETCH_RETRY_INTERVAL_IN_MILLISECONDS);
|
||||
updateProfileInformation(profileJSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile information from json on UI thread.
|
||||
*
|
||||
* @param profileJson json fetched from server.
|
||||
* @param profileJSON json fetched from server.
|
||||
*/
|
||||
protected void updateProfileInformation(final ExtendedJSONObject profileJson) {
|
||||
// Remove the scheduled runnable for fetching the profile information.
|
||||
if (profileFetchRunnable != null) {
|
||||
handler.removeCallbacks(profileFetchRunnable);
|
||||
protected void updateProfileInformation(final ExtendedJSONObject profileJSON) {
|
||||
// View changes must always be done on UI thread.
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
FxAccountUtils.pii(LOG_TAG, "Profile JSON is: " + profileJSON.toJSONString());
|
||||
|
||||
final String userName = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_USERNAME);
|
||||
// Update the profile username and email if available.
|
||||
if (!TextUtils.isEmpty(userName)) {
|
||||
profilePreference.setTitle(userName);
|
||||
profilePreference.setSummary(fxAccount.getEmail());
|
||||
} else {
|
||||
profilePreference.setTitle(fxAccount.getEmail());
|
||||
}
|
||||
|
||||
// Read the profile information from json and Update the UI elements.
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Icon update from java is not supported prior to API 11, skip the avatar update for older device.
|
||||
if (AppConstants.Versions.feature11Plus) {
|
||||
profilePreference.setIcon(getResources().getDrawable(R.drawable.sync_avatar_default));
|
||||
}
|
||||
profilePreference.setTitle(fxAccount.getAndroidAccount().name);
|
||||
}
|
||||
});
|
||||
// Icon update from java is not supported prior to API 11, skip the avatar image fetch and update for older device.
|
||||
if (!AppConstants.Versions.feature11Plus) {
|
||||
Logger.info(LOG_TAG, "Skipping profile image fetch for older pre-API 11 devices.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Avatar URI empty, skip profile image fetch.
|
||||
final String avatarURI = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_AVATAR);
|
||||
if (TextUtils.isEmpty(avatarURI)) {
|
||||
Logger.info(LOG_TAG, "AvatarURI is empty, skipping profile image fetch.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Using noPlaceholder would avoid a pop of the default image, but it's not available in the version of Picasso
|
||||
// we ship in the tree.
|
||||
Picasso
|
||||
.with(getActivity())
|
||||
.load(avatarURI)
|
||||
.centerInside()
|
||||
.resizeDimen(R.dimen.fxaccount_profile_image_width, R.dimen.fxaccount_profile_image_height)
|
||||
.placeholder(R.drawable.sync_avatar_default)
|
||||
.error(R.drawable.sync_avatar_default)
|
||||
.into(profileAvatarTarget);
|
||||
}
|
||||
|
||||
private void scheduleAndUpdateLastSyncedTime() {
|
||||
@ -830,26 +850,24 @@ public class FxAccountStatusFragment
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Runnable that schedules a future to fetch profile information.
|
||||
*/
|
||||
protected class ProfileFetchUpdateRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
updateProfileInformation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast receiver to receive updates for the cached profile action.
|
||||
*/
|
||||
public class FxAccountProfileInformationReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION)) {
|
||||
// We should have a cached profile json here.
|
||||
updateProfileInformation(fxAccount.getCachedProfileJSON());
|
||||
if (!intent.getAction().equals(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.info(LOG_TAG, "Profile avatar cache update action broadcast received.");
|
||||
// Update the UI from cached profile json on the main thread.
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateProfileInformation();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,76 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.fxa.activities;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.Preference;
|
||||
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
|
||||
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
|
||||
/**
|
||||
* A Picasso Target that updates a preference icon.
|
||||
*
|
||||
* Nota bene: Android grew support for updating preference icons programatically
|
||||
* only in API 11. This class silently ignores requests before API 11.
|
||||
*/
|
||||
public class PicassoPreferenceIconTarget implements Target {
|
||||
private final Preference preference;
|
||||
private final Resources resources;
|
||||
private final float cornerRadius;
|
||||
|
||||
public PicassoPreferenceIconTarget(Resources resources, Preference preference) {
|
||||
this(resources, preference, 0);
|
||||
}
|
||||
|
||||
public PicassoPreferenceIconTarget(Resources resources, Preference preference, float cornerRadius) {
|
||||
this.resources = resources;
|
||||
this.preference = preference;
|
||||
this.cornerRadius = cornerRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||
// Updating icons from Java is not supported prior to API 11.
|
||||
if (!AppConstants.Versions.feature11Plus) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Drawable drawable;
|
||||
if (cornerRadius > 0) {
|
||||
final RoundedBitmapDrawable roundedBitmapDrawable;
|
||||
roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, bitmap);
|
||||
roundedBitmapDrawable.setCornerRadius(cornerRadius);
|
||||
roundedBitmapDrawable.setAntiAlias(true);
|
||||
drawable = roundedBitmapDrawable;
|
||||
} else {
|
||||
drawable = new BitmapDrawable(resources, bitmap);
|
||||
}
|
||||
preference.setIcon(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable errorDrawable) {
|
||||
// Updating icons from Java is not supported prior to API 11.
|
||||
if (!AppConstants.Versions.feature11Plus) {
|
||||
return;
|
||||
}
|
||||
preference.setIcon(errorDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable placeHolderDrawable) {
|
||||
// Updating icons from Java is not supported prior to API 11.
|
||||
if (!AppConstants.Versions.feature11Plus) {
|
||||
return;
|
||||
}
|
||||
preference.setIcon(placeHolderDrawable);
|
||||
}
|
||||
}
|
@ -69,12 +69,12 @@ public class AndroidFxAccount {
|
||||
|
||||
public static final String ACCOUNT_KEY_TOKEN_SERVER = "tokenServerURI"; // Sync-specific.
|
||||
public static final String ACCOUNT_KEY_DESCRIPTOR = "descriptor";
|
||||
public static final String ACCOUNT_KEY_PROFILE_AVATAR = "avatar";
|
||||
|
||||
public static final int CURRENT_BUNDLE_VERSION = 2;
|
||||
public static final String BUNDLE_KEY_BUNDLE_VERSION = "version";
|
||||
public static final String BUNDLE_KEY_STATE_LABEL = "stateLabel";
|
||||
public static final String BUNDLE_KEY_STATE = "state";
|
||||
public static final String BUNDLE_KEY_PROFILE_JSON = "profile";
|
||||
|
||||
// Account authentication token type for fetching account profile.
|
||||
public static final String PROFILE_OAUTH_TOKEN_TYPE = "oauth::profile";
|
||||
@ -105,13 +105,6 @@ public class AndroidFxAccount {
|
||||
}
|
||||
|
||||
private static final String PREF_KEY_LAST_SYNCED_TIMESTAMP = "lastSyncedTimestamp";
|
||||
public static final String PREF_KEY_LAST_PROFILE_FETCH_TIME = "lastProfilefetchTime";
|
||||
public static final String PREF_KEY_NUMBER_OF_PROFILE_FETCH = "numProfileFetch";
|
||||
|
||||
// Max wait time between successful profile avatar network fetch.
|
||||
public static final long PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
|
||||
// Max attempts allowed for retrying profile avatar network fetch.
|
||||
public static final int MAX_PROFILE_FETCH_RETRIES = 5;
|
||||
|
||||
protected final Context context;
|
||||
protected final AccountManager accountManager;
|
||||
@ -127,7 +120,6 @@ public class AndroidFxAccount {
|
||||
*/
|
||||
protected static final ConcurrentHashMap<String, ExtendedJSONObject> perAccountBundleCache =
|
||||
new ConcurrentHashMap<>();
|
||||
private ExtendedJSONObject profileJson;
|
||||
|
||||
public static void invalidateCaches() {
|
||||
perAccountBundleCache.clear();
|
||||
@ -667,39 +659,17 @@ public class AndroidFxAccount {
|
||||
return intent;
|
||||
}
|
||||
|
||||
private void setLastProfileFetchTimestampAndAttempts(long now, int attempts) {
|
||||
try {
|
||||
getSyncPrefs().edit().putLong(PREF_KEY_LAST_PROFILE_FETCH_TIME, now).commit();
|
||||
getSyncPrefs().edit().putInt(PREF_KEY_NUMBER_OF_PROFILE_FETCH, attempts);
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception setting last profile fetch time & attempts; ignoring.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private long getLastProfileFetchTimestamp() {
|
||||
final long neverFetched = -1L;
|
||||
try {
|
||||
return getSyncPrefs().getLong(PREF_KEY_LAST_PROFILE_FETCH_TIME, neverFetched);
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception getting last profile fetch time; ignoring.", e);
|
||||
return neverFetched;
|
||||
}
|
||||
}
|
||||
|
||||
private int getNumberOfProfileFetch() {
|
||||
final int neverFetched = 0;
|
||||
try {
|
||||
return getSyncPrefs().getInt(PREF_KEY_NUMBER_OF_PROFILE_FETCH, neverFetched);
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception getting number of profile fetch; ignoring.", e);
|
||||
return neverFetched;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canScheduleProfileFetch() {
|
||||
final int attempts = getNumberOfProfileFetch();
|
||||
final long delta = System.currentTimeMillis() - getLastProfileFetchTimestamp();
|
||||
return delta > PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS || attempts < MAX_PROFILE_FETCH_RETRIES;
|
||||
/**
|
||||
* Create an intent announcing that the profile JSON attached to this Firefox Account has been updated.
|
||||
* <p>
|
||||
* It is not guaranteed that the profile JSON has changed.
|
||||
*
|
||||
* @return <code>Intent</code> to broadcast.
|
||||
*/
|
||||
private Intent makeProfileJSONUpdatedIntent() {
|
||||
final Intent intent = new Intent();
|
||||
intent.setAction(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public void setLastSyncedTimestamp(long now) {
|
||||
@ -755,60 +725,31 @@ public class AndroidFxAccount {
|
||||
ContentResolver.setIsSyncable(account, BrowserContract.READING_LIST_AUTHORITY, 1);
|
||||
}
|
||||
|
||||
// Helper function to create intent for profile avatar updated event.
|
||||
private Intent getProfileAvatarUpdatedIntent() {
|
||||
final Intent profileCachedIntent = new Intent();
|
||||
profileCachedIntent.setAction(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION);
|
||||
return profileCachedIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached profile JSON object if available or null.
|
||||
* Returns the current profile JSON if available, or null.
|
||||
*
|
||||
* @return profile JSON Object.
|
||||
* @return profile JSON object.
|
||||
*/
|
||||
public ExtendedJSONObject getCachedProfileJSON() {
|
||||
if (profileJson == null) {
|
||||
// Try to retrieve and parse the json string from account manager.
|
||||
final String profileJsonString = accountManager.getUserData(account, ACCOUNT_KEY_PROFILE_AVATAR);
|
||||
if (profileJsonString != null) {
|
||||
Logger.info(LOG_TAG, "Cached Profile information retrieved from AccountManager.");
|
||||
try {
|
||||
profileJson = ExtendedJSONObject.parseJSONObject(profileJsonString);
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Failed to parse profile json; ignoring.", e);
|
||||
}
|
||||
}
|
||||
public ExtendedJSONObject getProfileJSON() {
|
||||
final String profileString = getBundleData(BUNDLE_KEY_PROFILE_JSON);
|
||||
if (profileString == null) {
|
||||
return null;
|
||||
}
|
||||
return profileJson;
|
||||
|
||||
try {
|
||||
return new ExtendedJSONObject(profileString);
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Failed to parse profile JSON; ignoring and returning null.", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the profile json from the server and updates the local cache.
|
||||
*
|
||||
* Fetch the profile JSON associated to the underlying Firefox Account from the server and update the local store.
|
||||
* <p>
|
||||
* On successful fetch and cache, LocalBroadcastManager is used to notify the receivers asynchronously.
|
||||
* </p>
|
||||
*
|
||||
* @param isForceFetch boolean to isForceFetch fetch from the server.
|
||||
* The LocalBroadcastManager is used to notify the receivers asynchronously after a successful fetch.
|
||||
*/
|
||||
public void maybeUpdateProfileJSON(final boolean isForceFetch) {
|
||||
final ExtendedJSONObject profileJson = getCachedProfileJSON();
|
||||
final Intent profileAvatarUpdatedIntent = getProfileAvatarUpdatedIntent();
|
||||
|
||||
if (!isForceFetch && profileJson != null && !profileJson.keySet().isEmpty()) {
|
||||
// Second line of defense, cache may have been updated in between.
|
||||
Logger.info(LOG_TAG, "Profile already cached.");
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(profileAvatarUpdatedIntent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isForceFetch && !canScheduleProfileFetch()) {
|
||||
// Rate limiting repeated attempts to fetch the profile information.
|
||||
Logger.info(LOG_TAG, "Too many attempts to fetch the profile information.");
|
||||
return;
|
||||
}
|
||||
|
||||
public void fetchProfileJSON() {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -828,24 +769,15 @@ public class AndroidFxAccount {
|
||||
final Intent intent = new Intent(context, FxAccountProfileService.class);
|
||||
intent.putExtra(FxAccountProfileService.KEY_AUTH_TOKEN, authToken);
|
||||
intent.putExtra(FxAccountProfileService.KEY_PROFILE_SERVER_URI, getProfileServerURI());
|
||||
intent.putExtra(FxAccountProfileService.KEY_RESULT_RECEIVER, new ProfileResultReceiver(profileAvatarUpdatedIntent));
|
||||
intent.putExtra(FxAccountProfileService.KEY_RESULT_RECEIVER, new ProfileResultReceiver(new Handler()));
|
||||
context.startService(intent);
|
||||
|
||||
// Update the profile fetch time and attempts, resetting the attempts if last fetch was over a day old.
|
||||
final int attempts = getNumberOfProfileFetch();
|
||||
final long now = System.currentTimeMillis();
|
||||
final long delta = now - getLastProfileFetchTimestamp();
|
||||
setLastProfileFetchTimestampAndAttempts(now, delta < PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS ? attempts + 1 : 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class ProfileResultReceiver extends ResultReceiver {
|
||||
private final Intent profileAvatarUpdatedIntent;
|
||||
|
||||
public ProfileResultReceiver(Intent broadcastIntent) {
|
||||
super(new Handler());
|
||||
this.profileAvatarUpdatedIntent = broadcastIntent;
|
||||
public ProfileResultReceiver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -853,21 +785,17 @@ public class AndroidFxAccount {
|
||||
super.onReceiveResult(resultCode, bundle);
|
||||
switch (resultCode) {
|
||||
case Activity.RESULT_OK:
|
||||
try {
|
||||
final String resultData = bundle.getString(FxAccountProfileService.KEY_RESULT_STRING);
|
||||
profileJson = ExtendedJSONObject.parseJSONObject(resultData);
|
||||
accountManager.setUserData(account, ACCOUNT_KEY_PROFILE_AVATAR, resultData);
|
||||
Logger.pii(LOG_TAG, "Profile fetch successful." + resultData);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(profileAvatarUpdatedIntent);
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Failed to parse profile json; ignoring.", e);
|
||||
}
|
||||
final String resultData = bundle.getString(FxAccountProfileService.KEY_RESULT_STRING);
|
||||
updateBundleValues(BUNDLE_KEY_PROFILE_JSON, resultData);
|
||||
Logger.info(LOG_TAG, "Profile JSON fetch succeeeded!");
|
||||
FxAccountUtils.pii(LOG_TAG, "Profile JSON fetch returned: " + resultData);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(makeDeletedAccountIntent());
|
||||
break;
|
||||
case Activity.RESULT_CANCELED:
|
||||
Logger.warn(LOG_TAG, "Failed to fetch profile; ignoring.");
|
||||
Logger.warn(LOG_TAG, "Failed to fetch profile JSON; ignoring.");
|
||||
break;
|
||||
default:
|
||||
Logger.warn(LOG_TAG, "Invalid Result code received; ignoring.");
|
||||
Logger.warn(LOG_TAG, "Invalid result code received; ignoring.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import android.os.Bundle;
|
||||
import android.os.ResultReceiver;
|
||||
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException;
|
||||
import org.mozilla.gecko.background.fxa.profile.FxAccountProfileClient10;
|
||||
@ -37,6 +38,11 @@ public class FxAccountProfileService extends IntentService {
|
||||
final String profileServerURI = intent.getStringExtra(KEY_PROFILE_SERVER_URI);
|
||||
final ResultReceiver resultReceiver = intent.getParcelableExtra(KEY_RESULT_RECEIVER);
|
||||
|
||||
if (resultReceiver == null) {
|
||||
Logger.warn(LOG_TAG, "Result receiver must not be null; ignoring intent.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (authToken == null || authToken.length() == 0) {
|
||||
Logger.warn(LOG_TAG, "Invalid Auth Token");
|
||||
sendResult("Invalid Auth Token", resultReceiver, Activity.RESULT_CANCELED);
|
||||
@ -66,7 +72,7 @@ public class FxAccountProfileService extends IntentService {
|
||||
@Override
|
||||
public void handleSuccess(ExtendedJSONObject result) {
|
||||
if (result != null){
|
||||
Logger.pii(LOG_TAG, "Profile Server response : " + result.toJSONString());
|
||||
FxAccountUtils.pii(LOG_TAG, "Profile server return profile: " + result.toJSONString());
|
||||
sendResult(result.toJSONString(), resultReceiver, Activity.RESULT_OK);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.background.fxa.SkewHandler;
|
||||
@ -532,6 +533,12 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
final KeyBundle syncKeyBundle = married.getSyncKeyBundle();
|
||||
final String clientState = married.getClientState();
|
||||
syncWithAssertion(audience, assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs, syncKeyBundle, clientState, sessionCallback, extras, fxAccount);
|
||||
|
||||
if (AppConstants.MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES) {
|
||||
// Force fetch the profile avatar information.
|
||||
Logger.info(LOG_TAG, "Fetching profile avatar information.");
|
||||
fxAccount.fetchProfileJSON();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
syncDelegate.handleError(e);
|
||||
return;
|
||||
|
@ -25,4 +25,9 @@
|
||||
<dimen name="preference_fragment_padding_side">16dp</dimen>
|
||||
|
||||
<integer name="preference_fragment_scrollbarStyle">0x02000000</integer> <!-- outsideOverlay -->
|
||||
|
||||
<!-- Profile avatar image height. -->
|
||||
<dimen name="fxaccount_profile_image_height">48dp</dimen>
|
||||
<!-- Profile avatar image width. -->
|
||||
<dimen name="fxaccount_profile_image_width">48dp</dimen>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user