OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.ntp; |
| 6 |
| 7 import android.animation.Animator; |
| 8 import android.animation.AnimatorListenerAdapter; |
| 9 import android.animation.ObjectAnimator; |
| 10 import android.app.Activity; |
| 11 import android.graphics.Color; |
| 12 import android.view.Gravity; |
| 13 import android.view.LayoutInflater; |
| 14 import android.view.View; |
| 15 import android.widget.FrameLayout; |
| 16 import android.widget.TextView; |
| 17 |
| 18 import com.google.android.apps.chrome.R; |
| 19 |
| 20 import org.chromium.chrome.browser.firstrun.AccountFirstRunView; |
| 21 import org.chromium.chrome.browser.firstrun.ProfileDataCache; |
| 22 import org.chromium.chrome.browser.profiles.Profile; |
| 23 import org.chromium.chrome.browser.signin.AccountAdder; |
| 24 import org.chromium.chrome.browser.sync.ui.ConfirmAccountChangeFragment; |
| 25 import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver; |
| 26 |
| 27 /** |
| 28 * Promo view on the recent tabs page that encourages the user to sign in to Chr
ome or enable sync. |
| 29 * This view handles three scenarios: |
| 30 * |
| 31 * 1. The user is not signed in: Shows the sign-in screen from first run. |
| 32 * 2. The user is signed in but sync is disabled: Displays a message encouraging
the user |
| 33 * to enable sync with a corresponding button. |
| 34 * 3. The user is signed in and sync is enabled: Displays a message instructing |
| 35 * the user to sign in and open tabs on another device to use this awesome fe
ature. |
| 36 */ |
| 37 public class RecentTabsPromoView extends FrameLayout implements AndroidSyncSetti
ngsObserver { |
| 38 |
| 39 /** |
| 40 * Interface definition for the model this view needs to interact with. |
| 41 */ |
| 42 public interface SyncPromoModel { |
| 43 /** |
| 44 * @return Whether sync is enabled. |
| 45 */ |
| 46 public boolean isSyncEnabled(); |
| 47 |
| 48 /** |
| 49 * @return Whether the user is signed in. |
| 50 */ |
| 51 public boolean isSignedIn(); |
| 52 |
| 53 /** |
| 54 * Enables sync for the current signed in account. |
| 55 */ |
| 56 public void enableSync(); |
| 57 |
| 58 /** |
| 59 * Attaches a listener to sync state changes. |
| 60 * |
| 61 * @param changeListener The SyncStateChangedListener The object to regi
ster for sync |
| 62 * updates. |
| 63 */ |
| 64 public void registerForSyncUpdates(AndroidSyncSettingsObserver changeLis
tener); |
| 65 |
| 66 /** |
| 67 * Removes a listener for sync state changes. |
| 68 * |
| 69 * @param changeListener The SyncStateChangedListener The object to unre
gister for sync |
| 70 * updates. |
| 71 */ |
| 72 public void unregisterForSyncUpdates(AndroidSyncSettingsObserver changeL
istener); |
| 73 } |
| 74 |
| 75 /** |
| 76 * Interface for listening user actions on this UI. |
| 77 */ |
| 78 public interface UserActionListener { |
| 79 /** |
| 80 * Called when user confirms an account to sign-in. |
| 81 */ |
| 82 void onAccountSelectionConfirmed(); |
| 83 |
| 84 /** |
| 85 * Called when user attempts to create a new account. |
| 86 */ |
| 87 void onNewAccount(); |
| 88 } |
| 89 |
| 90 private static final int PROMO_TYPE_SIGN_IN = 0; |
| 91 private static final int PROMO_TYPE_SYNC_DISABLED = 1; |
| 92 private static final int PROMO_TYPE_SYNC_ENABLED = 2; |
| 93 |
| 94 private static final int TEXT_COLOR_NORMAL = 0xff333333; |
| 95 private static final int TEXT_COLOR_LIGHT = 0xffa0a0a0; |
| 96 |
| 97 private static final long FADE_DURATION_MS = 300L; |
| 98 |
| 99 private Activity mActivity; |
| 100 private SyncPromoModel mModel; |
| 101 private UserActionListener mUserActionListener; |
| 102 |
| 103 private View mPromo; |
| 104 private int mPromoType = -1; |
| 105 private Animator mFadeAnimation; |
| 106 |
| 107 /** |
| 108 * Constructor for use from Java. |
| 109 * |
| 110 * @param activity The Activity this view will be presented in. |
| 111 * @param model The SyncPromoModel used to determine the state of sync and s
ign-in. |
| 112 */ |
| 113 public RecentTabsPromoView(Activity activity, SyncPromoModel model, |
| 114 UserActionListener userActionListener) { |
| 115 super(activity); |
| 116 mModel = model; |
| 117 mActivity = activity; |
| 118 mUserActionListener = userActionListener; |
| 119 int sidePadding = getResources().getDimensionPixelOffset(R.dimen.recent_
tabs_promo_padding); |
| 120 setPadding(sidePadding, 0, sidePadding, 0); |
| 121 } |
| 122 |
| 123 @Override |
| 124 protected void onAttachedToWindow() { |
| 125 super.onAttachedToWindow(); |
| 126 mModel.registerForSyncUpdates(this); |
| 127 configureForSyncState(false); |
| 128 } |
| 129 |
| 130 @Override |
| 131 protected void onDetachedFromWindow() { |
| 132 super.onDetachedFromWindow(); |
| 133 mModel.unregisterForSyncUpdates(this); |
| 134 } |
| 135 |
| 136 @Override |
| 137 public void onWindowVisibilityChanged(int visibility) { |
| 138 super.onWindowVisibilityChanged(visibility); |
| 139 if (visibility == View.VISIBLE) { |
| 140 configureForSyncState(false); |
| 141 } |
| 142 } |
| 143 |
| 144 // AndroidSyncSettingsObserver |
| 145 @Override |
| 146 public void androidSyncSettingsChanged() { |
| 147 configureForSyncState(true); |
| 148 } |
| 149 |
| 150 private void configureForSyncState(boolean animate) { |
| 151 int desiredPromoType = getDesiredPromoType(); |
| 152 if (mPromo != null && mPromoType == desiredPromoType) { |
| 153 return; |
| 154 } |
| 155 |
| 156 // In the rare case that the promo type changes while an animation is al
ready underway, |
| 157 // cancel the existing animation and show the new promo without animatio
n. This is a rare |
| 158 // case, and it's not worth the complexity (and bug potential) of implem
enting a three-way |
| 159 // cross fade. |
| 160 if (mFadeAnimation != null) { |
| 161 mFadeAnimation.end(); |
| 162 animate = false; |
| 163 } |
| 164 |
| 165 if (animate && mPromoType == PROMO_TYPE_SIGN_IN) { |
| 166 ((AccountFirstRunView) mPromo).switchToSignedMode(); |
| 167 } |
| 168 |
| 169 final View oldPromo = mPromo; |
| 170 mPromoType = desiredPromoType; |
| 171 mPromo = createPromoView(desiredPromoType); |
| 172 |
| 173 if (animate) { |
| 174 // Fade in the new promo on top of the old one. Set the background c
olor to white so |
| 175 // the old promo effectively fades out as the new one fades in. |
| 176 mPromo.setAlpha(0f); |
| 177 mPromo.setBackgroundColor(Color.WHITE); |
| 178 addView(mPromo); |
| 179 |
| 180 mFadeAnimation = ObjectAnimator.ofFloat(mPromo, View.ALPHA, 1f); |
| 181 mFadeAnimation.setDuration(FADE_DURATION_MS); |
| 182 mFadeAnimation.addListener(new AnimatorListenerAdapter() { |
| 183 @Override |
| 184 public void onAnimationEnd(Animator animation) { |
| 185 mFadeAnimation = null; |
| 186 mPromo.setBackgroundResource(0); |
| 187 removeView(oldPromo); |
| 188 } |
| 189 }); |
| 190 mFadeAnimation.start(); |
| 191 } else { |
| 192 removeView(oldPromo); |
| 193 addView(mPromo); |
| 194 } |
| 195 } |
| 196 |
| 197 private int getDesiredPromoType() { |
| 198 if (!mModel.isSignedIn()) { |
| 199 return PROMO_TYPE_SIGN_IN; |
| 200 } else { |
| 201 return mModel.isSyncEnabled() ? PROMO_TYPE_SYNC_ENABLED : PROMO_TYPE
_SYNC_DISABLED; |
| 202 } |
| 203 } |
| 204 |
| 205 private View createPromoView(int promoType) { |
| 206 if (promoType == PROMO_TYPE_SIGN_IN) { |
| 207 return createSignInPromoView(); |
| 208 } else { |
| 209 return createSyncPromoView(promoType == PROMO_TYPE_SYNC_ENABLED); |
| 210 } |
| 211 } |
| 212 |
| 213 private View createSyncPromoView(boolean isSyncEnabled) { |
| 214 View syncPromoView = LayoutInflater.from(getContext()).inflate( |
| 215 R.layout.recent_tabs_sync_promo, this, false); |
| 216 |
| 217 TextView textView = (TextView) syncPromoView.findViewById(R.id.text_view
); |
| 218 View enableSyncButton = syncPromoView.findViewById(R.id.enable_sync_butt
on); |
| 219 |
| 220 if (isSyncEnabled) { |
| 221 textView.setText(R.string.ntp_recent_tabs_sync_promo_instructions); |
| 222 textView.setTextColor(TEXT_COLOR_LIGHT); |
| 223 enableSyncButton.setVisibility(View.GONE); |
| 224 } else { |
| 225 textView.setText(R.string.ntp_recent_tabs_sync_enable_sync); |
| 226 textView.setTextColor(TEXT_COLOR_NORMAL); |
| 227 enableSyncButton.setOnClickListener(new OnClickListener() { |
| 228 @Override |
| 229 public void onClick(View v) { |
| 230 mModel.enableSync(); |
| 231 } |
| 232 }); |
| 233 } |
| 234 |
| 235 return syncPromoView; |
| 236 } |
| 237 |
| 238 private View createSignInPromoView() { |
| 239 AccountFirstRunView signInPromoView = (AccountFirstRunView) |
| 240 LayoutInflater.from(getContext()).inflate(R.layout.fre_choose_ac
count, this, false); |
| 241 ProfileDataCache profileData = new ProfileDataCache( |
| 242 mActivity, Profile.getLastUsedProfile()); |
| 243 signInPromoView.init(profileData); |
| 244 signInPromoView.getLayoutParams().height = LayoutParams.WRAP_CONTENT; |
| 245 ((FrameLayout.LayoutParams) signInPromoView.getLayoutParams()).gravity =
Gravity.CENTER; |
| 246 signInPromoView.configureForRecentTabsPage(); |
| 247 signInPromoView.setCanCancel(false); |
| 248 signInPromoView.setListener(new AccountFirstRunView.Listener() { |
| 249 @Override |
| 250 public void onAccountSelectionConfirmed(String accountName) { |
| 251 mUserActionListener.onAccountSelectionConfirmed(); |
| 252 |
| 253 ConfirmAccountChangeFragment.confirmSyncAccount(accountName, mAc
tivity); |
| 254 } |
| 255 |
| 256 @Override |
| 257 public void onAccountSelectionCanceled() { |
| 258 assert false : "Button should be hidden"; |
| 259 } |
| 260 |
| 261 @Override |
| 262 public void onNewAccount() { |
| 263 mUserActionListener.onNewAccount(); |
| 264 |
| 265 AccountAdder.getInstance().addAccount(mActivity, AccountAdder.AD
D_ACCOUNT_RESULT); |
| 266 } |
| 267 |
| 268 @Override |
| 269 public void onSigningInCompleted(String accountName) { |
| 270 assert false : "Button should be hidden"; |
| 271 } |
| 272 |
| 273 @Override |
| 274 public void onSettingsButtonClicked(String accountName) { |
| 275 assert false : "Button should be hidden"; |
| 276 } |
| 277 |
| 278 @Override |
| 279 public void onFailedToSetForcedAccount(String forcedAccountName) { |
| 280 // TODO(bauerb): make sure we shouldn't see SignInPromoView. |
| 281 assert false : "No forced accounts in SignInPromoView"; |
| 282 } |
| 283 }); |
| 284 |
| 285 return signInPromoView; |
| 286 } |
| 287 } |
OLD | NEW |