Bug 781262: Replaced sync box on about:home with promo box abstraction. r=sriram
authorMichael Comella <michael.l.comella@gmail.com>
Mon, 20 Aug 2012 16:10:00 +1200
changeset 102793 fb8c41ccafedafc7637136bf5bbbbdd48ef700b1
parent 102792 ca2c1aa1acbc28d78407cff3f16dfb39e3bdbeab
child 102794 bface603ef7211eb6c637f7ed0dd0b59b7df7dbd
push id1016
push userbmcbride@mozilla.com
push dateTue, 21 Aug 2012 07:43:16 +0000
treeherderfx-team@bface603ef72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssriram
bugs781262
milestone17.0a1
Bug 781262: Replaced sync box on about:home with promo box abstraction. r=sriram Bug 781262: Replaced sync box on about:home with promo box abstraction. r=sriram
mobile/android/base/AboutHomeContent.java
mobile/android/base/AboutHomePromoBox.java
mobile/android/base/GeckoViewsFactory.java
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_sync_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_sync_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_sync_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_sync_pressed_bg.9.png
mobile/android/base/resources/drawable/abouthome_promo_box.xml
mobile/android/base/resources/drawable/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable/abouthome_sync_bg.9.png
mobile/android/base/resources/drawable/abouthome_sync_box.xml
mobile/android/base/resources/drawable/abouthome_sync_pressed_bg.9.png
mobile/android/base/resources/layout-xlarge-land-v11/abouthome_content.xml.in
mobile/android/base/resources/layout/abouthome_content.xml.in
mobile/android/base/resources/layout/abouthome_promo_box.xml
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -80,16 +80,17 @@ public class AboutHomeContent extends Sc
     private LayoutInflater mInflater;
 
     private AccountManager mAccountManager;
     private OnAccountsUpdateListener mAccountListener = null;
 
     protected SimpleCursorAdapter mTopSitesAdapter;
     protected GridView mTopSitesGrid;
 
+    private AboutHomePromoBox mPromoBox;
     protected AboutHomeSection mAddons;
     protected AboutHomeSection mLastTabs;
     protected AboutHomeSection mRemoteTabs;
 
     private View.OnClickListener mRemoteTabClickListener;
     private OnInterceptTouchListener mOnInterceptTouchListener;
 
     public interface UriLoadCallback {
@@ -150,16 +151,17 @@ public class AboutHomeContent extends Sc
                 String spec = c.getString(c.getColumnIndex(URLColumns.URL));
                 Log.i(LOGTAG, "clicked: " + spec);
 
                 if (mUriLoadCallback != null)
                     mUriLoadCallback.callback(spec);
             }
         });
 
+        mPromoBox = (AboutHomePromoBox) findViewById(R.id.promo_box);
         mAddons = (AboutHomeSection) findViewById(R.id.recommended_addons);
         mLastTabs = (AboutHomeSection) findViewById(R.id.last_tabs);
         mRemoteTabs = (AboutHomeSection) findViewById(R.id.remote_tabs);
 
         TextView allTopSitesText = (TextView) findViewById(R.id.all_top_sites_text);
         allTopSitesText.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 mActivity.showAwesomebar(AwesomeBar.Target.CURRENT_TAB);
@@ -174,38 +176,16 @@ public class AboutHomeContent extends Sc
         });
 
         mRemoteTabs.setOnMoreTextClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 mActivity.showRemoteTabs();
             }
         });
 
-        TextView syncTextView = (TextView) findViewById(R.id.sync_text);
-        String syncText = syncTextView.getText().toString() + " \u00BB";
-        String boldName = getContext().getResources().getString(R.string.abouthome_sync_bold_name);
-        int styleIndex = syncText.indexOf(boldName);
-
-        // Highlight any occurrence of "Firefox Sync" in the string
-        // with a bold style.
-        if (styleIndex >= 0) {
-            SpannableString spannableText = new SpannableString(syncText);
-            spannableText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), styleIndex, styleIndex + 12, 0);
-            syncTextView.setText(spannableText, TextView.BufferType.SPANNABLE);
-        }
-
-        LinearLayout syncBox = (LinearLayout) findViewById(R.id.sync_box);
-        syncBox.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                Context context = v.getContext();
-                Intent intent = new Intent(context, SetupSyncActivity.class);
-                context.startActivity(intent);
-            }
-        });
-
         setTopSitesConstants();
     }
 
     public void onDestroy() {
         if (mAccountListener != null) {
             mAccountManager.removeOnAccountsUpdatedListener(mAccountListener);
             mAccountListener = null;
         }
@@ -227,31 +207,33 @@ public class AboutHomeContent extends Sc
         int visibilityWithoutTopSites = visible && !hasTopSites ? View.VISIBLE : View.GONE;
 
         findViewById(R.id.top_sites_grid).setVisibility(visibilityWithTopSites);
         findViewById(R.id.top_sites_title).setVisibility(visibility);
         findViewById(R.id.all_top_sites_text).setVisibility(visibilityWithTopSites);
         findViewById(R.id.no_top_sites_text).setVisibility(visibilityWithoutTopSites);
     }
 
-    private void setSyncVisibility(boolean visible) {
-        int visibility = visible ? View.VISIBLE : View.GONE;
-        findViewById(R.id.sync_box).setVisibility(visibility);
+    private void setPromoBoxVisibility(boolean visible, AboutHomePromoBox.Type type) {
+        if (visible)
+            mPromoBox.show(type);
+        else
+            mPromoBox.hide();
     }
 
     private void updateLayout(GeckoApp.StartupMode startupMode, boolean syncIsSetup) {
         // The idea here is that we only show the sync invitation
         // on the very first run. Show sync banner below the top
         // sites section in all other cases.
 
         boolean hasTopSites = mTopSitesAdapter.getCount() > 0;
         boolean isFirstRun = (startupMode == GeckoApp.StartupMode.NEW_PROFILE);
 
         setTopSitesVisibility(!isFirstRun || hasTopSites, hasTopSites);
-        setSyncVisibility(!syncIsSetup);
+        setPromoBoxVisibility(!syncIsSetup, AboutHomePromoBox.Type.SYNC);
     }
 
     private void updateLayoutForSync() {
         final GeckoApp.StartupMode startupMode = mActivity.getStartupMode();
         final boolean syncIsSetup = SyncAccounts.syncAccountsExist(mContext);
 
         post(new Runnable() {
             public void run() {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AboutHomePromoBox.java
@@ -0,0 +1,126 @@
+/* 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;
+
+import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.text.SpannableString;
+import android.text.style.StyleSpan;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * A promotional box for the about:home page. The layout contains an ImageView to the left of a
+ * TextView whose resources may be overidden to display custom values for a new type of promo box.
+ * To do this, add a new Type value and update show() to call setResources() for your values -
+ * including a set[Box Type]Resources() helper method is recommended.
+ */
+public class AboutHomePromoBox extends LinearLayout implements View.OnClickListener {
+    private static final String LOGTAG = "AboutHomePromoBox";
+
+    public enum Type { SYNC };
+
+    private Type mType;
+
+    private final Context mContext;
+    private final TextView mTextView;
+    private final ImageView mImageView;
+
+    // Use setResources() to set these variables for each PromoBox type.
+    private int mTextResource;
+    private int mBoldTextResource;
+    private int mImageResource;
+
+    public AboutHomePromoBox(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        inflater.inflate(R.layout.abouthome_promo_box, this);
+
+        mContext = context;
+        mTextView = (TextView) findViewById(R.id.text);
+        mImageView = (ImageView) findViewById(R.id.icon);
+        setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View v) {
+        Log.d(LOGTAG, "I work out.");
+        switch (mType) {
+            case SYNC:
+                final Context context = v.getContext();
+                final Intent intent = new Intent(context, SetupSyncActivity.class);
+                context.startActivity(intent);
+                break;
+
+            default:
+                Log.e(LOGTAG, "Invalid type was set when promo box was clicked.");
+                break;
+        }
+    }
+
+    /**
+     * Shows the specified promo box. If a promo box is already active, it will be overidden with a
+     * promo box of the specified type.
+     */
+    public void show(Type type) {
+        mType = type;
+        switch (type) {
+            case SYNC:
+                setSyncResources();
+                break;
+
+            default:
+                Log.e(LOGTAG, "Invalid PromoBoxType specified.");
+                break;
+        }
+        updateViewResources();
+        setVisibility(View.VISIBLE);
+    }
+
+    public void hide() {
+        setVisibility(View.GONE);
+        mType = null;
+    }
+
+    private void setResources(int textResource, int boldTextResource, int imageResource) {
+        mTextResource = textResource;
+        mBoldTextResource = boldTextResource;
+        mImageResource = imageResource;
+    }
+
+    private void updateViewResources() {
+        updateTextViewResources();
+        mImageView.setImageResource(mImageResource);
+    }
+
+    private void updateTextViewResources() {
+        final String promoText = mContext.getResources().getString(mTextResource) + " \u00BB";
+
+        final String boldName = mContext.getResources().getString(mBoldTextResource);
+        final int styleIndex = promoText.indexOf(boldName);
+        if (styleIndex < 0)
+            mTextView.setText(promoText);
+        else {
+            final SpannableString spannableText = new SpannableString(promoText);
+            spannableText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), styleIndex,
+                    styleIndex + boldName.length(), 0);
+            mTextView.setText(spannableText, TextView.BufferType.SPANNABLE);
+        }
+    }
+
+    // Type.SYNC: Setup Firefox sync.
+    private void setSyncResources() {
+        setResources(R.string.abouthome_about_sync, R.string.abouthome_sync_bold_name,
+                R.drawable.abouthome_sync_logo);
+    }
+}
--- a/mobile/android/base/GeckoViewsFactory.java
+++ b/mobile/android/base/GeckoViewsFactory.java
@@ -33,17 +33,19 @@ public final class GeckoViewsFactory imp
         if (!TextUtils.isEmpty(name) && name.startsWith(GECKO_VIEW_IDENTIFIER)) {
             String viewName = name.substring(GECKO_VIEW_IDENTIFIER_LENGTH);
 
             if (TextUtils.isEmpty(viewName))
                 return null;
         
             Log.i(LOGTAG, "Creating custom Gecko view: " + viewName);
 
-            if (TextUtils.equals(viewName, "AboutHomeSection"))
+            if (TextUtils.equals(viewName, "AboutHomePromoBox"))
+                return new AboutHomePromoBox(context, attrs);
+            else if (TextUtils.equals(viewName, "AboutHomeSection"))
                 return new AboutHomeSection(context, attrs);
             else if (TextUtils.equals(viewName, "AwesomeBarTabs"))
                 return new AwesomeBarTabs(context, attrs);
             else if (TextUtils.equals(viewName, "FormAssistPopup"))
                 return new FormAssistPopup(context, attrs);
             else if (TextUtils.equals(viewName, "LinkTextView"))
                 return new LinkTextView(context, attrs);
             else if (TextUtils.equals(viewName, "FindInPageBar"))
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -31,16 +31,17 @@ UTIL_JAVA_FILES := \
   INIParser.java \
   INISection.java \
   util/EventDispatcher.java \
   util/FloatUtils.java \
   $(NULL)
 
 FENNEC_JAVA_FILES = \
   AboutHomeContent.java \
+  AboutHomePromoBox.java \
   AboutHomeSection.java \
   ActivityHandlerHelper.java \
   AndroidImport.java \
   AndroidImportPreference.java \
   AlertNotification.java \
   AwesomeBar.java \
   AwesomebarResultHandler.java \
   AwesomeBarTabs.java \
@@ -328,16 +329,17 @@ RES_LAYOUT = \
   res/layout/tabs_panel_toolbar.xml \
   res/layout/tabs_panel_toolbar_menu.xml \
   res/layout/tabs_row.xml \
   res/layout/tabs_tray.xml \
   res/layout/list_item_header.xml \
   res/layout/select_dialog_list.xml \
   res/layout/abouthome_addon_row.xml \
   res/layout/abouthome_last_tabs_row.xml \
+  res/layout/abouthome_promo_box.xml \
   res/layout/abouthome_section.xml \
   res/layout/abouthome_remote_tab_row.xml \
   res/layout/abouthome_topsite_item.xml \
   res/layout/validation_message.xml \
   $(NULL)
  
 RES_LAYOUT_LAND_V14 = \
   res/layout-land-v14/browser_toolbar.xml \
@@ -414,19 +416,19 @@ RES_DRAWABLE_NODPI = \
   res/drawable-nodpi/tabs_tray_selected_bg.png \
   $(NULL)
 
 RES_DRAWABLE_BASE = \
   res/drawable/favicon.png \
   res/drawable/folder.png \
   res/drawable/abouthome_icon.png \
   res/drawable/abouthome_logo.png \
+  res/drawable/abouthome_promo_box_bg.9.png \
   res/drawable/abouthome_sync_logo.png \
-  res/drawable/abouthome_sync_bg.9.png \
-  res/drawable/abouthome_sync_pressed_bg.9.png \
+  res/drawable/abouthome_promo_box_pressed_bg.9.png \
   res/drawable/abouthome_thumbnail.png \
   res/drawable/address_bar_bg_shadow.png \
   res/drawable/alert_addon.png \
   res/drawable/alert_app.png \
   res/drawable/alert_download.png \
   res/drawable/awesomebar_tab_center.9.png \
   res/drawable/awesomebar_tab_left.9.png \
   res/drawable/awesomebar_tab_right.9.png \
@@ -498,19 +500,19 @@ RES_DRAWABLE_LDPI = \
 
 RES_DRAWABLE_HDPI = \
   res/drawable-hdpi/favicon.png \
   res/drawable-hdpi/folder.png \
   res/drawable-hdpi/home_bg.png \
   res/drawable-hdpi/home_star.png \
   res/drawable-hdpi/abouthome_icon.png \
   res/drawable-hdpi/abouthome_logo.png \
+  res/drawable-hdpi/abouthome_promo_box_bg.9.png \
   res/drawable-hdpi/abouthome_sync_logo.png \
-  res/drawable-hdpi/abouthome_sync_bg.9.png \
-  res/drawable-hdpi/abouthome_sync_pressed_bg.9.png \
+  res/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png \
   res/drawable-hdpi/abouthome_thumbnail.png \
   res/drawable-hdpi/address_bar_bg_shadow.png \
   res/drawable-hdpi/alert_addon.png \
   res/drawable-hdpi/alert_app.png \
   res/drawable-hdpi/alert_download.png \
   res/drawable-hdpi/awesomebar_tab_center.9.png \
   res/drawable-hdpi/awesomebar_tab_left.9.png \
   res/drawable-hdpi/awesomebar_tab_right.9.png \
@@ -564,19 +566,19 @@ RES_DRAWABLE_HDPI = \
   $(addprefix res/drawable-hdpi/,$(notdir $(SYNC_RES_DRAWABLE_HDPI))) \
   $(NULL)
 
 RES_DRAWABLE_XHDPI = \
   res/drawable-xhdpi/favicon.png \
   res/drawable-xhdpi/folder.png \
   res/drawable-xhdpi/abouthome_icon.png \
   res/drawable-xhdpi/abouthome_logo.png \
+  res/drawable-xhdpi/abouthome_promo_box_bg.9.png \
   res/drawable-xhdpi/abouthome_sync_logo.png \
-  res/drawable-xhdpi/abouthome_sync_bg.9.png \
-  res/drawable-xhdpi/abouthome_sync_pressed_bg.9.png \
+  res/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png \
   res/drawable-xhdpi/abouthome_thumbnail.png \
   res/drawable-xhdpi/address_bar_bg_curve.png \
   res/drawable-xhdpi/address_bar_bg_shadow.png \
   res/drawable-xhdpi/address_bar_texture_port.png \
   res/drawable-xhdpi/address_bar_url_default.9.png \
   res/drawable-xhdpi/address_bar_url_pressed.9.png \
   res/drawable-xhdpi/alert_addon.png \
   res/drawable-xhdpi/alert_app.png \
@@ -953,17 +955,17 @@ FENNEC_PP_JAVA_FILES += CrashReporter.ja
 MOZ_ANDROID_DRAWABLES += mobile/android/base/resources/drawable/crash_reporter.png
 RES_LAYOUT += res/layout/crash_reporter.xml
 endif
 
 MOZ_ANDROID_DRAWABLES += \
   $(SYNC_RES_DRAWABLE)                                                          \
   mobile/android/base/resources/drawable/abouthome_bg_repeat.xml                \
   mobile/android/base/resources/drawable/abouthome_divider.xml                  \
-  mobile/android/base/resources/drawable/abouthome_sync_box.xml                 \
+  mobile/android/base/resources/drawable/abouthome_promo_box.xml                \
   mobile/android/base/resources/drawable/action_bar_button.xml                  \
   mobile/android/base/resources/drawable/address_bar_bg.xml                     \
   mobile/android/base/resources/drawable/address_bar_bg_shadow_repeat.xml       \
   mobile/android/base/resources/drawable/autocomplete_list_bg.9.png             \
   mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml           \
   mobile/android/base/resources/drawable/awesomebar_tab_selected.xml            \
   mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml          \
   mobile/android/base/resources/drawable/desktop_notification.png               \
rename from mobile/android/base/resources/drawable-hdpi/abouthome_sync_bg.9.png
rename to mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_bg.9.png
rename from mobile/android/base/resources/drawable-hdpi/abouthome_sync_pressed_bg.9.png
rename to mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png
rename from mobile/android/base/resources/drawable-xhdpi/abouthome_sync_bg.9.png
rename to mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_bg.9.png
rename from mobile/android/base/resources/drawable-xhdpi/abouthome_sync_pressed_bg.9.png
rename to mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png
rename from mobile/android/base/resources/drawable/abouthome_sync_box.xml
rename to mobile/android/base/resources/drawable/abouthome_promo_box.xml
--- a/mobile/android/base/resources/drawable/abouthome_sync_box.xml
+++ b/mobile/android/base/resources/drawable/abouthome_promo_box.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true" android:drawable="@drawable/abouthome_sync_pressed_bg"/>
-    <item android:drawable="@drawable/abouthome_sync_bg"/>
+    <item android:state_pressed="true" android:drawable="@drawable/abouthome_promo_box_pressed_bg"/>
+    <item android:drawable="@drawable/abouthome_promo_box_bg"/>
 
 </selector>
rename from mobile/android/base/resources/drawable/abouthome_sync_bg.9.png
rename to mobile/android/base/resources/drawable/abouthome_promo_box_bg.9.png
rename from mobile/android/base/resources/drawable/abouthome_sync_pressed_bg.9.png
rename to mobile/android/base/resources/drawable/abouthome_promo_box_pressed_bg.9.png
--- a/mobile/android/base/resources/layout-xlarge-land-v11/abouthome_content.xml.in
+++ b/mobile/android/base/resources/layout-xlarge-land-v11/abouthome_content.xml.in
@@ -64,47 +64,28 @@
                                             android:text="@string/abouthome_top_sites_browse"
                                             android:layout_width="fill_parent"
                                             android:layout_height="30dip"
                                             android:layout_marginTop="7dip"
                                             android:textColor="#22629e"
                                             android:textSize="12sp"
                                             android:gravity="top|center_horizontal"/>
 
-                <LinearLayout android:id="@+id/sync_box"
-                              android:background="@drawable/abouthome_sync_box"
-                              android:orientation="horizontal"
-                              android:layout_width="fill_parent"
-                              android:layout_height="wrap_content"
-                              android:layout_marginLeft="12dp"
-                              android:layout_marginRight="12dp"
-                              android:layout_marginTop="17dp"
-                              android:layout_marginBottom="14dp"
-                              android:gravity="center"
-                              android:clickable="true"
-                              android:visibility="gone">
-
-                    <ImageView android:id="@+id/sync_logo"
-                               android:src="@drawable/abouthome_sync_logo"
-                               android:layout_width="wrap_content"
-                               android:layout_height="wrap_content"
-                               android:layout_weight="0"
-                               android:gravity="left|center_vertical"/>
-
-                    <TextView android:id="@+id/sync_text"
-                              android:text="@string/abouthome_about_sync"
-                              android:layout_width="0dp"
-                              android:layout_height="wrap_content"
-                              android:layout_weight="1"
-                              android:layout_marginLeft="7dp"
-                              android:gravity="center"
-                              android:textSize="15sp"
-                              android:textColor="#FFFFFF"/>
-
-                </LinearLayout>
+            <org.mozilla.gecko.AboutHomePromoBox android:id="@+id/promo_box"
+                                                 android:orientation="horizontal"
+                                                 android:background="@drawable/abouthome_promo_box"
+                                                 android:layout_width="fill_parent"
+                                                 android:layout_height="wrap_content"
+                                                 android:layout_marginLeft="12dp"
+                                                 android:layout_marginRight="12dp"
+                                                 android:layout_marginTop="17dp"
+                                                 android:layout_marginBottom="14dp"
+                                                 android:gravity="center"
+                                                 android:clickable="true"
+                                                 android:visibility="gone"/>
 
         </LinearLayout>
 
         <RelativeLayout android:layout_width="0dp"
                         android:layout_height="fill_parent"
                         android:layout_weight="0.4"
                         android:layout_marginLeft="@dimen/abouthome_gutter_small"
                         android:layout_marginRight="@dimen/abouthome_gutter_large">
--- a/mobile/android/base/resources/layout/abouthome_content.xml.in
+++ b/mobile/android/base/resources/layout/abouthome_content.xml.in
@@ -71,47 +71,28 @@
                                             android:text="@string/abouthome_top_sites_browse"
                                             android:layout_width="fill_parent"
                                             android:layout_height="30dip"
                                             android:layout_marginTop="7dip"
                                             android:textColor="#22629e"
                                             android:textSize="12sp"
                                             android:gravity="top|center_horizontal"/>
 
-            <LinearLayout android:id="@+id/sync_box"
-                          android:background="@drawable/abouthome_sync_box"
-                          android:orientation="horizontal"
-                          android:layout_width="fill_parent"
-                          android:layout_height="wrap_content"
-                          android:layout_marginLeft="12dp"
-                          android:layout_marginRight="12dp"
-                          android:layout_marginTop="17dp"
-                          android:layout_marginBottom="14dp"
-                          android:gravity="center"
-                          android:clickable="true"
-                          android:visibility="gone">
-
-                <ImageView android:id="@+id/sync_logo"
-                           android:src="@drawable/abouthome_sync_logo"
-                           android:layout_width="wrap_content"
-                           android:layout_height="wrap_content"
-                           android:layout_weight="0"
-                           android:gravity="left|center_vertical"/>
-
-                <TextView android:id="@+id/sync_text"
-                          android:text="@string/abouthome_about_sync"
-                          android:layout_width="0dp"
-                          android:layout_height="wrap_content"
-                          android:layout_weight="1"
-                          android:layout_marginLeft="7dp"
-                          android:gravity="center"
-                          android:textSize="15sp"
-                          android:textColor="#FFFFFF"/>
-
-            </LinearLayout>
+            <org.mozilla.gecko.AboutHomePromoBox android:id="@+id/promo_box"
+                                                 android:orientation="horizontal"
+                                                 android:background="@drawable/abouthome_promo_box"
+                                                 android:layout_width="fill_parent"
+                                                 android:layout_height="wrap_content"
+                                                 android:layout_marginLeft="12dp"
+                                                 android:layout_marginRight="12dp"
+                                                 android:layout_marginTop="17dp"
+                                                 android:layout_marginBottom="14dp"
+                                                 android:gravity="center"
+                                                 android:clickable="true"
+                                                 android:visibility="gone"/>
 
             <org.mozilla.gecko.AboutHomeSection android:id="@+id/last_tabs"
                                                 android:layout_width="fill_parent"
                                                 android:layout_height="wrap_content"
                                                 android:visibility="gone"
                                                 gecko:title="@string/abouthome_last_tabs_title"
                                                 gecko:more_text="@string/abouthome_last_tabs_open"/>
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/abouthome_promo_box.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:gecko="http://schemas.android.com/apk/res/@ANDROID_PACKAGE_NAME@">
+
+    <ImageView android:id="@+id/icon"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_weight="0"
+               android:gravity="left|center_vertical"/>
+
+    <TextView android:id="@+id/text"
+              android:layout_width="0dp"
+              android:layout_height="wrap_content"
+              android:layout_weight="1"
+              android:layout_marginLeft="7dp"
+              android:gravity="center"
+              android:textSize="15sp"
+              android:textColor="#FFFFFF"/>
+
+</merge>