// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.firstrun; import android.accounts.Account; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import org.chromium.chrome.R; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileDownloader; import org.chromium.chrome.browser.profiles.ProfileDownloader.Observer; import org.chromium.components.signin.AccountManagerHelper; import org.chromium.ui.gfx.DeviceDisplayInfo; import java.util.HashMap; /** * Fetches and caches Google Account profile images and full names for the accounts on the device. */ public class ProfileDataCache implements Observer { private static final int PROFILE_IMAGE_SIZE_DP = 136; // Max size of the user picture. private static final int PROFILE_IMAGE_STROKE_DP = 3; private static class CacheEntry { public CacheEntry(Bitmap picture, String fullName, String givenName) { this.picture = picture; this.fullName = fullName; this.givenName = givenName; } public Bitmap picture; public String fullName; public String givenName; } private final HashMap<String, CacheEntry> mCacheEntries = new HashMap<String, CacheEntry>(); private final Bitmap mPlaceholderImage; private final int mImageSizePx; private final int mImageStrokePx; private final int mImageStrokeColor; private Observer mObserver; private final Context mContext; private Profile mProfile; public ProfileDataCache(Context context, Profile profile) { ProfileDownloader.addObserver(this); mContext = context; mProfile = profile; final DeviceDisplayInfo info = DeviceDisplayInfo.create(context); mImageSizePx = (int) Math.ceil(PROFILE_IMAGE_SIZE_DP * info.getDIPScale()); mImageStrokePx = (int) Math.ceil(PROFILE_IMAGE_STROKE_DP * info.getDIPScale()); mImageStrokeColor = Color.WHITE; Bitmap placeHolder = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.fre_placeholder); mPlaceholderImage = getCroppedBitmap(placeHolder); update(); } /** * Sets the profile to use for the fetcher and triggers the update. * @param profile A profile to use. */ public void setProfile(Profile profile) { mProfile = profile; update(); } /** * Initiate fetching the user accounts data (images and the full name). * Fetched data will be sent to observers of ProfileDownloader. */ public void update() { if (mProfile == null) return; Account[] accounts = AccountManagerHelper.get(mContext).getGoogleAccounts(); for (int i = 0; i < accounts.length; i++) { if (mCacheEntries.get(accounts[i].name) == null) { ProfileDownloader.startFetchingAccountInfoFor( mContext, mProfile, accounts[i].name, mImageSizePx, true); } } } /** * @param accountId Google account ID for the image that is requested. * @return Returns the profile image for a given Google account ID if it's in * the cache, otherwise returns a placeholder image. */ public Bitmap getImage(String accountId) { CacheEntry cacheEntry = mCacheEntries.get(accountId); if (cacheEntry == null) return mPlaceholderImage; return cacheEntry.picture; } /** * @param accountId Google account ID for the full name that is requested. * @return Returns the full name for a given Google account ID if it is * the cache, otherwise returns null. */ public String getFullName(String accountId) { CacheEntry cacheEntry = mCacheEntries.get(accountId); if (cacheEntry == null) return null; return cacheEntry.fullName; } /** * @param accountId Google account ID for the full name that is requested. * @return Returns the given name for a given Google account ID if it is in the cache, otherwise * returns null. */ public String getGivenName(String accountId) { CacheEntry cacheEntry = mCacheEntries.get(accountId); if (cacheEntry == null) return null; return cacheEntry.givenName; } public void destroy() { ProfileDownloader.removeObserver(this); mObserver = null; } @Override public void onProfileDownloaded(String accountId, String fullName, String givenName, Bitmap bitmap) { bitmap = getCroppedBitmap(bitmap); mCacheEntries.put(accountId, new CacheEntry(bitmap, fullName, givenName)); if (mObserver != null) mObserver.onProfileDownloaded(accountId, fullName, givenName, bitmap); } private Bitmap getCroppedBitmap(Bitmap bitmap) { Bitmap output = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(Color.WHITE); final float radius = (bitmap.getWidth() - mImageStrokePx) / 2f; canvas.drawCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, radius, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); paint.setColor(mImageStrokeColor); paint.setStyle(Paint.Style.STROKE); paint.setXfermode(new PorterDuffXfermode(Mode.SRC)); paint.setStrokeWidth(mImageStrokePx); canvas.drawCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, radius, paint); return output; } /** * @param observer Observer that should be notified when new profile images are available. */ public void setObserver(Observer observer) { mObserver = observer; } }