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

Commit 2ca680f7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Runtime apply overlay by ThemeOverlayManager" into qt-dev

parents 9d3a7d0c 2f639aba
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.State.MODE_GRID;

import android.content.Intent;
import android.content.om.OverlayManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
@@ -73,6 +74,7 @@ import com.android.documentsui.roots.ProvidersCache;
import com.android.documentsui.sidebar.RootsFragment;
import com.android.documentsui.sorting.SortController;
import com.android.documentsui.sorting.SortModel;
import com.android.documentsui.theme.ThemeOverlayManager;

import com.google.android.material.appbar.AppBarLayout;

@@ -101,6 +103,8 @@ public abstract class BaseActivity
    protected NavigationViewManager mNavigator;
    protected SortController mSortController;

    protected ThemeOverlayManager mThemeOverlayManager;

    private final List<EventListener> mEventListeners = new ArrayList<>();
    private final String mTag;

@@ -132,6 +136,9 @@ public abstract class BaseActivity
        // Record the time when onCreate is invoked for metric.
        mStartTime = new Date().getTime();

        mThemeOverlayManager = new ThemeOverlayManager(getSystemService(OverlayManager.class),
                getPackageName());
        mThemeOverlayManager.applyOverlays(true);
        // ToDo Create tool to check resource version before applyStyle for the theme
        // If version code is not match, we should reset overlay package to default,
        // in case Activity continueusly encounter resource not found exception
+82 −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.documentsui.theme;

import android.annotation.TargetApi;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;

import java.util.List;

/**
 * ThemeOverlayManager manage runtime resource overlay packages of DocumentsUI
 */
public class ThemeOverlayManager {
    private static final String TAG = ThemeOverlayManager.class.getSimpleName();

    private static final boolean DEBUG = false;

    private OverlayManager mOverlayManager;
    private String mTargetPackageId;
    private UserHandle mUserHandle;

    @TargetApi(Build.VERSION_CODES.M)
    public ThemeOverlayManager(OverlayManager overlayManager, String targetPackageId) {
        mOverlayManager = overlayManager;
        mTargetPackageId = targetPackageId;
        mUserHandle = UserHandle.of(UserHandle.myUserId());
    }

    /**
     * Apply runtime overlay package
     *
     * @param enabled whether or not enable overlay package
     */
    public void applyOverlays(boolean enabled) {
        setOverlaysEnabled(getOverlayInfo(), enabled);
    }

    private List<OverlayInfo> getOverlayInfo() {
        if (mOverlayManager != null) {
            return mOverlayManager.getOverlayInfosForTarget(mTargetPackageId, mUserHandle);
        }
        return null;
    }

    private void setOverlaysEnabled(List<OverlayInfo> overlayInfos, boolean enabled) {
        if (mOverlayManager != null && overlayInfos != null) {
            for (OverlayInfo info : overlayInfos) {
                if (info.isEnabled() != enabled) {
                    setEnabled(info.getPackageName(), mUserHandle, enabled);
                } else {
                    Log.w(TAG, "Overlay package:" + info.getPackageName()
                            + ", already enabled, UserHandle:");
                }
            }
        }
    }

    private void setEnabled(String pkg, UserHandle userHandle, boolean enabled) {
        if (DEBUG) {
            Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
        }
        mOverlayManager.setEnabled(pkg, enabled, userHandle);
    }
}
+169 −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.documentsui.theme;

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

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.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.os.UserHandle;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.google.common.collect.Lists;

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

import java.util.List;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class ThemeOverlayManagerTest {
    private static final String TEST_DISABLED_PREFIX = "com.example.";
    private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
    private static final String TEST_OVERLAY_PACKAGE = "test.overlay";
    private static final String TEST_TARGET_PACKAGE = "test.target";

    @Mock
    OverlayManager mOverlayManager;

    ThemeOverlayManager mThemeOverlayManager;

    UserHandle mUserHandle;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mUserHandle = UserHandle.of(UserHandle.myUserId());

        when(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(),
                mUserHandle)).thenReturn(Lists.newArrayList(
                createOverlayInfo(getOverlayPackageId(), getEnabledTargetPackageId(), true)));

        when(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(),
                mUserHandle)).thenReturn(Lists.newArrayList(
                createOverlayInfo(getOverlayPackageId(), getDisabledTargetPackageId(), false)));
    }

    @Test
    public void testOverlayPackagesForDocumentsUI_shouldBeNonStatic() {
        final String docsuiPkgId =
                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName();
        final OverlayManager manager =
                InstrumentationRegistry.getInstrumentation().getTargetContext().getSystemService(
                        OverlayManager.class);
        final List<OverlayInfo> infos = manager.getOverlayInfosForTarget(docsuiPkgId, mUserHandle);
        for (OverlayInfo info : infos) {
            assertThat(info.isStatic).isFalse();
        }
    }

    @Test
    public void testApplyOverlays_shouldSetEnabled() {
        final boolean enabled = true;

        mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
                getDisabledTargetPackageId());
        mThemeOverlayManager.applyOverlays(enabled);

        verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
                mUserHandle);
    }

    @Test
    public void testApplyOverlays_shouldGetOverlayInfo() {
        final boolean enabled = true;

        mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
                getEnabledTargetPackageId());
        mThemeOverlayManager.applyOverlays(enabled);

        verify(mOverlayManager, times(1)).getOverlayInfosForTarget(getEnabledTargetPackageId(),
                mUserHandle);
    }

    @Test
    public void testApplyOverlays_shouldCheckEnabled_beforeSetEnabled() {
        final boolean enabled = true;

        mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
                getEnabledTargetPackageId());
        mThemeOverlayManager.applyOverlays(enabled);

        verify(mOverlayManager, never()).setEnabled(getOverlayPackageId(), enabled,
                mUserHandle);
    }

    @Test
    public void testDefaultDisabled_applyOverlays_shouldEnabled() {
        final boolean enabled = true;

        assertThat(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(),
                mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);

        mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
                getDisabledTargetPackageId());
        mThemeOverlayManager.applyOverlays(enabled);

        verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
                mUserHandle);
    }

    @Test
    public void testDefaultEnabled_applyOverlays_shouldDisabled() {
        final boolean enabled = false;

        assertThat(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(),
                mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);

        mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
                getEnabledTargetPackageId());
        mThemeOverlayManager.applyOverlays(enabled);

        verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
                mUserHandle);
    }

    private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
            boolean enabled) {
        return new OverlayInfo(packageName, targetPackageName, null, null, "",
                enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false);
    }

    private static String getDisabledTargetPackageId() {
        return TEST_DISABLED_PREFIX + TEST_TARGET_PACKAGE;
    }

    private static String getEnabledTargetPackageId() {
        return TEST_ENABLED_PREFIX + TEST_TARGET_PACKAGE;
    }

    private static String getOverlayPackageId() {
        return TEST_DISABLED_PREFIX + TEST_OVERLAY_PACKAGE;
    }
}