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

Commit a74060c1 authored by Sunny Shao's avatar Sunny Shao
Browse files

Add Tapjacking Protection for SettingsHomepageActivity

Add/remove the SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS flag into/from
SettingsHomepageActivity and SettingsPanelActivity with lifecycle.

Bug: 138442483
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.homepage
      make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.panel
      manual test
Change-Id: I72f9a947f57f74a8c09127d6c39173594c248ddc
Merged-In: I72f9a947f57f74a8c09127d6c39173594c248ddc
parent 30bf9e2e
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction;

import com.android.settings.R;
import com.android.settings.accounts.AvatarViewMixin;
import com.android.settings.core.HideNonSystemOverlayMixin;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;

@@ -54,8 +55,8 @@ public class SettingsHomepageActivity extends FragmentActivity {
                .initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);

        final ImageView avatarView = findViewById(R.id.account_avatar);
        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
        getLifecycle().addObserver(avatarViewMixin);
        getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
        getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));

        if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
            // Only allow contextual feature on high ram devices.
+2 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import androidx.fragment.app.FragmentManager;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.HideNonSystemOverlayMixin;

/**
 * Dialog Activity to host Settings Slices.
@@ -62,6 +63,7 @@ public class SettingsPanelActivity extends FragmentActivity {
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        createOrUpdatePanel(true /* shouldForceCreation */);
        getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
    }

    @Override
+73 −0
Original line number Diff line number Diff line
@@ -16,20 +16,42 @@

package com.android.settings.homepage;

import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

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

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;

import com.android.settings.R;
import com.android.settings.core.HideNonSystemOverlayMixin;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;

@RunWith(RobolectricTestRunner.class)
public class SettingsHomepageActivityTest {
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() {
@@ -55,4 +77,55 @@ public class SettingsHomepageActivityTest {

        assertThat(frameLayout.getLayoutTransition()).isNotNull();
    }

    @Test
    @Config(shadows = {
            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
            BatteryFixSliceTest.ShadowBatteryTipLoader.class
    })
    public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);

        final ActivityController<SettingsHomepageActivity> activityController =
                Robolectric.buildActivity(SettingsHomepageActivity.class).create();
        final SettingsHomepageActivity activity = spy(activityController.get());
        final Window window = mock(Window.class);
        when(activity.getWindow()).thenReturn(window);
        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));

        activityController.start();

        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    }

    @Test
    @Config(shadows = {
            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
            BatteryFixSliceTest.ShadowBatteryTipLoader.class,
    })
    public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);

        final ActivityController<SettingsHomepageActivity> activityController =
                Robolectric.buildActivity(SettingsHomepageActivity.class).create();
        final SettingsHomepageActivity activity = spy(activityController.get());
        final Window window = mock(Window.class);
        when(activity.getWindow()).thenReturn(window);
        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));

        activityController.start();

        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);

        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        when(window.getAttributes()).thenReturn(layoutParams);

        activityController.stop();
        final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);

        verify(window).setAttributes(paramCaptor.capture());
        assertThat(paramCaptor.getValue().privateFlags
                & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
    }
}
+54 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.panel;

import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

import static com.android.settings.panel.SettingsPanelActivity.KEY_MEDIA_PACKAGE_NAME;
import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT;

@@ -28,17 +30,23 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.view.MotionEvent;
import android.os.Build;
import android.view.Window;
import android.view.WindowManager;

import com.android.settings.core.HideNonSystemOverlayMixin;
import com.android.settings.testutils.FakeFeatureFactory;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.util.ReflectionHelpers;

@RunWith(RobolectricTestRunner.class)
public class SettingsPanelActivityTest {
@@ -50,6 +58,7 @@ public class SettingsPanelActivityTest {

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
        mSettingsPanelActivity = spy(
                Robolectric.buildActivity(FakeSettingsPanelActivity.class).create().get());
@@ -87,4 +96,47 @@ public class SettingsPanelActivityTest {
        assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
                .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
    }

    @Test
    public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);

        final ActivityController<SettingsPanelActivity> activityController =
                Robolectric.buildActivity(SettingsPanelActivity.class).create();
        final SettingsPanelActivity activity = spy(activityController.get());
        final Window window = mock(Window.class);
        when(activity.getWindow()).thenReturn(window);
        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));

        activityController.start();

        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    }

    @Test
    public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);

        final ActivityController<SettingsPanelActivity> activityController =
                Robolectric.buildActivity(SettingsPanelActivity.class).create();
        final SettingsPanelActivity activity = spy(activityController.get());
        final Window window = mock(Window.class);
        when(activity.getWindow()).thenReturn(window);
        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));

        activityController.start();

        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);

        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        when(window.getAttributes()).thenReturn(layoutParams);

        activityController.stop();
        final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);

        verify(window).setAttributes(paramCaptor.capture());
        assertThat(paramCaptor.getValue().privateFlags
                & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
    }
}