Make ConfirmationActivity display duration configurable
Allow configuration of the duration that ConfigurationActivity should be visible through intent extra data.
Bug: 143577686
Test: ./gradlew wear:wear:connectedCheck --info --daemon -Pandroid.testInstrumentationRunnerArguments.class=androidx.wear.widget.ConfirmationActivityTest and androidx.wear.widget.ConfirmationActivityTest (from within Android studio against a Cuttlefish AVD and a Watch round emulator)
Change-Id: Ibc780bc5c7f8ce7a72a2fe022a498061682dd910
diff --git a/wear/wear/api/1.1.0-alpha01.txt b/wear/wear/api/1.1.0-alpha01.txt
index f6415c8..b6b0a6d 100644
--- a/wear/wear/api/1.1.0-alpha01.txt
+++ b/wear/wear/api/1.1.0-alpha01.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/api/current.txt b/wear/wear/api/current.txt
index f6415c8..b6b0a6d 100644
--- a/wear/wear/api/current.txt
+++ b/wear/wear/api/current.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/api/public_plus_experimental_1.1.0-alpha01.txt b/wear/wear/api/public_plus_experimental_1.1.0-alpha01.txt
index f6415c8..b6b0a6d 100644
--- a/wear/wear/api/public_plus_experimental_1.1.0-alpha01.txt
+++ b/wear/wear/api/public_plus_experimental_1.1.0-alpha01.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/api/public_plus_experimental_current.txt b/wear/wear/api/public_plus_experimental_current.txt
index f6415c8..b6b0a6d 100644
--- a/wear/wear/api/public_plus_experimental_current.txt
+++ b/wear/wear/api/public_plus_experimental_current.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/api/restricted_1.1.0-alpha01.txt b/wear/wear/api/restricted_1.1.0-alpha01.txt
index 9db49de..79c0d86 100644
--- a/wear/wear/api/restricted_1.1.0-alpha01.txt
+++ b/wear/wear/api/restricted_1.1.0-alpha01.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/api/restricted_current.txt b/wear/wear/api/restricted_current.txt
index 9db49de..79c0d86 100644
--- a/wear/wear/api/restricted_current.txt
+++ b/wear/wear/api/restricted_current.txt
@@ -5,6 +5,8 @@
ctor public ConfirmationActivity();
method protected void onAnimationFinished();
method public void onCreate(android.os.Bundle!);
+ field public static final int DEFAULT_ANIMATION_DURATION_MS = 1000; // 0x3e8
+ field public static final String EXTRA_ANIMATION_DURATION_MS = "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
field public static final String EXTRA_ANIMATION_TYPE = "androidx.wear.activity.extra.ANIMATION_TYPE";
field public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
field public static final int FAILURE_ANIMATION = 3; // 0x3
diff --git a/wear/wear/src/androidTest/AndroidManifest.xml b/wear/wear/src/androidTest/AndroidManifest.xml
index 9bbf118..a62627b 100644
--- a/wear/wear/src/androidTest/AndroidManifest.xml
+++ b/wear/wear/src/androidTest/AndroidManifest.xml
@@ -83,6 +83,16 @@
</intent-filter>
</activity>
+ <activity android:name="androidx.wear.widget.ConfirmationActivityTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="androidx.wear.activity.ConfirmationActivity">
+ </activity>
+
<!-- Test app is iOS compatible. -->
<meta-data
android:name="com.google.android.wearable.standalone"
diff --git a/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTest.java b/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTest.java
new file mode 100644
index 0000000..4c8791f
--- /dev/null
+++ b/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.widget;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.widget.Button;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.wear.activity.ConfirmationActivity;
+import androidx.wear.test.R;
+import androidx.wear.widget.util.WakeLockRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ConfirmationActivityTest {
+
+ // Number of milliseconds before the end of the duration period that we should check that the
+ // ConfirmationActivity still has focus
+ private static final int MILLIS_BEFORE_END_OF_DURATION = 150;
+
+ // Number of milliseconds after the end of the duration period that we should wait before the
+ // ConfirmationActivity still lost focus
+ private static final int MILLIS_AFTER_END_OF_DURATION = 150;
+
+ // Number of milliseconds to wait for the confirmation activity to display initially
+ private static final int MILLIS_TO_WAIT_FOR_ACTIVITY_TO_BE_DRAWN = 100;
+
+ @Rule
+ public final WakeLockRule wakeLock = new WakeLockRule();
+
+ @Rule
+ public final ActivityTestRule<ConfirmationActivityTestActivity> mActivityRule =
+ new ActivityTestRule<>(ConfirmationActivityTestActivity.class, true, true);
+
+ @Test
+ public void testConfirmationDialogShownForDefaultDuration() throws Throwable {
+ testConfirmationDialogShownForConfiguredDuration(
+ ConfirmationActivity.DEFAULT_ANIMATION_DURATION_MS);
+ }
+
+ @Test
+ public void testConfirmationDialogShownForShortDuration() throws Throwable {
+ int testDuration = ConfirmationActivity.DEFAULT_ANIMATION_DURATION_MS / 2;
+ // Check that the structure of the test is still valid
+ assertTrue(testDuration
+ > (MILLIS_BEFORE_END_OF_DURATION + MILLIS_TO_WAIT_FOR_ACTIVITY_TO_BE_DRAWN));
+
+ testConfirmationDialogShownForConfiguredDuration(testDuration);
+ }
+
+ @Test
+ public void testConfirmationDialogShownForLongerDuration() throws Throwable {
+ testConfirmationDialogShownForConfiguredDuration(
+ ConfirmationActivity.DEFAULT_ANIMATION_DURATION_MS * 2);
+ }
+
+ private void testConfirmationDialogShownForConfiguredDuration(int duration) throws Throwable {
+ // Wait for the test activity to be visible
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ // Check that the test activity currently hasWindowFocus()
+ assertTrue(mActivityRule.getActivity().hasWindowFocus());
+ Button button =
+ mActivityRule.getActivity().findViewById(R.id.show_confirmation_activity_button);
+
+ // GIVEN a display duration in milliseconds
+ mActivityRule.getActivity().setDuration(duration);
+ // WHEN we click on the button
+ mActivityRule.runOnUiThread(button::performClick);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ // THEN wait for the activity to be drawn
+ Thread.sleep(MILLIS_TO_WAIT_FOR_ACTIVITY_TO_BE_DRAWN);
+ // AND lose window focus to the confirmation activity on top
+ assertFalse(mActivityRule.getActivity().hasWindowFocus());
+ // AND wait until a short while before the confirmation activity is due to expire
+ Thread.sleep(duration - MILLIS_BEFORE_END_OF_DURATION
+ - MILLIS_TO_WAIT_FOR_ACTIVITY_TO_BE_DRAWN);
+ // AND confirm that the confirmation activity still has focus
+ assertFalse(mActivityRule.getActivity().hasWindowFocus());
+ // AND wait for until the confirmation activity should be gone
+ Thread.sleep(MILLIS_AFTER_END_OF_DURATION + MILLIS_BEFORE_END_OF_DURATION
+ + MILLIS_TO_WAIT_FOR_ACTIVITY_TO_BE_DRAWN);
+ // AND confirm that the test activity has focus again
+ assertTrue(mActivityRule.getActivity().hasWindowFocus());
+ }
+
+}
diff --git a/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTestActivity.java b/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTestActivity.java
new file mode 100644
index 0000000..2d80336
--- /dev/null
+++ b/wear/wear/src/androidTest/java/androidx/wear/widget/ConfirmationActivityTestActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.widget;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Button;
+
+import androidx.wear.activity.ConfirmationActivity;
+import androidx.wear.test.R;
+
+public class ConfirmationActivityTestActivity extends Activity {
+
+ /**
+ * Configurable duration in milliseconds to display the confirmation dialog for.
+ */
+ public void setDuration(int duration) {
+ mDuration = duration;
+ }
+
+ private int mDuration = ConfirmationActivity.DEFAULT_ANIMATION_DURATION_MS;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.confirmation_activity_test_layout);
+ Button button = findViewById(R.id.show_confirmation_activity_button);
+
+ button.setOnClickListener(
+ v -> {
+ Intent intent = new Intent(ConfirmationActivityTestActivity.this,
+ ConfirmationActivity.class);
+ intent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE,
+ ConfirmationActivity.SUCCESS_ANIMATION);
+ intent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_DURATION_MS, mDuration);
+ intent.putExtra(ConfirmationActivity.EXTRA_MESSAGE, "A message");
+
+ startActivity(intent);
+ }
+ );
+ }
+}
diff --git a/wear/wear/src/androidTest/res/layout/confirmation_activity_test_layout.xml b/wear/wear/src/androidTest/res/layout/confirmation_activity_test_layout.xml
new file mode 100644
index 0000000..5ef7d68
--- /dev/null
+++ b/wear/wear/src/androidTest/res/layout/confirmation_activity_test_layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/accept_deny_dialog_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#333333"
+ tools:context="androidx.wear.widget.ConfirmationActivityTestActivity">
+ <Button
+ android:id="@+id/show_confirmation_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+</FrameLayout>
diff --git a/wear/wear/src/main/java/androidx/wear/activity/ConfirmationActivity.java b/wear/wear/src/main/java/androidx/wear/activity/ConfirmationActivity.java
index 875c241..9359302 100644
--- a/wear/wear/src/main/java/androidx/wear/activity/ConfirmationActivity.java
+++ b/wear/wear/src/main/java/androidx/wear/activity/ConfirmationActivity.java
@@ -47,19 +47,49 @@
* <dd>Displays a generic failure page with an optional message.
* </dl>
*
- * An optional message, included in the extra {@link #EXTRA_MESSAGE} will be displayed horizontally
- * centered below the animation.
+ * <p>An optional message, included in the extra {@link #EXTRA_MESSAGE} will be displayed
+ * horizontally centered below the animation.
+ *
+ * <p>An optional duration to keep the confirmation activity visible for, included in the extra
+ * {@link #EXTRA_ANIMATION_DURATION_MS}
+ *
+ * <p>Default duration is {@link #DEFAULT_ANIMATION_DURATION_MS}
*/
public class ConfirmationActivity extends Activity {
+ /**
+ * Used as a string extra field on an intent for this activity to define the message that
+ * should be displayed to the user while the activity is visible.
+ */
public static final String EXTRA_MESSAGE = "androidx.wear.activity.extra.MESSAGE";
+
+ /**
+ * The lookup key for an optional int that defines the animation type that should be
+ * displayed. Should be one of {@link #SUCCESS_ANIMATION}, {@link #OPEN_ON_PHONE_ANIMATION},
+ * or {@link #FAILURE_ANIMATION}
+ *
+ * <p>If no value is specified it will default to {@link #SUCCESS_ANIMATION}
+ */
public static final String EXTRA_ANIMATION_TYPE =
"androidx.wear.activity.extra.ANIMATION_TYPE";
+ /**
+ * The lookup key for an optional int that defines the duration in milliseconds that the
+ * confirmation activity should be displayed.
+ *
+ * If no value is specified it will default to {@value #DEFAULT_ANIMATION_DURATION_MS}
+ */
+ public static final String EXTRA_ANIMATION_DURATION_MS =
+ "androidx.wear.activity.extra.ANIMATION_DURATION_MS";
+
public static final int SUCCESS_ANIMATION = 1;
public static final int OPEN_ON_PHONE_ANIMATION = 2;
public static final int FAILURE_ANIMATION = 3;
+ /** Default animation duration in ms. **/
+ public static final int DEFAULT_ANIMATION_DURATION_MS =
+ ConfirmationOverlay.DEFAULT_ANIMATION_DURATION_MS;
+
private static final SparseIntArray CONFIRMATION_OVERLAY_TYPES = new SparseIntArray();
static {
@@ -77,6 +107,8 @@
Intent intent = getIntent();
int requestedType = intent.getIntExtra(EXTRA_ANIMATION_TYPE, SUCCESS_ANIMATION);
+ int animationDurationMillis = intent.getIntExtra(EXTRA_ANIMATION_DURATION_MS,
+ DEFAULT_ANIMATION_DURATION_MS);
if (CONFIRMATION_OVERLAY_TYPES.indexOfKey(requestedType) < 0) {
throw new IllegalArgumentException("Unknown type of animation: " + requestedType);
}
@@ -87,6 +119,7 @@
new ConfirmationOverlay()
.setType(type)
.setMessage(message)
+ .setDuration(animationDurationMillis)
.setOnAnimationFinishedListener(
new ConfirmationOverlay.OnAnimationFinishedListener() {
@Override