Bug 1246238 - Pre: Implement SimpleHelperUI r=sebastian
authorAndrzej Hunt <ahunt@mozilla.com>
Sat, 23 Apr 2016 10:56:17 +0200
changeset 332386 d0bed027367312449a35fb4f3a50b68a250545d9
parent 332385 6f5e1ec74f4908a610bbe0274e03ff31abc3bd3c
child 332387 f9177e655c8c7c3250087d71c0b6fed5e335e1b5
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssebastian
bugs1246238, 1236328, 1247689
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1246238 - Pre: Implement SimpleHelperUI r=sebastian This provides a basic helper UI that can be customised with images/text. We need a very similar helper for both reader-view offline bookmarking related helpers (Bug 1236328 and Bug 1247689), hence it's useful to have a common class implementing most of the required functionality. Most of the new helper is borrowed from the existing HomeScreenPrompt. I will extract the common functionality in a followup Bug. MozReview-Commit-ID: Byc5VnVFffj
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/java/org/mozilla/gecko/promotion/SimpleHelperUI.java
mobile/android/base/moz.build
mobile/android/services/src/main/res/layout/simple_helper_ui.xml
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -154,16 +154,20 @@
         </activity-alias>
 
         <service android:name="org.mozilla.gecko.GeckoService" />
 
         <activity android:name="org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt"
                   android:launchMode="singleTop"
                   android:theme="@style/OverlayActivity" />
 
+        <activity android:name="org.mozilla.gecko.promotion.SimpleHelperUI"
+                  android:launchMode="singleTop"
+                  android:theme="@style/OverlayActivity" />
+
         <activity android:name="org.mozilla.gecko.promotion.HomeScreenPrompt"
                   android:launchMode="singleTop"
                   android:theme="@style/OverlayActivity" />
 
         <!-- The main reason for the Tab Queue build flag is to not mess with the VIEW intent filter
              before the rest of the plumbing is in place -->
 
         <service android:name="org.mozilla.gecko.tabqueue.TabQueueService" />
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/promotion/SimpleHelperUI.java
@@ -0,0 +1,191 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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.promotion;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.StringRes;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.mozilla.gecko.Locales;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
+
+/**
+ * Generic HelperUI (prompt) that can be populated with an image, title, message and action button.
+ * See show() for usage. This is run as an Activity, results must be handled in the parent Activities
+ * onActivityResult().
+ */
+public class SimpleHelperUI extends Locales.LocaleAwareActivity {
+    private View containerView;
+
+    private boolean isAnimating;
+
+    private String mTelemetryExtra;
+
+    private static final String EXTRA_TELEMETRYEXTRA = "telemetryextra";
+    private static final String EXTRA_TITLE = "title";
+    private static final String EXTRA_MESSAGE = "message";
+    private static final String EXTRA_IMAGE = "image";
+    private static final String EXTRA_BUTTON = "button";
+    private static final String EXTRA_RESULTCODE_POSITIVE = "positive";
+    private static final String EXTRA_RESULTCODE_NEGATIVE = "negative";
+
+
+    /**
+     * Show a generic helper UI/prompt.
+     *
+     * @param owner The owning Activity, the result of this prompt will be delivered to its
+     *              onActivityResult().
+     * @param requestCode The request code for the Activity that will be created, this is passed to
+     *                    onActivityResult() to identify the prompt.
+     *
+     * @param positiveResultCode The result code passed to onActivityResult() when the button has
+     *                           been pressed.
+     * @param negativeResultCode The result code passed to onActivityResult() when the prompt was
+     *                           dismissed, either by pressing outside the prompt or by pressing the
+     *                           device back button.
+     */
+    public static void show(Activity owner, String telemetryExtra,
+                            int requestCode,
+                            @StringRes int title, @StringRes int message,
+                            @DrawableRes int image, @StringRes int buttonText,
+                            int positiveResultCode, int negativeResultCode) {
+        Intent intent = new Intent(owner, SimpleHelperUI.class);
+
+        intent.putExtra(EXTRA_TELEMETRYEXTRA, telemetryExtra);
+
+        intent.putExtra(EXTRA_TITLE, title);
+        intent.putExtra(EXTRA_MESSAGE, message);
+
+        intent.putExtra(EXTRA_IMAGE, image);
+        intent.putExtra(EXTRA_BUTTON, buttonText);
+
+        intent.putExtra(EXTRA_RESULTCODE_POSITIVE, positiveResultCode);
+        intent.putExtra(EXTRA_RESULTCODE_NEGATIVE, negativeResultCode);
+
+        owner.startActivityForResult(intent, requestCode);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mTelemetryExtra = getIntent().getStringExtra(EXTRA_TELEMETRYEXTRA);
+
+        setupViews();
+
+        slideIn();
+    }
+
+    private void setupViews() {
+        final Intent i = getIntent();
+
+        setContentView(R.layout.simple_helper_ui);
+
+        containerView = findViewById(R.id.container);
+
+        ((ImageView) findViewById(R.id.image)).setImageResource(i.getIntExtra(EXTRA_IMAGE, 0));
+
+        ((TextView) findViewById(R.id.title)).setText(i.getIntExtra(EXTRA_TITLE, 0));
+
+        ((TextView) findViewById(R.id.message)).setText(i.getIntExtra(EXTRA_MESSAGE, 0));
+
+        final Button button = ((Button) findViewById(R.id.button));
+        button.setText(i.getIntExtra(EXTRA_BUTTON, 0));
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                slideOut();
+
+                Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.BUTTON, mTelemetryExtra);
+
+                setResult(i.getIntExtra(EXTRA_RESULTCODE_POSITIVE, -1));
+            }
+        });
+    }
+
+    private void slideIn() {
+        containerView.setTranslationY(500);
+        containerView.setAlpha(0);
+
+        final Animator translateAnimator = ObjectAnimator.ofFloat(containerView, "translationY", 0);
+        translateAnimator.setDuration(400);
+
+        final Animator alphaAnimator = ObjectAnimator.ofFloat(containerView, "alpha", 1);
+        alphaAnimator.setStartDelay(200);
+        alphaAnimator.setDuration(600);
+
+        final AnimatorSet set = new AnimatorSet();
+        set.playTogether(alphaAnimator, translateAnimator);
+        set.setStartDelay(400);
+
+        set.start();
+    }
+
+    private void slideOut() {
+        if (isAnimating) {
+            return;
+        }
+
+        isAnimating = true;
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(containerView, "translationY", containerView.getHeight());
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                finish();
+            }
+
+        });
+        animator.start();
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+
+        // Don't perform an activity-dismiss animation.
+        overridePendingTransition(0, 0);
+    }
+
+    @Override
+    public void onBackPressed() {
+        slideOut();
+
+        Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.BACK, mTelemetryExtra);
+
+        setResult(getIntent().getIntExtra(EXTRA_RESULTCODE_NEGATIVE, -1));
+
+    }
+
+    /**
+     * User clicked outside of the prompt.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        slideOut();
+
+        // Not really an action triggered by the "back" button but with the same effect: Finishing this
+        // activity and going back to the previous one.
+        Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.BACK, mTelemetryExtra);
+
+        setResult(getIntent().getIntExtra(EXTRA_RESULTCODE_NEGATIVE, -1));
+
+        return true;
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -502,16 +502,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'preferences/SearchPreferenceCategory.java',
     'preferences/SetHomepagePreference.java',
     'preferences/SyncPreference.java',
     'PrefsHelper.java',
     'PrintHelper.java',
     'PrivateTab.java',
     'promotion/AddToHomeScreenPromotion.java',
     'promotion/HomeScreenPrompt.java',
+    'promotion/SimpleHelperUI.java',
     'prompts/ColorPickerInput.java',
     'prompts/IconGridInput.java',
     'prompts/IntentChooserPrompt.java',
     'prompts/IntentHandler.java',
     'prompts/Prompt.java',
     'prompts/PromptInput.java',
     'prompts/PromptListAdapter.java',
     'prompts/PromptListItem.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/services/src/main/res/layout/simple_helper_ui.xml
@@ -0,0 +1,61 @@
+<?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:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@android:color/white"
+        android:layout_gravity="bottom|center"
+        android:clickable="true"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@+id/image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="40dp"
+            android:layout_marginBottom="40dp"
+            android:scaleType="fitCenter"
+            android:layout_gravity="center"
+            android:adjustViewBounds="true"/>
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="@dimen/firstrun_content_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:textAppearance="@style/TextAppearance.FirstrunLight.Main"/>
+
+
+        <TextView
+            android:id="@+id/message"
+            android:layout_width="@dimen/firstrun_content_width"
+            android:layout_height="wrap_content"
+            android:paddingTop="20dp"
+            android:paddingBottom="30dp"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:textAppearance="@style/TextAppearance.FirstrunRegular.Body"
+            android:singleLine="false"/>
+
+        <Button
+            android:id="@+id/button"
+            style="@style/Widget.Firstrun.Button"
+            android:background="@drawable/button_background_action_orange_round"
+            android:layout_gravity="center"
+            android:layout_marginBottom="30dp"/>
+
+    </LinearLayout>
+</merge>