Bug 1329144 - IntentUtil can extract ActionButton info from Intent draft
authorJulian_Chu <walkingice0204@gmail.com>
Fri, 03 Feb 2017 13:42:13 +0800
changeset 479185 6d31483aae8782aaf77dcbef269ff287f17c5352
parent 479184 9118b6aa2e45efee546b4185be1f30ee3d8813f6
child 479186 16978b1dcb714db50c5409af2d03588444b07a89
child 480254 c4a5707785a5ebf3dd31a3d3dd0a4f69238a1fe1
push id44174
push userbmo:walkingice0204@gmail.com
push dateMon, 06 Feb 2017 07:33:37 +0000
bugs1329144
milestone54.0a1
Bug 1329144 - IntentUtil can extract ActionButton info from Intent To support ActionButton in CustomTabsActivity, information should be extract from intent. MozReview-Commit-ID: 3C19U0EQfV6
mobile/android/base/java/org/mozilla/gecko/customtabs/IntentUtil.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestIntentUtil.java
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/IntentUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/IntentUtil.java
@@ -1,16 +1,18 @@
 /* -*- 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.customtabs;
 
+import android.app.PendingIntent;
 import android.content.Intent;
+import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.customtabs.CustomTabsIntent;
 
 /**
  * A utility class for CustomTabsActivity to extract information from intent.
  * For example, this class helps to extract exit-animation resource id.
@@ -23,16 +25,85 @@ class IntentUtil {
     private static final String PREFIX = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
             ? "android:activity."
             : "android:";
     private static final String KEY_PACKAGE_NAME = PREFIX + "packageName";
     private static final String KEY_ANIM_ENTER_RES_ID = PREFIX + "animEnterRes";
     private static final String KEY_ANIM_EXIT_RES_ID = PREFIX + "animExitRes";
 
     /**
+     * To determine whether the intent has necessary information to build an Action-Button.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return true, if intent has all necessary information.
+     */
+    static boolean hasActionButton(@NonNull Intent intent) {
+        return (getActionButtonBundle(intent) != null)
+                && (getActionButtonIcon(intent) != null)
+                && (getActionButtonDescription(intent) != null)
+                && (getActionButtonPendingIntent(intent) != null);
+    }
+
+    /**
+     * To extract bitmap icon from intent for Action-Button.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return bitmap icon, if any. Otherwise, null.
+     */
+    static Bitmap getActionButtonIcon(@NonNull Intent intent) {
+        final Bundle bundle = getActionButtonBundle(intent);
+        return (bundle == null) ? null : (Bitmap) bundle.getParcelable(CustomTabsIntent.KEY_ICON);
+    }
+
+    /**
+     * To extract description from intent for Action-Button. This description is used for
+     * accessibility.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return description, if any. Otherwise, null.
+     */
+    static String getActionButtonDescription(@NonNull Intent intent) {
+        final Bundle bundle = getActionButtonBundle(intent);
+        return (bundle == null) ? null : bundle.getString(CustomTabsIntent.KEY_DESCRIPTION);
+    }
+
+    /**
+     * To extract pending-intent from intent for Action-Button.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return PendingIntent, if any. Otherwise, null.
+     */
+    static PendingIntent getActionButtonPendingIntent(@NonNull Intent intent) {
+        final Bundle bundle = getActionButtonBundle(intent);
+        return (bundle == null)
+                ? null
+                : (PendingIntent) bundle.getParcelable(CustomTabsIntent.KEY_PENDING_INTENT);
+    }
+
+    /**
+     * To know whether the Action-Button should be tinted.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return true, if Action-Button should be tinted. Default value is false.
+     */
+    static boolean isActionButtonTinted(@NonNull Intent intent) {
+        return intent.getBooleanExtra(CustomTabsIntent.EXTRA_TINT_ACTION_BUTTON, false);
+    }
+
+    /**
+     * To extract extra Action-button bundle from an intent.
+     *
+     * @param intent which to launch a Custom-Tabs-Activity
+     * @return bundle for Action-Button, if any. Otherwise, null.
+     */
+    private static Bundle getActionButtonBundle(@NonNull Intent intent) {
+        return intent.getBundleExtra(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE);
+    }
+
+    /**
      * To get package name of 3rd-party-app from an intent.
      * If the app defined extra exit-animation to use, it should also provide its package name
      * to get correct animation resource.
      *
      * @param intent which to launch a Custom-Tabs-Activity
      * @return package name, if the intent defined extra exit-animation bundle. Otherwise, null.
      */
     static String getAnimationPackageName(@NonNull Intent intent) {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestIntentUtil.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestIntentUtil.java
@@ -1,41 +1,87 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.customtabs;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.support.annotation.AnimRes;
 import android.support.customtabs.CustomTabsIntent;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.Objects;
+
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 
 @RunWith(TestRunner.class)
 public class TestIntentUtil {
 
     private static final String THIRD_PARTY_PACKAGE_NAME = "mozilla.unit.test";
     private Context spyContext;  // 3rd party app context
 
     @Before
     public void setUp() {
         spyContext = spy(RuntimeEnvironment.application);
         doReturn(THIRD_PARTY_PACKAGE_NAME).when(spyContext).getPackageName();
     }
 
     @Test
+    public void testIntentWithActionButton() {
+        // create properties for CustomTabsIntent
+        final String description = "Description";
+        final boolean tinted = true;
+        final Intent actionIntent = new Intent(Intent.ACTION_VIEW);
+        final int reqCode = 0x123;
+        final PendingIntent pendingIntent = PendingIntent.getActivities(spyContext,
+                reqCode,
+                new Intent[]{actionIntent},
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        final Bitmap bitmap = BitmapFactory.decodeResource(
+                spyContext.getResources(),
+                R.drawable.ic_action_settings); // arbitrary icon resource
+
+        final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
+        builder.setActionButton(bitmap, description, pendingIntent, tinted);
+
+        Intent intent = builder.build().intent;
+        Assert.assertTrue(IntentUtil.hasActionButton(intent));
+        Assert.assertEquals(tinted, IntentUtil.isActionButtonTinted(intent));
+        Assert.assertEquals(bitmap, IntentUtil.getActionButtonIcon(intent));
+        Assert.assertEquals(description, IntentUtil.getActionButtonDescription(intent));
+        Assert.assertTrue(
+                Objects.equals(pendingIntent, IntentUtil.getActionButtonPendingIntent(intent)));
+    }
+
+    @Test
+    public void testIntentWithoutActionButton() {
+        final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
+
+        Intent intent = builder.build().intent;
+        Assert.assertFalse(IntentUtil.hasActionButton(intent));
+        Assert.assertFalse(IntentUtil.isActionButtonTinted(intent));
+        Assert.assertNull(IntentUtil.getActionButtonIcon(intent));
+        Assert.assertNull(IntentUtil.getActionButtonDescription(intent));
+        Assert.assertNull(IntentUtil.getActionButtonPendingIntent(intent));
+    }
+
+    @Test
     public void testIntentWithCustomAnimation() {
         @AnimRes final int enterRes = 0x123; // arbitrary number as animation resource id
         @AnimRes final int exitRes = 0x456; // arbitrary number as animation resource id
 
         final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
         builder.setExitAnimations(spyContext, enterRes, exitRes);
         final Intent i = builder.build().intent;