Bug 1246238 - Pre: Implement SimpleHelperUI r?sebastian draft
authorAndrzej Hunt <ahunt@mozilla.com>
Wed, 20 Apr 2016 21:27:03 +0200
changeset 354570 0b8ef72dc63c9c6be37e39a794102ea0356e5e8e
parent 354461 a1823d3e691960016d156ed062eb416d2d135707
child 354571 5f1412096f86ac6f3ae6cd9579d0159b3b10b65f
push id16125
push userahunt@mozilla.com
push dateThu, 21 Apr 2016 09:08:44 +0000
reviewerssebastian
bugs1246238, 1236328, 1247689
milestone48.0a1
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);
+
+        ((ImageView) findViewById(R.id.image)).setImageResource(i.getIntExtra(EXTRA_IMAGE, -1));
+
+        ((TextView) findViewById(R.id.title)).setText(i.getIntExtra(EXTRA_TITLE, -1));
+
+        ((TextView) findViewById(R.id.message)).setText(i.getIntExtra(EXTRA_MESSAGE, -1));
+
+        ((Button) findViewById(R.id.button)).setText(i.getIntExtra(EXTRA_BUTTON, -1));
+
+        containerView = findViewById(R.id.container);
+
+        findViewById(R.id.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
@@ -510,16 +510,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>