Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5d2dc4e authored by Binyi Wu's avatar Binyi Wu Committed by Android (Google) Code Review
Browse files

Merge "Update survey triggering mechanisms" into tm-qpr-dev

parents 125a6fce 7078a766
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -26,14 +26,15 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 * An interface for classes wishing to provide the ability to serve surveys to implement.
 */
public interface SurveyFeatureProvider {

    /**
     * Downloads a survey asynchronously to shared preferences to be served at a later date.
     *
     * @param activity A valid context.
     * @param surveyId A unique Id representing a survey to download.
     * @param data     a text blob to be attached to the survey results.
     * @deprecated This is not used after T.
     */
    @Deprecated
    void downloadSurvey(Activity activity, String surveyId, @Nullable String data);

    /**
@@ -42,7 +43,9 @@ public interface SurveyFeatureProvider {
     * @param activity The host activity to show the survey in.
     * @param surveyId A unique Id representing a survey to download.
     * @return A boolean indicating if a survey was shown or not.
     * @deprecated This is not used after T.
     */
    @Deprecated
    boolean showSurveyIfAvailable(Activity activity, String surveyId);

    /**
@@ -52,7 +55,9 @@ public interface SurveyFeatureProvider {
     * @param context   A valid context.
     * @param simpleKey The simple name of the key to get the surveyId for.
     * @return The unique Id as a string or null on error.
     * @deprecated This is not used after T.
     */
    @Deprecated
    String getSurveyId(Context context, String simpleKey);

    /**
@@ -64,24 +69,32 @@ public interface SurveyFeatureProvider {
     * @param surveyId the site ID.
     * @return the unix timestamp for the available survey for the given {@coe siteId} or -1 if
     * there is none available.
     * @deprecated This is not used after T.
     */
    @Deprecated
    long getSurveyExpirationDate(Context context, String surveyId);

    /**
     * Registers an activity to show surveys/prompts as soon as they are downloaded. The receiver
     * should be unregistered prior to destroying the activity to avoid undefined behavior by
     * calling {@link #unregisterReceiver(Activity, BroadcastReceiver)}.
     *
     * @param activity The activity that should show surveys once they are downloaded.
     * @return the broadcast receiver listening for survey downloads. Must be unregistered before
     * leaving the activity.
     * @deprecated This is not used after T.
     */
    @Deprecated
    BroadcastReceiver createAndRegisterReceiver(Activity activity);

    /**
     * Unregisters the broadcast receiver for this activity. Should only be called once per activity
     * after a call to {@link #createAndRegisterReceiver(Activity)}.
     *
     * @param activity The activity that was used to register the BroadcastReceiver.
     * @deprecated This is not used after T.
     */
    @Deprecated
    static void unregisterReceiver(Activity activity, BroadcastReceiver receiver) {
        if (activity == null) {
            throw new IllegalStateException("Cannot unregister receiver if activity is null");
@@ -89,4 +102,11 @@ public interface SurveyFeatureProvider {

        LocalBroadcastManager.getInstance(activity).unregisterReceiver(receiver);
    }

    /**
     * Send the visited activity to the place where it will trigger a survey if possible.
     *
     * @param simpleKey The simple name of the key to get the surveyId for.
     */
    void sendActivityIfAvailable(String simpleKey);
}
+5 −25
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@
package com.android.settings.survey;

import android.app.Activity;
import android.content.BroadcastReceiver;

import androidx.fragment.app.Fragment;

import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SurveyFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;

/**
@@ -31,16 +29,16 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
 * in settings. This allows new classes to automatically support settings provided the extend
 * one of the relevant classes in com.android.settings.lifecycle.
 */
public class SurveyMixin implements LifecycleObserver, OnResume, OnPause {
public class SurveyMixin implements LifecycleObserver, OnResume {

    private String mName;
    private Fragment mFragment;
    private BroadcastReceiver mReceiver;

    /**
     * A mixin that attempts to perform survey related tasks right before onResume is called
     * in a Settings PreferenceFragment. This will allow for remote updating and creation of
     * surveys.
     *
     * @param fragment     The fragment that this mixin will be attached to.
     * @param fragmentName The simple name of the fragment.
     */
@@ -53,31 +51,13 @@ public class SurveyMixin implements LifecycleObserver, OnResume, OnPause {
    public void onResume() {
        Activity activity = mFragment.getActivity();

        // guard against the activity not existing yet or the feature being disabled
        // guard against the activity not existing yet
        if (activity != null) {
            SurveyFeatureProvider provider =
                    FeatureFactory.getFactory(activity).getSurveyFeatureProvider(activity);
            if (provider != null) {

                // Try to download a survey if there is none available, show the survey otherwise
                String id = provider.getSurveyId(activity, mName);
                if (provider.getSurveyExpirationDate(activity, id) <= -1) {
                    // register the receiver to show the survey on completion.
                    mReceiver = provider.createAndRegisterReceiver(activity);
                    provider.downloadSurvey(activity, id, null /* data */);
                } else {
                    provider.showSurveyIfAvailable(activity, id);
                }
            }
                provider.sendActivityIfAvailable(mName);
            }
        }

    @Override
    public void onPause() {
        Activity activity = mFragment.getActivity();
        if (mReceiver != null && activity != null) {
            SurveyFeatureProvider.unregisterReceiver(activity, mReceiver);
            mReceiver = null;
        }
    }
}
+2 −100
Original line number Diff line number Diff line
package com.android.settings.survey;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;

import androidx.fragment.app.FragmentActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.overlay.SurveyFeatureProvider;
@@ -28,22 +20,15 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;

import java.util.ArrayList;
import java.util.HashMap;

@RunWith(RobolectricTestRunner.class)
public class SurveyMixinTest {

    private static final String FAKE_KEY = "fake_key";
    private static final String FAKE_SURVEY_ID = "fake_id";

    private Context mContext;
    private SurveyFeatureProvider mProvider;
    @Mock
    private BroadcastReceiver mReceiver;
    @Mock
    private InstrumentedPreferenceFragment mFragment;

    @Before
@@ -52,99 +37,16 @@ public class SurveyMixinTest {
        MockitoAnnotations.initMocks(this);
        mContext = RuntimeEnvironment.application;
        mProvider = FakeFeatureFactory.setupForTest().getSurveyFeatureProvider(mContext);
        when(mProvider.getSurveyId(any(), eq(FAKE_KEY))).thenReturn(FAKE_SURVEY_ID);
    }

    @Test
    public void onResume_triesRegisteringReceiverAndDownloadingWhenNoSurveyDetected() {
        // Pretend there is no survey in memory
        when(mProvider.getSurveyExpirationDate(any(), any())).thenReturn(-1L);

    public void onResume_noActionIfActivityDoesNotExist() {
        // Pretend we are an activity that is starting up
        FragmentActivity temp = Robolectric.setupActivity(FragmentActivity.class);
        when(mFragment.getActivity()).thenReturn(temp);
        SurveyMixin mixin = new SurveyMixin(mFragment, FAKE_KEY);
        mixin.onResume();

        // Verify that a download was attempted
        verify(mProvider, times(1)).downloadSurvey(any(), any(), any());
        // Verify that we registered a receiver for download completion broadcasts
        verify(mProvider, times(1)).createAndRegisterReceiver(any());
        // Verify we did not try to show a survey
        verify(mProvider, never()).showSurveyIfAvailable(any(), any());
    }

    @Test
    public void onResume_triesShowingSurveyWhenOneIsPresent() {
        // Pretend there is a survey in memory
        when(mProvider.getSurveyExpirationDate(any(), any())).thenReturn(0L);

        // Pretend we are an activity that is starting up
        FragmentActivity temp = Robolectric.setupActivity(FragmentActivity.class);
        when(mFragment.getActivity()).thenReturn(temp);
        SurveyMixin mixin = new SurveyMixin(mFragment, FAKE_KEY);
        mixin.onResume();

        // Verify that a download was not attempted
        verify(mProvider, never()).downloadSurvey(any(), any(), any());
        // Verify that we did not register a receiver
        verify(mProvider, never()).createAndRegisterReceiver(any());
        // Verify we tried to show a survey
        verify(mProvider, times(1)).showSurveyIfAvailable(any(), any());
    }

    @Test
    public void onResume_doesNothingWhenActivityIsNull() {
        // Pretend the activity died somewhere in the process
        when(mFragment.getActivity()).thenReturn(null);
        SurveyMixin mixin = new SurveyMixin(mFragment, FAKE_KEY);
        mixin.onResume();

        // Verify we don't try showing or downloading a survey
        verify(mProvider, never()).showSurveyIfAvailable(any(), any());
        verify(mProvider, never()).downloadSurvey(any(), any(), any());
    }

    @Test
    public void onPause_removesReceiverIfPreviouslySet() {
        // Pretend there is a survey in memory
        when(mProvider.getSurveyExpirationDate(any(), any())).thenReturn(-1L);

        // Pretend we are an activity that starts and stops
        FragmentActivity temp = Robolectric.setupActivity(FragmentActivity.class);
        when(mFragment.getActivity()).thenReturn(temp);
        when(mProvider.createAndRegisterReceiver(any())).thenReturn(mReceiver);
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(temp);
        SurveyMixin mixin = new SurveyMixin(mFragment, FAKE_KEY);
        mixin.onResume();
        manager.registerReceiver(mReceiver, new IntentFilter());
        mixin.onPause();

        // Verify we remove the receiver
        HashMap<BroadcastReceiver, ArrayList<IntentFilter>> map =
                ReflectionHelpers.getField(manager, "mReceivers");
        assertThat(map.containsKey(mReceiver)).isFalse();
    }

    @Test
    public void onPause_doesNothingWhenActivityOrReceiverNull() {
        // Pretend there is a survey in memory
        when(mProvider.getSurveyExpirationDate(any(), any())).thenReturn(-1L);

        // Pretend we are an activity that fails to create a receiver properly
        FragmentActivity temp = Robolectric.setupActivity(FragmentActivity.class);
        when(mFragment.getActivity()).thenReturn(temp);
        SurveyMixin mixin = new SurveyMixin(mFragment, FAKE_KEY);
        mixin.onPause();

        // Verify we do nothing;
        verify(mProvider, never()).showSurveyIfAvailable(any(), any());

        // pretend the activity died before onPause
        when(mFragment.getActivity()).thenReturn(null);
        mixin.onPause();

        // Verify we do nothing
        verify(mProvider, never()).showSurveyIfAvailable(any(), any());
        verify(mProvider, times(0)).sendActivityIfAvailable(FAKE_KEY);
    }
}