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

Commit 235d706e authored by Usman Abdullah's avatar Usman Abdullah Committed by Android (Google) Code Review
Browse files

Merge "Performing auto-migration when there are no blocked nums" into nyc-dev

parents fd954667 03dffbf9
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -19,11 +19,13 @@ package com.android.dialer;
import android.app.Application;
import android.content.Context;
import android.os.Trace;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;

import com.android.contacts.common.extensions.ExtensionsFactory;
import com.android.contacts.common.testing.NeededForTesting;
import com.android.dialer.compat.FilteredNumberCompat;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
import com.android.dialer.filterednumber.BlockedNumbersAutoMigrator;

public class DialerApplication extends Application {

@@ -39,6 +41,8 @@ public class DialerApplication extends Application {
        Trace.beginSection(TAG + " ExtensionsFactory initialization");
        ExtensionsFactory.init(getApplicationContext());
        Trace.endSection();
        new BlockedNumbersAutoMigrator(PreferenceManager.getDefaultSharedPreferences(this),
                new FilteredNumberAsyncQueryHandler(getContentResolver())).autoMigrate();
        Trace.endSection();
    }

+10 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.dialer.compat;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;

import android.app.FragmentManager;
@@ -67,6 +68,8 @@ public class FilteredNumberCompat {

    private static Boolean isEnabledForTest;

    private static Context contextForTest;

    /**
     * @return The column name for ID in the filtered number database.
     */
@@ -154,7 +157,8 @@ public class FilteredNumberCompat {
     */
    @NeededForTesting
    public static void setHasMigratedToNewBlocking(boolean hasMigrated) {
        PreferenceManager.getDefaultSharedPreferences(DialerApplication.getContext()).edit()
        PreferenceManager.getDefaultSharedPreferences(
                MoreObjects.firstNonNull(contextForTest, DialerApplication.getContext())).edit()
                .putBoolean(HAS_MIGRATED_TO_NEW_BLOCKING_KEY, hasMigrated).apply();
    }

@@ -163,6 +167,11 @@ public class FilteredNumberCompat {
        isEnabledForTest = isEnabled;
    }

    @NeededForTesting
    public static void setContextForTest(Context context) {
        contextForTest = context;
    }

    /**
     * Gets the content {@link Uri} for number filtering.
     *
+1 −1
Original line number Diff line number Diff line
@@ -125,7 +125,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
                null, null, null);
    }

    public final void hasBlockedNumbers(final OnHasBlockedNumbersListener listener) {
    public void hasBlockedNumbers(final OnHasBlockedNumbersListener listener) {
        startQuery(NO_TOKEN,
                new Listener() {
                    @Override
+101 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.dialer.filterednumber;

import com.google.common.base.Preconditions;

import android.content.SharedPreferences;
import android.util.Log;

import com.android.dialer.compat.FilteredNumberCompat;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnHasBlockedNumbersListener;

/**
 * Class responsible for checking if the user can be auto-migrated to {@link
 * android.provider.BlockedNumberContract} blocking. In order for this to happen, the user cannot
 * have any numbers that are blocked in the Dialer solution.
 */
public class BlockedNumbersAutoMigrator {

    private static final String TAG = "BlockedNumbersAuto";

    private static final String HAS_CHECKED_AUTO_MIGRATE_KEY = "checkedAutoMigrate";

    private final SharedPreferences sharedPreferences;
    private final FilteredNumberAsyncQueryHandler queryHandler;

    /**
     * Constructs the BlockedNumbersAutoMigrator with the given {@link SharedPreferences} and {@link
     * FilteredNumberAsyncQueryHandler}.
     *
     * @param sharedPreferences The SharedPreferences used to persist information.
     * @param queryHandler The FilteredNumberAsyncQueryHandler used to determine if there are
     * blocked numbers.
     * @throws NullPointerException if sharedPreferences or queryHandler are null.
     */
    public BlockedNumbersAutoMigrator(SharedPreferences sharedPreferences,
            FilteredNumberAsyncQueryHandler queryHandler) {
        this.sharedPreferences = Preconditions.checkNotNull(sharedPreferences);
        this.queryHandler = Preconditions.checkNotNull(queryHandler);
    }

    /**
     * Attempts to perform the auto-migration. Auto-migration will only be attempted once and can be
     * performed only when the user has no blocked numbers. As a result of this method, the user
     * will be migrated to the framework blocking solution, as determined by {@link
     * FilteredNumberCompat#hasMigratedToNewBlocking()}.
     */
    public void autoMigrate() {
        if (!shouldAttemptAutoMigrate()) {
            return;
        }

        Log.i(TAG, "Attempting to auto-migrate.");
        queryHandler.hasBlockedNumbers(new OnHasBlockedNumbersListener() {
            @Override
            public void onHasBlockedNumbers(boolean hasBlockedNumbers) {
                if (hasBlockedNumbers) {
                    Log.i(TAG, "Not auto-migrating: blocked numbers exist.");
                    return;
                }
                Log.i(TAG, "Auto-migrating: no blocked numbers.");
                FilteredNumberCompat.setHasMigratedToNewBlocking(true);
            }
        });
    }

    private boolean shouldAttemptAutoMigrate() {
        if (sharedPreferences.contains(HAS_CHECKED_AUTO_MIGRATE_KEY)) {
            Log.d(TAG, "Not attempting auto-migrate: already checked once.");
            return false;
        }
        Log.i(TAG, "Updating state as already checked for auto-migrate.");
        sharedPreferences.edit().putBoolean(HAS_CHECKED_AUTO_MIGRATE_KEY, true).apply();

        if (!FilteredNumberCompat.canUseNewFiltering()) {
            Log.i(TAG, "Not attempting auto-migrate: not available.");
            return false;
        }

        if (FilteredNumberCompat.hasMigratedToNewBlocking()) {
            Log.i(TAG, "Not attempting auto-migrate: already migrated.");
            return false;
        }
        return true;
    }
}
+201 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.dialer.filterednumber;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;

import com.android.contacts.common.compat.CompatUtils;
import com.android.dialer.compat.FilteredNumberCompat;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnHasBlockedNumbersListener;

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class BlockedNumbersAutoMigratorTest extends AndroidTestCase {

    private static final String HAS_CHECKED_AUTO_MIGRATE_KEY_FOR_TEST = "checkedAutoMigrateForTest";

    @Mock
    private FilteredNumberAsyncQueryHandler mockQueryHandler;

    private SharedPreferences sharedPreferences;

    private BlockedNumbersAutoMigrator blockedNumbersAutoMigrator;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        MockitoAnnotations.initMocks(this);
        FilteredNumberCompat.setContextForTest(getContext());
        FilteredNumberCompat.setHasMigratedToNewBlocking(false);

        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
        // SharedPreference state isn't cleaned up between each test automatically, clear it now
        sharedPreferences.edit().clear().apply();

        blockedNumbersAutoMigrator = new BlockedNumbersAutoMigrator(sharedPreferences,
                mockQueryHandler);
    }

    public void testConstructor_NullSharedPreferences() {
        try {
            new BlockedNumbersAutoMigrator(null, mockQueryHandler);
            fail();
        } catch (NullPointerException e) {
        }
    }

    public void testConstructor_NullQueryHandler() {
        try {
            new BlockedNumbersAutoMigrator(sharedPreferences, null);
            fail();
        } catch (NullPointerException e) {
        }
    }

    public void testAutoMigrate_M() {
        if (CompatUtils.isNCompatible()) {
            return;
        }
        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, never()).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
    }

    public void testAutoMigrate_AlreadyMigrated() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        FilteredNumberCompat.setHasMigratedToNewBlocking(true);

        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, never()).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
    }

    public void testAutoMigrate_AlreadyChecked() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        sharedPreferences.edit()
                .putBoolean(HAS_CHECKED_AUTO_MIGRATE_KEY_FOR_TEST, true)
                .apply();

        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, never()).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
    }

    public void testAutoMigrate_HasNumbers() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        setupFilteredNumberHasBlockedNumbersExpectation(true);

        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
        assertFalse(FilteredNumberCompat.hasMigratedToNewBlocking());
    }

    public void testAutoMigrate_HasNumbers_MultipleCalls() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        setupFilteredNumberHasBlockedNumbersExpectation(true);

        blockedNumbersAutoMigrator.autoMigrate();
        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, times(1))
                .hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
        assertFalse(FilteredNumberCompat.hasMigratedToNewBlocking());
    }

    public void testAutoMigrate_NoNumbers() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        setupFilteredNumberHasBlockedNumbersExpectation(false);

        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
        assertTrue(FilteredNumberCompat.hasMigratedToNewBlocking());
    }

    public void testAutoMigrate_NoNumbers_MultipleCalls() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        setupFilteredNumberHasBlockedNumbersExpectation(false);

        blockedNumbersAutoMigrator.autoMigrate();
        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, times(1))
                .hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
        assertTrue(FilteredNumberCompat.hasMigratedToNewBlocking());
    }


    public void testAutoMigrate_SimulateClearingAppData() {
        if (!CompatUtils.isNCompatible()) {
            return;
        }
        setupFilteredNumberHasBlockedNumbersExpectation(true);

        blockedNumbersAutoMigrator.autoMigrate();

        // Clearing app data removes the sharedPreferences and all of the blocked numbers
        sharedPreferences.edit().clear().apply();
        setupFilteredNumberHasBlockedNumbersExpectation(false);

        blockedNumbersAutoMigrator.autoMigrate();

        verify(mockQueryHandler, times(2))
                .hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
        assertTrue(FilteredNumberCompat.hasMigratedToNewBlocking());
    }

    /*
     * Sets up the {@link #mockQueryHandler} to call the {@link OnHasBlockedNumbersListener} with
     * the given hasBlockedNumbers value as the parameter, when
     * {@link FilteredNumberAsyncQueryHandler#hasBlockedNumbers} is called.
     */
    private void setupFilteredNumberHasBlockedNumbersExpectation(final boolean hasBlockedNumbers) {
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                ((OnHasBlockedNumbersListener) invocation.getArguments()[0])
                        .onHasBlockedNumbers(hasBlockedNumbers);
                return null;
            }
        }).when(mockQueryHandler).hasBlockedNumbers(any(OnHasBlockedNumbersListener.class));
    }
}