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

Commit 9a599522 authored by Anna Trostanetski's avatar Anna Trostanetski Committed by android-build-merger
Browse files

Merge "Add Listeners to PlatformCompat" am: e14d7099

am: aa7b6893

Change-Id: I199da6b0dd063c610649f2275916ca907d6ed7d4
parents 4fae9dd7 aa7b6893
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -38,6 +38,20 @@ import java.util.Map;
 */
public final class CompatChange extends CompatibilityChangeInfo {

    /**
     * Callback listener for when compat changes are updated for a package.
     * See {@link #registerListener(ChangeListener)} for more details.
     */
    public interface ChangeListener {
        /**
         * Called upon an override change for packageName and the change this listener is
         * registered for. Called before the app is killed.
         */
        void onCompatChange(String packageName);
    }

    ChangeListener mListener = null;

    private Map<String, Boolean> mPackageOverrides;

    public CompatChange(long changeId) {
@@ -64,6 +78,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
                change.getDisabled());
    }

    void registerListener(ChangeListener listener) {
        if (mListener != null) {
            throw new IllegalStateException(
                    "Listener for change " + toString() + " already registered.");
        }
        mListener = listener;
    }


    /**
     * Force the enabled state of this change for a given package name. The change will only take
     * effect after that packages process is killed and restarted.
@@ -78,6 +101,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
            mPackageOverrides = new HashMap<>();
        }
        mPackageOverrides.put(pname, enabled);
        notifyListener(pname);
    }

    /**
@@ -89,7 +113,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
     */
    void removePackageOverride(String pname) {
        if (mPackageOverrides != null) {
            mPackageOverrides.remove(pname);
            if (mPackageOverrides.remove(pname) != null) {
                notifyListener(pname);
            }
        }
    }

@@ -131,4 +157,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
        }
        return sb.append(")").toString();
    }

    private void notifyListener(String packageName) {
        if (mListener != null) {
            mListener.onCompatChange(packageName);
        }
    }
}
+22 −1
Original line number Diff line number Diff line
@@ -228,7 +228,7 @@ final class CompatConfig {

    /**
     * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
     * {@link #addAppOverrides(CompatibilityChangeConfig, String)} for a certain package.
     * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
     *
     * <p>This restores the default behaviour for the given change and app, once any app
     * processes have been restarted.
@@ -243,6 +243,27 @@ final class CompatConfig {
        }
    }

    boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
        boolean alreadyKnown = true;
        synchronized (mChanges) {
            CompatChange c = mChanges.get(changeId);
            if (c == null) {
                alreadyKnown = false;
                c = new CompatChange(changeId);
                addChange(c);
            }
            c.registerListener(listener);
        }
        return alreadyKnown;
    }

    @VisibleForTesting
    void clearChanges() {
        synchronized (mChanges) {
            mChanges.clear();
        }
    }

    /**
     * Dumps the current list of compatibility config information.
     *
+17 −0
Original line number Diff line number Diff line
@@ -107,6 +107,23 @@ public class PlatformCompat extends IPlatformCompat.Stub {
        return enabled;
    }

    /**
     * Register a listener for change state overrides. Only one listener per change is allowed.
     *
     * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
     * packageName before the app is killed upon an override change. The state of a change is not
     * guaranteed to change when {@code listener.onCompatChange(String)} is called.
     *
     * @param changeId to get updates for
     * @param listener the listener that will be called upon a potential change for package.
     * @throws IllegalStateException if a listener was already registered for changeId
     * @returns {@code true} if a change with changeId was already known, or (@code false}
     * otherwise.
     */
    public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
        return CompatConfig.get().registerListener(changeId, listener);
    }

    @Override
    public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
        CompatConfig.get().addOverrides(overrides, packageName);
+272 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.compat;

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

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.testng.Assert.assertThrows;

import android.compat.Compatibility;
import android.content.Context;
import android.content.pm.PackageManager;

import com.android.internal.compat.CompatibilityChangeConfig;

import com.google.common.collect.ImmutableSet;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class PlatformCompatTest {
    private static final String PACKAGE_NAME = "my.package";

    @Mock
    private Context mContext;
    @Mock
    private PackageManager mPackageManager;
    @Mock
    CompatChange.ChangeListener mListener1, mListener2;


    @Before
    public void setUp() throws Exception {
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
                new PackageManager.NameNotFoundException());
        CompatConfig.get().clearChanges();
    }

    @Test
    public void testRegisterListenerToSameIdThrows() {
        PlatformCompat pc = new PlatformCompat(mContext);

        // Registering a listener to change 1 is successful.
        pc.registerListener(1, mListener1);
        // Registering a listener to change 2 is successful.
        pc.registerListener(2, mListener1);
        // Trying to register another listener to change id 1 fails.
        assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
    }

    @Test
    public void testRegisterListenerReturn() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
                PACKAGE_NAME);

        // Change id 1 is known (added in setOverrides).
        assertThat(pc.registerListener(1, mListener1)).isTrue();
        // Change 2 is unknown.
        assertThat(pc.registerListener(2, mListener1)).isFalse();
    }

    @Test
    public void testListenerCalledOnSetOverrides() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener1);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
                PACKAGE_NAME);

        verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerNotCalledOnWrongPackage() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener1);

        pc.setOverridesForTest(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
                PACKAGE_NAME);

        verify(mListener1, never()).onCompatChange("other.package");
    }

    @Test
    public void testListenerCalledOnSetOverridesTwoListeners() {
        PlatformCompat pc = new PlatformCompat(mContext);
        pc.registerListener(1, mListener1);

        final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
        final ImmutableSet<Long> disabled = ImmutableSet.of(2L);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(enabled, disabled)),
                PACKAGE_NAME);

        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);

        reset(mListener1);
        reset(mListener2);

        pc.registerListener(2, mListener2);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(enabled, disabled)),
                PACKAGE_NAME);

        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnSetOverridesForTest() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener1);

        pc.setOverridesForTest(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
                PACKAGE_NAME);

        verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnSetOverridesTwoListenersForTest() {
        PlatformCompat pc = new PlatformCompat(mContext);
        pc.registerListener(1, mListener1);

        final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
        final ImmutableSet<Long> disabled = ImmutableSet.of(2L);

        pc.setOverridesForTest(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(enabled, disabled)),
                PACKAGE_NAME);

        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);

        reset(mListener1);
        reset(mListener2);

        pc.registerListener(2, mListener2);
        pc.setOverridesForTest(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(enabled, disabled)),
                PACKAGE_NAME);

        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnClearOverrides() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener2);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
                PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);

        reset(mListener1);
        reset(mListener2);

        pc.clearOverrides(PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnClearOverridesMultipleOverrides() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener2);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
                PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);

        reset(mListener1);
        reset(mListener2);

        pc.clearOverrides(PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnClearOverrideExists() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);
        pc.registerListener(2, mListener2);

        pc.setOverrides(
                new CompatibilityChangeConfig(
                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
                PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);

        reset(mListener1);
        reset(mListener2);

        pc.clearOverride(1, PACKAGE_NAME);
        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
    }

    @Test
    public void testListenerCalledOnClearOverrideDoesntExist() {
        PlatformCompat pc = new PlatformCompat(mContext);

        pc.registerListener(1, mListener1);

        pc.clearOverride(1, PACKAGE_NAME);
        // Listener not called when a non existing override is removed.
        verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
    }


}