Commit fdd63fdc authored by Tanmoy Mollik's avatar Tanmoy Mollik Committed by Commit Bot

[Android] Create Personalized Sync Promo for Bookmark page

This cl creates personalized sync promos for the bookmark page when the
user is signed in but not syncing. This cl also creates a new vector
image and changes the base personalized_signin_promo_view_body.xml
file that will be used to make promos in other places, e.g., Recent
Tabs, Settings etc.
The hooks to show the promo is only added in ReorderBookmarkItemsAdapter
as BookmarkItemsAdapter class is scheduled to be deprecated.

Screenshot: https://crbug.com/1057603#c8

Bug: 1057603
Change-Id: I148395e8ee1e910b117f64b1b7031254c6146043
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2173057
Commit-Queue: Tanmoy Mollik <triploblastic@chromium.org>
Reviewed-by: default avatarBoris Sazonov <bsazonov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771754}
parent 1c3aea31
......@@ -807,6 +807,7 @@ chrome_java_resources = [
"java/res/drawable/ic_signal_cellular_4_bar.xml",
"java/res/drawable/ic_site_timer.xml",
"java/res/drawable/ic_swap_vert_round.xml",
"java/res/drawable/ic_sync_badge_off_20dp.xml",
"java/res/drawable/ic_sync_error_40dp.xml",
"java/res/drawable/ic_sync_green_40dp.xml",
"java/res/drawable/ic_toolbar_share_offset_24dp.xml",
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 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. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="21"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:strokeWidth="1"
android:pathData="M10,20.5C15.799,20.5 20.5,15.799 20.5,10C20.5,4.201 15.799,-0.5 10,-0.5C4.201,-0.5 -0.5,4.201 -0.5,10C-0.5,15.799 4.201,20.5 10,20.5Z"
android:fillColor="#9AA0A6"
android:strokeColor="#ffffff"/>
<path
android:pathData="M8.75,6.4688V5.1625C8.25,5.2937 7.7812,5.5 7.3562,5.7625L8.2687,6.675C8.425,6.6 8.5812,6.525 8.75,6.4688ZM4.2875,5.8812L5.7625,7.3562C5.2812,8.1187 5,9.025 5,10C5,11.3813 5.5687,12.625 6.475,13.525L5,15H8.75V11.25L7.35,12.65C6.675,11.9687 6.25,11.0375 6.25,10C6.25,9.375 6.4062,8.7875 6.675,8.2688L11.725,13.3187C11.5687,13.4 11.4125,13.475 11.2437,13.5312V14.8375C11.7437,14.7062 12.2125,14.5 12.6375,14.2375L14.1125,15.7125L14.9062,14.9188L5.0875,5.0875L4.2875,5.8812ZM15,5H11.25V8.75L12.65,7.35C13.325,8.0313 13.75,8.9625 13.75,10C13.75,10.625 13.5937,11.2125 13.325,11.7313L14.2375,12.6437C14.7187,11.8812 15,10.975 15,10C15,8.6187 14.4312,7.375 13.525,6.475L15,5Z"
android:fillColor="#ffffff"/>
</vector>
......@@ -8,12 +8,24 @@
tools:showIn="@layout/personalized_signin_promo_view_settings">
<TextView
android:id="@+id/signin_promo_description"
android:id="@+id/signin_promo_status_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"
android:text="@string/signin_promo_status_message"
android:visibility="gone"/>
<TextView
android:id="@+id/signin_promo_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="12dp"
android:gravity="center"
android:lineSpacingMultiplier="1.25"
android:textAppearance="@style/TextAppearance.TextMedium.Primary"
......@@ -36,4 +48,4 @@
android:ellipsize="end"
android:singleLine="true"
android:text="@string/signin_promo_choose_account"/>
</merge>
\ No newline at end of file
</merge>
......@@ -43,14 +43,15 @@ class BookmarkItemsAdapter extends DragReorderableListAdapter<BookmarkItem>
* Specifies the view types that the bookmark delegate screen can contain.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({ViewType.PERSONALIZED_SIGNIN_PROMO, ViewType.SYNC_PROMO, ViewType.FOLDER,
ViewType.BOOKMARK})
@IntDef({ViewType.PERSONALIZED_SIGNIN_PROMO, ViewType.PERSONALIZED_SYNC_PROMO,
ViewType.SYNC_PROMO, ViewType.FOLDER, ViewType.BOOKMARK})
private @interface ViewType {
int INVALID_PROMO = -1;
int PERSONALIZED_SIGNIN_PROMO = 0;
int SYNC_PROMO = 1;
int FOLDER = 2;
int BOOKMARK = 3;
int PERSONALIZED_SYNC_PROMO = 1;
int SYNC_PROMO = 2;
int FOLDER = 3;
int BOOKMARK = 4;
}
private static final int MAXIMUM_NUMBER_OF_SEARCH_RESULTS = 500;
......@@ -187,7 +188,9 @@ class BookmarkItemsAdapter extends DragReorderableListAdapter<BookmarkItem>
switch (viewType) {
case ViewType.PERSONALIZED_SIGNIN_PROMO:
return mPromoHeaderManager.createPersonalizedSigninPromoHolder(parent);
// fall through
case ViewType.PERSONALIZED_SYNC_PROMO:
return mPromoHeaderManager.createPersonalizedSigninAndSyncPromoHolder(parent);
case ViewType.SYNC_PROMO:
return mPromoHeaderManager.createSyncPromoHolder(parent);
case ViewType.FOLDER:
......@@ -205,6 +208,9 @@ class BookmarkItemsAdapter extends DragReorderableListAdapter<BookmarkItem>
if (holder.getItemViewType() == ViewType.PERSONALIZED_SIGNIN_PROMO) {
PersonalizedSigninPromoView view = (PersonalizedSigninPromoView) holder.itemView;
mPromoHeaderManager.setupPersonalizedSigninPromo(view);
} else if (holder.getItemViewType() == ViewType.PERSONALIZED_SYNC_PROMO) {
PersonalizedSigninPromoView view = (PersonalizedSigninPromoView) holder.itemView;
mPromoHeaderManager.setupPersonalizedSyncPromo(view);
} else if (!(holder.getItemViewType() == ViewType.SYNC_PROMO)) {
BookmarkRow row = ((BookmarkRow) holder.itemView);
BookmarkId id = getIdByPosition(position);
......@@ -231,6 +237,8 @@ class BookmarkItemsAdapter extends DragReorderableListAdapter<BookmarkItem>
public void onViewRecycled(ViewHolder holder) {
switch (holder.getItemViewType()) {
case ViewType.PERSONALIZED_SIGNIN_PROMO:
// fall through
case ViewType.PERSONALIZED_SYNC_PROMO:
mPromoHeaderManager.detachPersonalizePromoView();
break;
default:
......@@ -407,6 +415,9 @@ class BookmarkItemsAdapter extends DragReorderableListAdapter<BookmarkItem>
case BookmarkPromoHeader.PromoState.PROMO_SIGNIN_PERSONALIZED:
mPromoHeaderType = ViewType.PERSONALIZED_SIGNIN_PROMO;
break;
case BookmarkPromoHeader.PromoState.PROMO_SYNC_PERSONALIZED:
mPromoHeaderType = ViewType.PERSONALIZED_SYNC_PROMO;
break;
case BookmarkPromoHeader.PromoState.PROMO_SYNC:
mPromoHeaderType = ViewType.SYNC_PROMO;
break;
......
......@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.chromium.base.task.PostTask;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
......@@ -29,6 +30,8 @@ import org.chromium.chrome.browser.signin.SigninPromoUtil;
import org.chromium.chrome.browser.signin.SyncPromoView;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.AccountsChangeObserver;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.signin.metrics.SigninAccessPoint;
import org.chromium.components.sync.AndroidSyncSettings;
import org.chromium.components.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
......@@ -47,11 +50,13 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
* Specifies the various states in which the Bookmarks promo can be.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({PromoState.PROMO_NONE, PromoState.PROMO_SIGNIN_PERSONALIZED, PromoState.PROMO_SYNC})
@IntDef({PromoState.PROMO_NONE, PromoState.PROMO_SIGNIN_PERSONALIZED,
PromoState.PROMO_SYNC_PERSONALIZED, PromoState.PROMO_SYNC})
@interface PromoState {
int PROMO_NONE = 0;
int PROMO_SIGNIN_PERSONALIZED = 1;
int PROMO_SYNC = 2;
int PROMO_SYNC_PERSONALIZED = 2;
int PROMO_SYNC = 3;
}
// TODO(kkimlabs): Figure out the optimal number based on UMA data.
......@@ -63,7 +68,7 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
private final SigninManager mSignInManager;
private final Runnable mPromoHeaderChangeAction;
private final @Nullable ProfileDataCache mProfileDataCache;
private @Nullable ProfileDataCache mProfileDataCache;
private final @Nullable SigninPromoController mSigninPromoController;
private @PromoState int mPromoState;
......@@ -77,11 +82,21 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
AndroidSyncSettings.get().registerObserver(this);
mSignInManager = IdentityServicesProvider.get().getSigninManager();
mSignInManager.addSignInStateObserver(this);
mPromoState = calculatePromoState();
if (mPromoState == PromoState.PROMO_SYNC) {
SharedPreferencesManager.getInstance().incrementInt(
ChromePreferenceKeys.SIGNIN_AND_SYNC_PROMO_SHOW_COUNT);
}
if (SigninPromoController.hasNotReachedImpressionLimit(
SigninAccessPoint.BOOKMARK_MANAGER)) {
int imageSize =
mContext.getResources().getDimensionPixelSize(R.dimen.user_picture_size);
mProfileDataCache = new ProfileDataCache(mContext, imageSize);
mProfileDataCache = ProfileDataCache.createProfileDataCache(mContext,
mPromoState == PromoState.PROMO_SYNC_PERSONALIZED
? R.drawable.ic_sync_badge_off_20dp
: 0);
mProfileDataCache.addObserver(this);
mSigninPromoController = new SigninPromoController(SigninAccessPoint.BOOKMARK_MANAGER);
AccountManagerFacadeProvider.getInstance().addObserver(this);
......@@ -89,15 +104,6 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
mProfileDataCache = null;
mSigninPromoController = null;
}
mSignInManager = IdentityServicesProvider.get().getSigninManager();
mSignInManager.addSignInStateObserver(this);
mPromoState = calculatePromoState();
if (mPromoState == PromoState.PROMO_SYNC) {
SharedPreferencesManager.getInstance().incrementInt(
ChromePreferenceKeys.SIGNIN_AND_SYNC_PROMO_SHOW_COUNT);
}
}
/**
......@@ -127,7 +133,7 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
* @return Personalized signin promo header {@link ViewHolder} instance that can be used with
* {@link RecyclerView}.
*/
ViewHolder createPersonalizedSigninPromoHolder(ViewGroup parent) {
ViewHolder createPersonalizedSigninAndSyncPromoHolder(ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(
R.layout.personalized_signin_promo_view_bookmarks, parent, false);
......@@ -155,6 +161,13 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
this::setPersonalizedSigninPromoDeclined);
}
void setupPersonalizedSyncPromo(PersonalizedSigninPromoView view) {
setupPersonalizedSigninPromo(view);
view.getStatusMessage().setVisibility(View.VISIBLE);
view.getChooseAccountButton().setVisibility(View.GONE);
view.getSigninButton().setText(R.string.sync_promo_turn_on_sync);
}
/**
* Detaches the previously configured {@link PersonalizedSigninPromoView}.
*/
......@@ -168,7 +181,7 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
private void setPersonalizedSigninPromoDeclined() {
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.SIGNIN_PROMO_PERSONALIZED_DECLINED, true);
mPromoState = calculatePromoState();
updatePromoState();
triggerPromoUpdate();
}
......@@ -201,6 +214,14 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
}
if (!mSignInManager.getIdentityManager().hasPrimaryAccount()) {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
CoreAccountInfo primaryAccount =
mSignInManager.getIdentityManager().getPrimaryAccountInfo(
ConsentLevel.NOT_REQUIRED);
if (primaryAccount != null && !wasPersonalizedSigninPromoDeclined()) {
return PromoState.PROMO_SYNC_PERSONALIZED;
}
}
return shouldShowBookmarkSigninPromo() ? PromoState.PROMO_SIGNIN_PERSONALIZED
: PromoState.PROMO_NONE;
}
......@@ -215,12 +236,30 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
return PromoState.PROMO_NONE;
}
private void updatePromoState() {
@PromoState
int currentState = calculatePromoState();
if (currentState == mPromoState) {
return;
}
mPromoState = currentState;
if (mProfileDataCache != null) {
mProfileDataCache.removeObserver(this);
}
mProfileDataCache = ProfileDataCache.createProfileDataCache(mContext,
mPromoState == PromoState.PROMO_SYNC_PERSONALIZED
? R.drawable.ic_sync_badge_off_20dp
: 0);
mProfileDataCache.addObserver(this);
}
// AndroidSyncSettingsObserver implementation.
@Override
public void androidSyncSettingsChanged() {
// AndroidSyncSettings calls this method from non-UI threads.
PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
mPromoState = calculatePromoState();
updatePromoState();
triggerPromoUpdate();
});
}
......@@ -228,13 +267,13 @@ class BookmarkPromoHeader implements AndroidSyncSettingsObserver, SignInStateObs
// SignInStateObserver implementation.
@Override
public void onSignedIn() {
mPromoState = calculatePromoState();
updatePromoState();
triggerPromoUpdate();
}
@Override
public void onSignedOut() {
mPromoState = calculatePromoState();
updatePromoState();
triggerPromoUpdate();
}
......
......@@ -21,6 +21,7 @@ import org.chromium.ui.widget.ButtonCompat;
public class PersonalizedSigninPromoView extends LinearLayout {
private ImageView mImage;
private ImageButton mDismissButton;
private TextView mStatus;
private TextView mDescription;
private ButtonCompat mSigninButton;
private Button mChooseAccountButton;
......@@ -35,6 +36,7 @@ public class PersonalizedSigninPromoView extends LinearLayout {
mImage = findViewById(R.id.signin_promo_image);
mDismissButton = findViewById(R.id.signin_promo_close_button);
mStatus = findViewById(R.id.signin_promo_status_message);
mDescription = findViewById(R.id.signin_promo_description);
mSigninButton = findViewById(R.id.signin_promo_signin_button);
mChooseAccountButton = findViewById(R.id.signin_promo_choose_account_button);
......@@ -54,6 +56,13 @@ public class PersonalizedSigninPromoView extends LinearLayout {
return mDismissButton;
}
/**
* @return A reference to the title of the sync promo.
*/
public TextView getStatusMessage() {
return mStatus;
}
/**
* @return A reference to the description of the promo.
*/
......
......@@ -2187,6 +2187,12 @@ To change this setting, <ph name="BEGIN_LINK">&lt;resetlink&gt;</ph>reset sync<p
<message name="IDS_SIGNIN_PROMO_CHOOSE_ANOTHER_ACCOUNT" desc="Button that the user can press if they want to select a different account before signing in. This button is shown below 'Continue as Joe Doe' button that signs user in with default account.">
Choose another account
</message>
<message name="IDS_SIGNIN_PROMO_STATUS_MESSAGE" desc="Title string for 'Turn on sync' sync promos.">
Sync is off
</message>
<message name="IDS_SYNC_PROMO_TURN_ON_SYNC" desc="Button that the user can press if they want to turn on sync with this account.">
Turn on sync
</message>
<message name="IDS_EXTERNAL_APP_LEAVE_INCOGNITO_WARNING" desc="Alert dialog text warning the user (who is currently in incognito mode) that the site they are currently using is going to share data with an external application." formatter_data="android_java">
This site is about to share information with an app outside of incognito mode.
......
e9f89af85ba18833c1eb62aa3654062ab3da1146
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment